fix: MPRIS reported a frozen position — Position is read on demand
The owner measured QBZ at 4:03 with Plasma's widget stuck at 0:14. The earlier seek fix was right about seeks and wrong about the shape of the problem: the position was not drifting, it was FROZEN. MPRIS `Position` is a read-on-demand property — the spec deliberately keeps it out of `PropertiesChanged`, so a client reads it when it wants it. The Linux backend serves whatever it last stored, and it only ever stored a position when `set_playback` carried one: at a track start (zero) and at a play/pause edge. Between those, every read returned the same stale number for as long as the track ran. This is in the SHARED crate, so the shipping Slint build has it identically — nobody had watched the widget's clock there. `MediaIntegration::set_position` stores and emits nothing, so the Qt poll loop refreshes it on the tick it already computes the position for: one channel send per second, no bus signal, so it does not become the per-tick work the perf rules refuse. The method is DEFAULTED, so no other consumer has to change — `cargo check` passes for qbz-app and qbzd, and the Slint frontend needs no edit (it cannot be built here, per the qbz-ui wall, so it is verified statically as R4 requires). cc
This commit is contained in:
4 files changed
+54
No files matched your search
@@ -191,6 +191,23 @@ pub(crate) fn push_playback_state(is_playing: bool, position_secs: u64) {
|
||||
mc.set_playback(status, Some(Duration::from_secs(position_secs)));
|
||||
}
|
||||
|
||||
/// Keep the reported position current, once per playback tick.
|
||||
///
|
||||
/// MPRIS `Position` is READ ON DEMAND — the spec keeps it out of
|
||||
/// `PropertiesChanged` — so the backend serves whatever it last stored, and
|
||||
/// before this it only stored one at a track start and at a play/pause edge.
|
||||
/// A desktop widget therefore showed a value that could be minutes stale:
|
||||
/// measured 2026-08-04 with QBZ at 4:03 and Plasma's widget stuck at 0:14.
|
||||
///
|
||||
/// `set_position` stores and emits nothing, so this is a channel send per
|
||||
/// second and never a bus signal — it does not become the per-tick work
|
||||
/// §7-M12 refuses.
|
||||
pub(crate) fn push_position(position_secs: u64) {
|
||||
if let Some(mc) = handle() {
|
||||
mc.set_position(Duration::from_secs(position_secs));
|
||||
}
|
||||
}
|
||||
|
||||
/// Compare-and-record the metadata de-dupe key. `true` when `key` differs from
|
||||
/// the last pushed value (→ caller pushes now), recording it as the new
|
||||
/// last-pushed value. A poisoned lock falls back to pushing.
|
||||
|
||||
@@ -2255,6 +2255,9 @@ pub fn start_poll_loop(runtime: Arc<AppRuntime<LoggingAdapter>>) {
|
||||
cache,
|
||||
track_id != 0,
|
||||
);
|
||||
// The desktop's copy of the same number. Read-on-demand, so it has
|
||||
// to be kept fresh rather than signalled — see push_position.
|
||||
crate::media_controls_qt::push_position(position);
|
||||
|
||||
// DELIVERED stream params -> the downgrade arrow + tooltip cause.
|
||||
// Deduped inside, so a steady stream costs no Qt-thread hop.
|
||||
|
||||
Reference in new issue
Block a user