mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
MPRTIS change to async
This commit is contained in:
@@ -742,12 +742,18 @@ bool MprisService::seek(const std::string& busName, int64_t offsetUs) {
|
||||
}
|
||||
|
||||
try {
|
||||
proxyIt->second->callMethod("Seek").onInterface(k_mpris_player_interface).withArguments(offsetUs);
|
||||
proxyIt->second->callMethodAsync("Seek")
|
||||
.onInterface(k_mpris_player_interface)
|
||||
.withArguments(offsetUs)
|
||||
.uponReplyInvoke([busName](std::optional<sdbus::Error> err) {
|
||||
if (err.has_value()) {
|
||||
kLog.warn("seek failed name={} err={}", busName, err->what());
|
||||
}
|
||||
});
|
||||
m_lastSeekCommandAt[busName] = std::chrono::steady_clock::now();
|
||||
addOrRefreshPlayer(busName);
|
||||
return true;
|
||||
} catch (const sdbus::Error& e) {
|
||||
kLog.warn("seek failed name={} err={}", busName, e.what());
|
||||
kLog.warn("seek dispatch failed name={} err={}", busName, e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -772,14 +778,7 @@ bool MprisService::setPosition(const std::string& busName, int64_t positionUs) {
|
||||
}
|
||||
|
||||
auto fallback_seek = [&]() {
|
||||
int64_t currentPositionUs = it->second.positionUs;
|
||||
try {
|
||||
const sdbus::Variant positionValue =
|
||||
proxyIt->second->getProperty("Position").onInterface(k_mpris_player_interface);
|
||||
currentPositionUs = positionValue.get<int64_t>();
|
||||
} catch (const sdbus::Error& e) {
|
||||
kLog.warn("position refresh failed name={} err={}, using cached value", busName, e.what());
|
||||
}
|
||||
const int64_t currentPositionUs = it->second.positionUs;
|
||||
|
||||
const int64_t offsetUs = positionUs - currentPositionUs;
|
||||
if (offsetUs == 0) {
|
||||
@@ -796,14 +795,18 @@ bool MprisService::setPosition(const std::string& busName, int64_t positionUs) {
|
||||
}
|
||||
|
||||
try {
|
||||
proxyIt->second->callMethod("SetPosition")
|
||||
proxyIt->second->callMethodAsync("SetPosition")
|
||||
.onInterface(k_mpris_player_interface)
|
||||
.withArguments(sdbus::ObjectPath{it->second.trackId}, positionUs);
|
||||
.withArguments(sdbus::ObjectPath{it->second.trackId}, positionUs)
|
||||
.uponReplyInvoke([busName](std::optional<sdbus::Error> err) {
|
||||
if (err.has_value()) {
|
||||
kLog.warn("set-position failed name={} err={}", busName, err->what());
|
||||
}
|
||||
});
|
||||
m_lastSeekCommandAt[busName] = std::chrono::steady_clock::now();
|
||||
addOrRefreshPlayer(busName);
|
||||
return true;
|
||||
} catch (const sdbus::Error& e) {
|
||||
kLog.warn("set-position failed name={} err={}, falling back to Seek", busName, e.what());
|
||||
kLog.warn("set-position dispatch failed name={} err={}, falling back to Seek", busName, e.what());
|
||||
return fallback_seek();
|
||||
}
|
||||
}
|
||||
@@ -828,11 +831,17 @@ bool MprisService::setVolume(const std::string& busName, double volume) {
|
||||
}
|
||||
|
||||
try {
|
||||
proxyIt->second->setProperty("Volume").onInterface(k_mpris_player_interface).toValue(volume);
|
||||
addOrRefreshPlayer(busName);
|
||||
proxyIt->second->callMethodAsync("Set")
|
||||
.onInterface(k_properties_interface)
|
||||
.withArguments(std::string{k_mpris_player_interface}, std::string{"Volume"}, sdbus::Variant{volume})
|
||||
.uponReplyInvoke([busName](std::optional<sdbus::Error> err) {
|
||||
if (err.has_value()) {
|
||||
kLog.warn("set-volume failed name={} err={}", busName, err->what());
|
||||
}
|
||||
});
|
||||
return true;
|
||||
} catch (const sdbus::Error& e) {
|
||||
kLog.warn("set-volume failed name={} err={}", busName, e.what());
|
||||
kLog.warn("set-volume dispatch failed name={} err={}", busName, e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -857,11 +866,17 @@ bool MprisService::setShuffle(const std::string& busName, bool shuffle) {
|
||||
}
|
||||
|
||||
try {
|
||||
proxyIt->second->setProperty("Shuffle").onInterface(k_mpris_player_interface).toValue(shuffle);
|
||||
addOrRefreshPlayer(busName);
|
||||
proxyIt->second->callMethodAsync("Set")
|
||||
.onInterface(k_properties_interface)
|
||||
.withArguments(std::string{k_mpris_player_interface}, std::string{"Shuffle"}, sdbus::Variant{shuffle})
|
||||
.uponReplyInvoke([busName](std::optional<sdbus::Error> err) {
|
||||
if (err.has_value()) {
|
||||
kLog.warn("set-shuffle failed name={} err={}", busName, err->what());
|
||||
}
|
||||
});
|
||||
return true;
|
||||
} catch (const sdbus::Error& e) {
|
||||
kLog.warn("set-shuffle failed name={} err={}", busName, e.what());
|
||||
kLog.warn("set-shuffle dispatch failed name={} err={}", busName, e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -886,11 +901,18 @@ bool MprisService::setLoopStatus(const std::string& busName, std::string loopSta
|
||||
}
|
||||
|
||||
try {
|
||||
proxyIt->second->setProperty("LoopStatus").onInterface(k_mpris_player_interface).toValue(std::move(loopStatus));
|
||||
addOrRefreshPlayer(busName);
|
||||
proxyIt->second->callMethodAsync("Set")
|
||||
.onInterface(k_properties_interface)
|
||||
.withArguments(std::string{k_mpris_player_interface}, std::string{"LoopStatus"},
|
||||
sdbus::Variant{std::move(loopStatus)})
|
||||
.uponReplyInvoke([busName](std::optional<sdbus::Error> err) {
|
||||
if (err.has_value()) {
|
||||
kLog.warn("set-loop-status failed name={} err={}", busName, err->what());
|
||||
}
|
||||
});
|
||||
return true;
|
||||
} catch (const sdbus::Error& e) {
|
||||
kLog.warn("set-loop-status failed name={} err={}", busName, e.what());
|
||||
kLog.warn("set-loop-status dispatch failed name={} err={}", busName, e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1801,12 +1823,18 @@ bool MprisService::callPlayerMethod(const std::string& busName, const char* meth
|
||||
}
|
||||
|
||||
try {
|
||||
it->second->callMethod(methodName).onInterface(k_mpris_player_interface);
|
||||
addOrRefreshPlayer(busName);
|
||||
kLog.debug("control name={} method={}", busName, methodName);
|
||||
it->second->callMethodAsync(methodName)
|
||||
.onInterface(k_mpris_player_interface)
|
||||
.uponReplyInvoke([busName, methodName](std::optional<sdbus::Error> err) {
|
||||
if (err.has_value()) {
|
||||
kLog.warn("control failed name={} method={} err={}", busName, methodName, err->what());
|
||||
return;
|
||||
}
|
||||
kLog.debug("control name={} method={}", busName, methodName);
|
||||
});
|
||||
return true;
|
||||
} catch (const sdbus::Error& e) {
|
||||
kLog.warn("control failed name={} method={} err={}", busName, methodName, e.what());
|
||||
kLog.warn("control dispatch failed name={} method={} err={}", busName, methodName, e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "shell/control_center/media_tab.h"
|
||||
|
||||
#include "core/deferred_call.h"
|
||||
#include "core/log.h"
|
||||
#include "dbus/mpris/mpris_art.h"
|
||||
#include "dbus/mpris/mpris_service.h"
|
||||
@@ -271,16 +272,17 @@ std::unique_ptr<Flex> MediaTab::create() {
|
||||
m_pendingSeekUs = targetUs;
|
||||
m_pendingSeekUntil = now + std::chrono::milliseconds(3000);
|
||||
|
||||
bool seekIssued = false;
|
||||
if (!seekBusName.empty()) {
|
||||
seekIssued = m_mpris->setPosition(seekBusName, targetUs);
|
||||
} else {
|
||||
seekIssued = m_mpris->setPositionActive(targetUs);
|
||||
}
|
||||
if (!seekIssued) {
|
||||
// Keep the thumb stable briefly even if transport seek dispatch races.
|
||||
m_pendingSeekUntil = now + std::chrono::milliseconds(750);
|
||||
}
|
||||
DeferredCall::callLater([this, seekBusName, targetUs]() {
|
||||
if (m_mpris == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (!seekBusName.empty()) {
|
||||
(void)m_mpris->setPosition(seekBusName, targetUs);
|
||||
} else {
|
||||
(void)m_mpris->setPositionActive(targetUs);
|
||||
}
|
||||
PanelManager::instance().refresh();
|
||||
});
|
||||
});
|
||||
m_progressSlider = progress.get();
|
||||
mediaStack->addChild(std::move(progress));
|
||||
@@ -305,13 +307,15 @@ std::unique_ptr<Flex> MediaTab::create() {
|
||||
repeat->setPadding(Style::spaceSm * scale, Style::spaceSm * scale);
|
||||
repeat->setRadius(Style::radiusLg * scale);
|
||||
repeat->setOnClick([this]() {
|
||||
if (m_mpris == nullptr) {
|
||||
return;
|
||||
}
|
||||
const auto current = m_mpris->loopStatusActive().value_or("None");
|
||||
const std::string next = current == "None" ? "Playlist" : (current == "Playlist" ? "Track" : "None");
|
||||
m_mpris->setLoopStatusActive(next);
|
||||
PanelManager::instance().refresh();
|
||||
DeferredCall::callLater([this]() {
|
||||
if (m_mpris == nullptr) {
|
||||
return;
|
||||
}
|
||||
const auto current = m_mpris->loopStatusActive().value_or("None");
|
||||
const std::string next = current == "None" ? "Playlist" : (current == "Playlist" ? "Track" : "None");
|
||||
(void)m_mpris->setLoopStatusActive(next);
|
||||
PanelManager::instance().refresh();
|
||||
});
|
||||
});
|
||||
m_repeatButton = repeat.get();
|
||||
controls->addChild(std::move(repeat));
|
||||
@@ -324,10 +328,12 @@ std::unique_ptr<Flex> MediaTab::create() {
|
||||
previous->setPadding(Style::spaceSm * scale, Style::spaceSm * scale);
|
||||
previous->setRadius(Style::radiusLg * scale);
|
||||
previous->setOnClick([this]() {
|
||||
if (m_mpris != nullptr) {
|
||||
m_mpris->previousActive();
|
||||
PanelManager::instance().refresh();
|
||||
}
|
||||
DeferredCall::callLater([this]() {
|
||||
if (m_mpris != nullptr) {
|
||||
(void)m_mpris->previousActive();
|
||||
PanelManager::instance().refresh();
|
||||
}
|
||||
});
|
||||
});
|
||||
m_prevButton = previous.get();
|
||||
controls->addChild(std::move(previous));
|
||||
@@ -340,10 +346,12 @@ std::unique_ptr<Flex> MediaTab::create() {
|
||||
playPause->setPadding(Style::spaceSm * scale, Style::spaceSm * scale);
|
||||
playPause->setRadius(Style::radiusLg * scale);
|
||||
playPause->setOnClick([this]() {
|
||||
if (m_mpris != nullptr) {
|
||||
m_mpris->playPauseActive();
|
||||
PanelManager::instance().refresh();
|
||||
}
|
||||
DeferredCall::callLater([this]() {
|
||||
if (m_mpris != nullptr) {
|
||||
(void)m_mpris->playPauseActive();
|
||||
PanelManager::instance().refresh();
|
||||
}
|
||||
});
|
||||
});
|
||||
m_playPauseButton = playPause.get();
|
||||
controls->addChild(std::move(playPause));
|
||||
@@ -356,10 +364,12 @@ std::unique_ptr<Flex> MediaTab::create() {
|
||||
next->setPadding(Style::spaceSm * scale, Style::spaceSm * scale);
|
||||
next->setRadius(Style::radiusLg * scale);
|
||||
next->setOnClick([this]() {
|
||||
if (m_mpris != nullptr) {
|
||||
m_mpris->nextActive();
|
||||
PanelManager::instance().refresh();
|
||||
}
|
||||
DeferredCall::callLater([this]() {
|
||||
if (m_mpris != nullptr) {
|
||||
(void)m_mpris->nextActive();
|
||||
PanelManager::instance().refresh();
|
||||
}
|
||||
});
|
||||
});
|
||||
m_nextButton = next.get();
|
||||
controls->addChild(std::move(next));
|
||||
@@ -372,11 +382,13 @@ std::unique_ptr<Flex> MediaTab::create() {
|
||||
shuffle->setPadding(Style::spaceSm * scale, Style::spaceSm * scale);
|
||||
shuffle->setRadius(Style::radiusLg * scale);
|
||||
shuffle->setOnClick([this]() {
|
||||
if (m_mpris != nullptr) {
|
||||
const bool enabled = m_mpris->shuffleActive().value_or(false);
|
||||
m_mpris->setShuffleActive(!enabled);
|
||||
PanelManager::instance().refresh();
|
||||
}
|
||||
DeferredCall::callLater([this]() {
|
||||
if (m_mpris != nullptr) {
|
||||
const bool enabled = m_mpris->shuffleActive().value_or(false);
|
||||
(void)m_mpris->setShuffleActive(!enabled);
|
||||
PanelManager::instance().refresh();
|
||||
}
|
||||
});
|
||||
});
|
||||
m_shuffleButton = shuffle.get();
|
||||
controls->addChild(std::move(shuffle));
|
||||
@@ -419,17 +431,20 @@ std::unique_ptr<Flex> MediaTab::create() {
|
||||
if (m_wayland != nullptr && m_renderContext != nullptr) {
|
||||
m_playerMenuPopup = std::make_unique<ContextMenuPopup>(*m_wayland, *m_renderContext);
|
||||
m_playerMenuPopup->setOnActivate([this](const ContextMenuControlEntry& entry) {
|
||||
if (m_mpris == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (entry.id == 0) {
|
||||
m_mpris->clearPinnedPlayerPreference();
|
||||
} else {
|
||||
const std::size_t idx = static_cast<std::size_t>(entry.id - 1);
|
||||
if (idx < m_playerBusNames.size()) {
|
||||
m_mpris->setPinnedPlayerPreference(m_playerBusNames[idx]);
|
||||
DeferredCall::callLater([this, entry]() {
|
||||
if (m_mpris == nullptr) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (entry.id == 0) {
|
||||
m_mpris->clearPinnedPlayerPreference();
|
||||
} else {
|
||||
const std::size_t idx = static_cast<std::size_t>(entry.id - 1);
|
||||
if (idx < m_playerBusNames.size()) {
|
||||
m_mpris->setPinnedPlayerPreference(m_playerBusNames[idx]);
|
||||
}
|
||||
}
|
||||
PanelManager::instance().refresh();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -603,7 +618,14 @@ void MediaTab::setActive(bool active) {
|
||||
// Pull a fresh snapshot (including Position) when the tab opens so the
|
||||
// progress slider starts at the current playback position.
|
||||
m_positionSampleAt = {};
|
||||
m_mpris->refreshPlayers();
|
||||
DeferredCall::callLater([this]() {
|
||||
if (m_mpris == nullptr) {
|
||||
return;
|
||||
}
|
||||
m_mpris->refreshPlayers();
|
||||
PanelManager::instance().requestUpdateOnly();
|
||||
PanelManager::instance().requestRedraw();
|
||||
});
|
||||
m_lastMprisRefreshAttempt = std::chrono::steady_clock::now();
|
||||
}
|
||||
}
|
||||
@@ -676,11 +698,14 @@ void MediaTab::refresh(Renderer& renderer) {
|
||||
if (shouldRetryMpris) {
|
||||
m_lastMprisRefreshAttempt = now;
|
||||
kLog.debug("media tab retrying mpris discovery players={} active={}", players.size(), active.has_value());
|
||||
m_mpris->refreshPlayers();
|
||||
players = m_mpris->listPlayers();
|
||||
active = m_mpris->activePlayer();
|
||||
kLog.debug("media tab refresh after retry players={} active={} active_bus=\"{}\"", players.size(),
|
||||
active.has_value(), active.has_value() ? active->busName : std::string{});
|
||||
DeferredCall::callLater([this]() {
|
||||
if (m_mpris == nullptr) {
|
||||
return;
|
||||
}
|
||||
m_mpris->refreshPlayers();
|
||||
PanelManager::instance().requestUpdateOnly();
|
||||
PanelManager::instance().requestRedraw();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user