diff --git a/src/dbus/mpris/mpris_service.cpp b/src/dbus/mpris/mpris_service.cpp index c210646ca..d7fa402c4 100644 --- a/src/dbus/mpris/mpris_service.cpp +++ b/src/dbus/mpris/mpris_service.cpp @@ -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 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(); - } 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 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 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 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 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 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; } } diff --git a/src/shell/control_center/media_tab.cpp b/src/shell/control_center/media_tab.cpp index e26c5b8d6..7029a7750 100644 --- a/src/shell/control_center/media_tab.cpp +++ b/src/shell/control_center/media_tab.cpp @@ -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 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 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 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 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 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 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 MediaTab::create() { if (m_wayland != nullptr && m_renderContext != nullptr) { m_playerMenuPopup = std::make_unique(*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(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(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(); + }); } }