fix: emit MPRIS Seeked, so an already-open widget stops extrapolating

The owner's observation is what separated the two halves of this: "el
contador del seekbar del widget solo empieza a contar hasta que lo abro."
A client reads Position ONCE, when it opens, and extrapolates from there —
it does not poll. So two different things were broken and only one was fixed
by keeping the stored position fresh.

Fresh storage fixes what a client sees when it OPENS. `Seeked` is the only
thing that reaches one that is ALREADY open: it tells the client to stop
extrapolating and re-read. Without it, a seek moved the music and the widget
kept counting from where it had been.

So the seek path emits Seeked instead of re-asserting the playback state,
which was the previous commit's guess at a cure inside an API that had no
signal. `mpris_server::Signal::Seeked` was there all along.

Defaulted on the trait to `set_position`, so a backend without the signal
still gets the value right on the next read and no other consumer changes:
cargo check passes for qbz-app and qbzd.

cc
This commit is contained in:
vicrodh committed 2026-08-04 14:05:05 -06:00
1 parent f45b703c64
commit 7ba07ec6f8
4 files changed
+48 -15

No files matched your search

+14
View File
@@ -208,6 +208,20 @@ pub(crate) fn push_position(position_secs: u64) {
}
}
/// Report a user SEEK — a discontinuous jump, not the ordinary advance.
///
/// `push_position` fixes what a client sees when it OPENS; this is what
/// reaches one that is ALREADY open. The owner's observation is what made the
/// distinction concrete: *"el contador del seekbar del widget solo empieza a
/// contar hasta que lo abro"* — the widget extrapolates from the value it read
/// at open and never looks again, so only the `Seeked` signal can tell it the
/// ground moved.
pub(crate) fn push_seeked(position_secs: u64) {
if let Some(mc) = handle() {
mc.seeked(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.
+4 -14
View File
@@ -1619,20 +1619,10 @@ pub async fn seek_frac(runtime: &Arc<AppRuntime<LoggingAdapter>>, frac: f32) {
log::warn!("[qbz-qt] seek failed: {e}");
return;
}
// Tell the desktop where we jumped to. Without this the MPRIS position is
// only ever refreshed on the play/pause edge, so a widget extrapolates
// from a base that is now wrong by the whole seek distance — the owner
// measured ~40 s of lag on 2026-08-04 after seeking forward.
//
// The shared crate exposes no `Seeked` emitter (`types.rs`), and
// `set_playback` already carries a position, so the honest fix inside the
// current API is to re-assert the state at the new position. The SHIPPING
// Slint build has the same gap and the same cure would apply there — that
// is a shared-crate conversation, not this one.
crate::media_controls_qt::push_playback_state(
runtime.core().player().get_playback_event().is_playing,
target,
);
// Tell the desktop we JUMPED. The 1 Hz `push_position` keeps the stored
// value fresh for a client that opens later; `Seeked` is the only thing
// that reaches one already open and extrapolating from what it read then.
crate::media_controls_qt::push_seeked(target);
}
pub async fn set_volume(runtime: &Arc<AppRuntime<LoggingAdapter>>, volume: f32) {