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