workspaces: keep the trail animating and level across row rebuilds
Two regressions from the previous commit, both from trusting the live geometry too far. Snapping instead of moving: switching to an empty workspace rebuilds the button row, and for a frame afterwards no button is allocated, so button_geom returned None for both the source and destination. from_geom then returned None and the caller fell back to an instant place(). The trail now remembers the last size measured from an allocated button and animates from that, so a rebuild costs continuity of size, not the animation itself. Sitting low: y was taken from the live geometry, which after a rebuild or mid-animation is not where the row actually is. Only x comes from the live geometry now — that is what makes an interrupted switch continue from where the pill is rather than jumping back — while y, w and h always come from a real button.
This commit is contained in:
parent
1b523eab63
commit
74f280eaed
1 changed files with 25 additions and 11 deletions
|
|
@ -277,6 +277,13 @@ struct Geom {
|
||||||
struct TrailInner {
|
struct TrailInner {
|
||||||
tick: Option<gtk4::TickCallbackId>,
|
tick: Option<gtk4::TickCallbackId>,
|
||||||
geom: Geom,
|
geom: Geom,
|
||||||
|
/// Last width/height measured from a button that was actually allocated.
|
||||||
|
/// A row rebuild (switching to an empty workspace makes Hyprland create
|
||||||
|
/// and destroy it) can leave every button unallocated for a frame, and
|
||||||
|
/// without a remembered size the trail had nothing safe to animate from
|
||||||
|
/// and fell back to an instant `place()` — which is what made a switch
|
||||||
|
/// snap instead of move.
|
||||||
|
natural: Option<(f64, f64)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Overlay + Fixed pill sitting *behind* the workspace buttons. The
|
/// Overlay + Fixed pill sitting *behind* the workspace buttons. The
|
||||||
|
|
@ -317,6 +324,7 @@ impl WorkspaceTrail {
|
||||||
|
|
||||||
let inner = Rc::new(RefCell::new(TrailInner {
|
let inner = Rc::new(RefCell::new(TrailInner {
|
||||||
tick: None,
|
tick: None,
|
||||||
|
natural: None,
|
||||||
geom: Geom {
|
geom: Geom {
|
||||||
x: 0.0,
|
x: 0.0,
|
||||||
y: 0.0,
|
y: 0.0,
|
||||||
|
|
@ -418,6 +426,7 @@ impl WorkspaceTrail {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
let cached = st.natural;
|
||||||
drop(st);
|
drop(st);
|
||||||
|
|
||||||
// Width must always come from a button that is CURRENTLY IN THE ROW.
|
// Width must always come from a button that is CURRENTLY IN THE ROW.
|
||||||
|
|
@ -447,19 +456,24 @@ impl WorkspaceTrail {
|
||||||
// Taking position from the live geometry and width from the source
|
// Taking position from the live geometry and width from the source
|
||||||
// button's natural size keeps the motion continuous while making width
|
// button's natural size keeps the motion continuous while making width
|
||||||
// a pure function of which button we started from.
|
// a pure function of which button we started from.
|
||||||
// `natural` is None only if BOTH buttons are detached, in which case
|
if let Some(n) = natural {
|
||||||
// there is no sane width to animate from and the caller falls back to
|
self.inner.borrow_mut().natural = Some((n.w, n.h));
|
||||||
// an instant `place()`. There is deliberately no path that returns the
|
}
|
||||||
// live width.
|
// Only x comes from the live geometry. That is what makes an
|
||||||
match (live, natural) {
|
// interrupted switch continue from where the pill currently is instead
|
||||||
(Some(live), Some(natural)) => Some(Geom {
|
// of jumping back. y/w/h always come from a real button: taking y from
|
||||||
|
// a mid-animation or post-rebuild geometry is what made the pill sit
|
||||||
|
// low, and taking w from it is what let the width compound.
|
||||||
|
let size = natural.map(|n| (n.w, n.h)).or(cached);
|
||||||
|
match (live, natural, size) {
|
||||||
|
(Some(live), _, Some((w, h))) => Some(Geom {
|
||||||
x: live.x,
|
x: live.x,
|
||||||
y: live.y,
|
y: natural.map(|n| n.y).unwrap_or(live.y),
|
||||||
w: natural.w,
|
w,
|
||||||
h: natural.h,
|
h,
|
||||||
}),
|
}),
|
||||||
(None, natural) => natural,
|
(None, Some(natural), _) => Some(natural),
|
||||||
(Some(_), None) => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue