Skip to content

QDBusPendingCall

ModuleDBus
Include
#include <QCoroDBusPendingCall>
CMake
target_link_libraries(myapp QCoro::DBus)
QMake
QT += QCoroDBus

QDBusPendingCall on its own doesn't have any operation that could be awaited asynchronously, this is usually done through a helper class called QDBusPendingCallWatcher. To simplify the API, QCoro allows to directly co_await completion of the pending call or use a wrapper class QCoroDBusPendingCall. To wrap a QDBusPendingCall into a QCoroDBusPendingCall, use qCoro():

QCoroDBusPendingCall qCoro(const QDBusPendingCall &);

To await completion of the pending call without the qCoro wrapper, just use the pending call in a co_await expression. The behavior is identical to awaiting on result of QCoroDBusPendingCall::waitForFinished().

QDBusPendingCall call = interface.asyncCall(...);
const QDBusReply<...> reply = co_await pendigCall;

QDBusPendingCall vs. QDBusPendingReply

As the Qt documentation for QDBusPendingCall says, you are more likely to use QDBusPendingReply in application code than QDBusPendingCall. QCoro has explicit support for QDBusPendingCall to allow using functions that return QDBusPendingCall directly in co_await expressions without the programmer having to first convert it to QDBusPendingReply. QDBusPendingReply can be constructed from a QDBusMessage, which is a result of awaiting QDBusPendingCall, therefore it's possible to perform both the conversion and awaiting in a single line of code:

QDBusPendingReply<...> reply = co_await iface.asyncCall(...);
Note that QDBusAbstractInterface::asyncCall returns a QDBusPendingCall.

waitForFinished()

 Waits until the DBus call is finished. This is equivalent to using
 [`QDBusPendingCallWatcher`][qdoc-qdbuspendingcallwatcher] and waiting for it
 to emit the [`finished()`][qdoc-qdbuspendingcallwatcher-finished] signal.

 Returns a `QDBusMessage` representing the reply to the call.

 If the call is already finished or has an error, the coroutine will not suspend and the `co_await`
 expression will return immediatelly.

 It is also possible to just directly use a `QDBusPendingCall` in a `co_await`
 expression to await its completion:
 ```cpp
 QDBusPendingCall pendingCall = interface.asyncCall(...);
 const auto reply = co_await pendingCall;
 ```

 The above is equivalent to:
 ```cpp
 QDBusPendingCall pendingCall = interface.asyncCall(...);
 const auto reply = co_await qCoro(pendingCall).waitForFinished();
 ```

 This is a coroutine-friendly equivalent to using [`QDBusPendingCallWatcher`][qdoc-qdbuspendingcallwatcher]:

 ```cpp
 QDBusPendingCall call = interface.asyncCall(...);
 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call);
 QObject::connect(watcher, &QDBusPendingCallWatcher::finished,
                  this, [](QDBusPendingCallWatcher *watcher) {
                     watcher->deleteLater();
                     const QDBusReply<...> reply = *watcher;
                     ...
                 });
 ```

 [qdoc-qdbuspendingcallwatcher]: https://doc.qt.io/qt-5/qdbuspendingcallwatcher.html
 [qdoc-qdbuspendingcallwatcher-finished]: https://doc.qt.io/qt-5/qdbuspendingcallwatcher.html#finished

Example

#include <QCoroDBus>

QCoro::Task<QString> PlayerControl::nextSong() {
    // Create a regular QDBusInterface representing the Spotify MPRIS interface
    QDBusInterface spotifyPlayer{QStringLiteral("org.mpris.MediaPlayer2.spotify"),
                                 QStringLiteral("/org/mpris/MediaPlayer2"),
                                 QStringLiteral("org.mpris.MediaPlayer2.Player")};
    // Call CanGoNext DBus method and co_await reply. During that the current coroutine is suspended.
    const QDBusReply<bool> canGoNext = co_await spotifyPlayer.asyncCall(QStringLiteral("CanGoNext"));
    // Response has arrived and coroutine is resumed. If the player can go to the next song,
    // do another async call to do so.
    if (static_cast<bool>(canGoNext)) {
        // co_await the call to finish, but throw away the result
        co_await spotifyPlayer.asyncCall(QStringLiteral("Next"));
    }

    // Finally, another async call to retrieve new track metadata. Once again, the coroutine
    // is suspended while we wait for the result.
    const QDBusReply<QVariantMap> metadata = co_await spotifyPlayer.asyncCall(QStringLiteral("Metadata"));
    // Since this function uses co_await, it is in fact a coroutine, so it must use co_return in order
    // to return our result. By definition, the result of this function can be co_awaited by the caller.
    co_return static_cast<const QVariantMap &>(metadata)[QStringLiteral("xesam:title")].toString();
}