aboutsummaryrefslogtreecommitdiff
path: root/src/layout
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2025-08-13 18:45:02 +0300
committerIvan Molodetskikh <yalterz@gmail.com>2025-08-14 15:58:59 +0300
commit25c1c0434907ebee85b1e9df5fd5ef60fa1a15fd (patch)
tree48abd9be3e77cfdf36d8a35604835bd183f8af1f /src/layout
parent36af02ad34efb3be9184d1d0449fc1ab42c432ca (diff)
downloadniri-25c1c0434907ebee85b1e9df5fd5ef60fa1a15fd.tar.gz
niri-25c1c0434907ebee85b1e9df5fd5ef60fa1a15fd.tar.bz2
niri-25c1c0434907ebee85b1e9df5fd5ef60fa1a15fd.zip
layout: Offset ongoing column X move anims for non-animated resizes
Diffstat (limited to 'src/layout')
-rw-r--r--src/layout/scrolling.rs60
-rw-r--r--src/layout/tests/animations.rs16
2 files changed, 54 insertions, 22 deletions
diff --git a/src/layout/scrolling.rs b/src/layout/scrolling.rs
index 5dfbb6ef..a60581af 100644
--- a/src/layout/scrolling.rs
+++ b/src/layout/scrolling.rs
@@ -1249,22 +1249,47 @@ impl<W: LayoutElement> ScrollingSpace<W> {
let offset = prev_width - self.data[col_idx].width;
// Move other columns in tandem with resizing.
- let started_resize_anim =
- column.tiles[tile_idx].resize_animation().is_some() && offset != 0.;
- if started_resize_anim {
+ let ongoing_resize_anim = column.tiles[tile_idx].resize_animation().is_some();
+ if offset != 0. {
if self.active_column_idx <= col_idx {
for col in &mut self.columns[col_idx + 1..] {
- col.animate_move_from_with_config(
- offset,
- self.options.animations.window_resize.anim,
- );
+ // If there's a resize animation on the tile (that may have just started in
+ // column.update_window()), then the apparent size change is smooth with no
+ // sudden jumps. This corresponds to adding an X animation to adjacent columns.
+ //
+ // There could also be no resize animation with nonzero offset. This could
+ // happen for example:
+ // - if the window resized on its own, which we don't animate
+ // - if the window resized by less than 10 px (the resize threshold)
+ //
+ // The latter case could also cancel an ongoing resize animation.
+ //
+ // Now, stationary columns shouldn't react to this offset change in any way,
+ // i.e. their apparent X position should jump together with the resize.
+ // However, adjacent columns that are already animating an X movement should
+ // offset their animations to avoid the jump.
+ //
+ // Notably, this is necessary to fix the animation jump when resizing width back
+ // and forth in quick succession (in a way that cancels the resize animation).
+ if ongoing_resize_anim {
+ col.animate_move_from_with_config(
+ offset,
+ self.options.animations.window_resize.anim,
+ );
+ } else {
+ col.offset_move_anim_current(offset);
+ }
}
} else {
for col in &mut self.columns[..=col_idx] {
- col.animate_move_from_with_config(
- -offset,
- self.options.animations.window_resize.anim,
- );
+ if ongoing_resize_anim {
+ col.animate_move_from_with_config(
+ -offset,
+ self.options.animations.window_resize.anim,
+ );
+ } else {
+ col.offset_move_anim_current(-offset);
+ }
}
}
}
@@ -1323,7 +1348,7 @@ impl<W: LayoutElement> ScrollingSpace<W> {
// Synchronize the horizontal view movement with the resize so that it looks nice.
// This is especially important for always-centered view.
- let config = if started_resize_anim {
+ let config = if ongoing_resize_anim {
self.options.animations.window_resize.anim
} else {
self.options.animations.horizontal_view_movement.0
@@ -3981,6 +4006,17 @@ impl<W: LayoutElement> Column<W> {
});
}
+ pub fn offset_move_anim_current(&mut self, offset: f64) {
+ if let Some(move_) = self.move_animation.as_mut() {
+ // If the anim is almost done, there's little point trying to offset it; we can let
+ // things jump. If it turns out like a bad idea, we could restart the anim intead.
+ let value = move_.anim.value();
+ if value > 0.001 {
+ move_.from += offset / value;
+ }
+ }
+ }
+
pub fn contains(&self, window: &W::Id) -> bool {
self.tiles
.iter()
diff --git a/src/layout/tests/animations.rs b/src/layout/tests/animations.rs
index 00101195..bae2d512 100644
--- a/src/layout/tests/animations.rs
+++ b/src/layout/tests/animations.rs
@@ -989,16 +989,14 @@ fn width_resize_and_cancel() {
check_ops_on_layout(&mut layout, &ops);
// Since the resize animation is cancelled, the width goes to the new value immediately. The X
- // position doesn't jump, instead the animation is offset to preserve the current position.
- //
- // FIXME: this is not currently the case!
+ // position doesn't jump, instead the animation is restarted to preserve the current position.
assert_snapshot!(format_tiles(&layout), @r"
100 × 100 at x: 0 y: 0
- 200 × 200 at x: 5 y: 0
+ 200 × 200 at x:105 y: 0
");
// Advance to the end of the move animation.
- Op::AdvanceAnimations { msec_delta: 950 }.apply(&mut layout);
+ Op::AdvanceAnimations { msec_delta: 1000 }.apply(&mut layout);
// Final state.
assert_snapshot!(format_tiles(&layout), @r"
@@ -1081,16 +1079,14 @@ fn width_resize_and_cancel_of_column_to_the_left() {
check_ops_on_layout(&mut layout, &ops);
// Since the resize animation is cancelled, the width goes to the new value immediately. The X
- // position doesn't jump, instead the animation is offset to preserve the current position.
- //
- // FIXME: this is not currently the case!
+ // position doesn't jump, instead the animation is restarted to preserve the current position.
assert_snapshot!(format_tiles(&layout), @r"
- 100 × 100 at x: 95 y: 0
+ 100 × 100 at x: -5 y: 0
200 × 200 at x:100 y: 0
");
// Advance to the end of the move animation.
- Op::AdvanceAnimations { msec_delta: 950 }.apply(&mut layout);
+ Op::AdvanceAnimations { msec_delta: 1000 }.apply(&mut layout);
// Final state.
assert_snapshot!(format_tiles(&layout), @r"