QDBusPendingCall
Module | DBus |
---|---|
Include |
|
CMake |
|
QMake |
|
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(...);
QDBusAbstractInterface::asyncCall
returns
a QDBusPendingCall
.
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 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:
QDBusPendingCall pendingCall = interface.asyncCall(...);
const auto reply = co_await pendingCall;
The above is equivalent to:
QDBusPendingCall pendingCall = interface.asyncCall(...);
const auto reply = co_await qCoro(pendingCall).waitForFinished();
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 QDBusReply<...> reply = *watcher;
...
});
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();
}