QDBusPendingReply
Module | DBus |
---|---|
Include |
|
CMake |
|
QMake |
|
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
and waiting for it
to emit the 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
:
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:
QDBusPendingReply<...> pendingReply = interface.asyncCall(...);
const auto reply = co_await pendingReply;
The above is equivalent to:
QDBusPendingReply<...> pendingReply = interface.asyncCall(...);
const auto reply = co_await qCoro(pendingReply).waitForFinished();
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();
}