Commit 9b24060c authored by Kai Uwe Broulik's avatar Kai Uwe Broulik 🍇

[MPRIS Data Engine] Avoid blocking calls when changing volume

Avoids plasmashell freezing when the player app is unresponsive or has a broken MPRIS implementation

Differential Revision: https://phabricator.kde.org/D20661
parent 63ac63ca
......@@ -27,6 +27,8 @@
#include <mprisroot.h>
#include <QDBusConnection>
#include <QDBusPendingCallWatcher>
#include <QDBusPendingReply>
PlayerControl::PlayerControl(PlayerContainer* container, QObject* parent)
: Plasma::Service(parent)
......@@ -90,29 +92,48 @@ void PlayerControl::containerDestroyed()
m_container = nullptr;
}
void PlayerControl::changeVolume(double delta, bool showOSD) {
const double volume = playerInterface()->volume();
const double newVolume = qBound(0.0, volume + delta, qMax(volume, 1.0));
playerInterface()->setVolume(newVolume);
if (showOSD) {
const auto& data = m_container->data();
QDBusMessage msg = QDBusMessage::createMethodCall(
QStringLiteral("org.kde.plasmashell"),
QStringLiteral("/org/kde/osdService"),
QStringLiteral("org.kde.osdService"),
QStringLiteral("mediaPlayerVolumeChanged")
);
void PlayerControl::changeVolume(double delta, bool showOSD)
{
// Not relying on property/setProperty to avoid doing blocking DBus calls
msg.setArguments({
(int)(100 * newVolume),
data.value("Identity", ""),
data.value("Desktop Icon Name", "")
});
const double volume = m_container->data().value(QStringLiteral("Volume")).toDouble();
const double newVolume = qBound(0.0, volume + delta, qMax(volume, 1.0));
QDBusConnection::sessionBus().asyncCall(msg);
}
QDBusPendingCall reply = propertiesInterface()->Set(m_container->playerInterface()->interface(),
QStringLiteral("Volume"), QDBusVariant(newVolume));
// Update the container value right away so when calling this method in quick succession
// (mouse wheeling the tray icon) next call already gets the new value
m_container->setData(QStringLiteral("Volume"), newVolume);
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(reply, this);
connect(watcher, &QDBusPendingCallWatcher::finished, [this, showOSD](QDBusPendingCallWatcher *watcher) {
watcher->deleteLater();
QDBusPendingReply<void> reply = *watcher;
if (reply.isError()) {
return;
}
if (showOSD) {
const auto& data = m_container->data();
QDBusMessage msg = QDBusMessage::createMethodCall(
QStringLiteral("org.kde.plasmashell"),
QStringLiteral("/org/kde/osdService"),
QStringLiteral("org.kde.osdService"),
QStringLiteral("mediaPlayerVolumeChanged")
);
msg.setArguments({
qRound(data.value(QStringLiteral("Volume")).toDouble() * 100),
data.value("Identity", ""),
data.value("Desktop Icon Name", "")
});
QDBusConnection::sessionBus().asyncCall(msg);
}
});
}
Plasma::ServiceJob* PlayerControl::createJob(const QString& operation,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment