Skip to content

QDBusPendingReply

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

QDBusPendingReply 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 reply or use a wrapper class QCoroDBusPendingReply. To wrap a QDBusPendingReply into a QCoroDBusPendingReply, use qCoro():

template<typename ... Args>
QCoroDBusPendingCall qCoro(const QDBusPendingReply<Args ...> &);

QDBusPendingReply in Qt5 vs Qt6

QDBusPendingReply in Qt6 is a variadic template, meaning that it can take any amount of template arguments. In Qt5, however, QDBusPendingReply is a template class that accepts only up to 8 paremeters. In QCoro the QCoroDBusPendingReply wrapper is implemented as a variadic template for compatibility with Qt6, but when building against Qt5, the number of template parameters is artificially limited to 8 to mirror the limitation of Qt5 QDBusPendingReply limitation.

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 QCoroDBusPendingReply::waitForFinished().

QDBusPendingReply<...> reply = interface.asyncCall(...);
co_await reply;
// Now the reply is finished and the result can be retrieved.

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 received reply. If the reply is already
 finished or an error has occurred the coroutine will not suspend and will return
 a result immediatelly.

 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 QDBusPendingReply<...> reply = *watcher;
                     ...
                 });
 ```

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

 The above is equivalent to:
 ```cpp
 QDBusPendingReply<...> pendingReply = interface.asyncCall(...);
 const auto reply = co_await qCoro(pendingReply).waitForFinished();
 ```

 [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();
}