fix: tame animated resize scaling

This commit is contained in:
Samuel Onoja committed 2026-09-25 01:13:21 +01:00
1 parent f6dce3316a
commit bf4f5f77f7
6 files changed
+27 -22

No files matched your search

+3 -3
View File
@@ -194,14 +194,14 @@ impl PointerConstraintsHandler for Ferese {
}; };
if focused_surface == *surface { if focused_surface == *surface {
let current = pointer.current_location(); let current = pointer.current_location();
let scale = self let (scale_x, scale_y) = self
.window_under_visual(current) .window_under_visual(current)
.and_then(|window| self.visual_scale_for_window(&window)) .and_then(|window| self.visual_scale_for_window(&window))
.unwrap_or(1.0); .unwrap_or((1.0, 1.0));
let current_surface_location = current - origin; let current_surface_location = current - origin;
let offset = location - current_surface_location; let offset = location - current_surface_location;
pointer.set_location(current + Point::from((offset.x * scale, offset.y * scale))); pointer.set_location(current + Point::from((offset.x * scale_x, offset.y * scale_y)));
} }
} }
} }
+5 -4
View File
@@ -174,10 +174,10 @@ impl Ferese {
let pointer = self.seat.get_pointer().expect("seat has a pointer"); let pointer = self.seat.get_pointer().expect("seat has a pointer");
let position = pointer.current_location(); let position = pointer.current_location();
let focus = self.surface_under(position); let focus = self.surface_under(position);
let scale = self let (scale_x, scale_y) = self
.window_under_visual(position) .window_under_visual(position)
.and_then(|window| self.visual_scale_for_window(&window)) .and_then(|window| self.visual_scale_for_window(&window))
.unwrap_or(1.0); .unwrap_or((1.0, 1.0));
let delta = event.delta(); let delta = event.delta();
let delta_unaccel = event.delta_unaccel(); let delta_unaccel = event.delta_unaccel();
@@ -185,8 +185,9 @@ impl Ferese {
self, self,
focus, focus,
&RelativeMotionEvent { &RelativeMotionEvent {
delta: (delta.x / scale, delta.y / scale).into(), delta: (delta.x / scale_x, delta.y / scale_y).into(),
delta_unaccel: (delta_unaccel.x / scale, delta_unaccel.y / scale).into(), delta_unaccel: (delta_unaccel.x / scale_x, delta_unaccel.y / scale_y)
.into(),
utime: (event.time_msec() as u64).saturating_mul(1_000), utime: (event.time_msec() as u64).saturating_mul(1_000),
}, },
); );
+1 -1
View File
@@ -332,7 +332,7 @@ impl Ferese {
}) })
} }
pub fn visual_scale_for_window(&self, window: &Window) -> Option<f64> { pub fn visual_scale_for_window(&self, window: &Window) -> Option<(f64, f64)> {
let id = self.window_ids.get(window)?; let id = self.window_ids.get(window)?;
self.window_geometry.get(id)?.visual_scale() self.window_geometry.get(id)?.visual_scale()
} }
+1 -1
View File
@@ -232,7 +232,7 @@ pub(crate) fn animated_window_elements(
constrain, constrain,
ConstrainBehavior { ConstrainBehavior {
reference: ConstrainReference::Geometry, reference: ConstrainReference::Geometry,
behavior: ConstrainScaleBehavior::Zoom, behavior: ConstrainScaleBehavior::Stretch,
align: ConstrainAlign::TOP | ConstrainAlign::LEFT, align: ConstrainAlign::TOP | ConstrainAlign::LEFT,
}, },
)) ))
+9 -7
View File
@@ -237,19 +237,22 @@ impl WindowGeometry {
pub fn inverse_visual_point(&self, x: f64, y: f64) -> Option<(f64, f64)> { pub fn inverse_visual_point(&self, x: f64, y: f64) -> Option<(f64, f64)> {
let visual = self.visual.current; let visual = self.visual.current;
let scale = self.visual_scale()?; let (scale_x, scale_y) = self.visual_scale()?;
Some(((x - visual.x) / scale, (y - visual.y) / scale)) Some(((x - visual.x) / scale_x, (y - visual.y) / scale_y))
} }
pub fn visual_scale(&self) -> Option<f64> { pub fn visual_scale(&self) -> Option<(f64, f64)> {
let source = self.client.committed_size?; let source = self.client.committed_size?;
let visual = self.visual.current; let visual = self.visual.current;
if source.width <= 0 || source.height <= 0 || visual.width <= 0.0 || visual.height <= 0.0 { if source.width <= 0 || source.height <= 0 || visual.width <= 0.0 || visual.height <= 0.0 {
return None; return None;
} }
Some((visual.width / f64::from(source.width)).max(visual.height / f64::from(source.height))) Some((
visual.width / f64::from(source.width),
visual.height / f64::from(source.height),
))
} }
} }
@@ -381,15 +384,14 @@ mod tests {
} }
#[test] #[test]
fn inverse_visual_point_matches_uniform_cover_transform() { fn inverse_visual_point_matches_stretched_transform() {
let initial = Rect::new(100.0, 50.0, 400.0, 300.0); let initial = Rect::new(100.0, 50.0, 400.0, 300.0);
let mut geometry = WindowGeometry::new(initial, Some(ClientSize::from_rect(initial))); let mut geometry = WindowGeometry::new(initial, Some(ClientSize::from_rect(initial)));
geometry.visual.current = Rect::new(200.0, 100.0, 600.0, 600.0); geometry.visual.current = Rect::new(200.0, 100.0, 600.0, 600.0);
// Cover scales the 4:3 source by 2x for a square allocation, then clips it.
assert_eq!( assert_eq!(
geometry.inverse_visual_point(600.0, 500.0), geometry.inverse_visual_point(600.0, 500.0),
Some((200.0, 200.0)) Some((400.0 * 2.0 / 3.0, 200.0))
); );
} }
+8 -6
View File
@@ -549,12 +549,14 @@ to avoid a visible source-size discontinuity. Whether using a live committed
buffer or snapshot, client content MUST remain aligned with the visual geometry buffer or snapshot, client content MUST remain aligned with the visual geometry
used for hit testing. used for hit testing.
During a non-interactive resize, committed content is scaled uniformly to cover During a non-interactive resize, committed content is scaled independently on
the visual content box and clipped to that box, anchored at its top-left content each axis to fill the visual content box and clipped to that box, anchored at
origin. Ferese MUST NOT expose uninitialized regions. When a matching commit its top-left content origin. This avoids the oversized crop produced by uniform
arrives it replaces the scaled source without restarting the animation. A commit cover scaling when only one dimension changes. Ferese MUST NOT expose
is matching when its acknowledged configure and effective buffer geometry match uninitialized regions. When a matching commit arrives it replaces the scaled
the requested client size after scale and transform. source without restarting the animation. A commit is matching when its
acknowledged configure and effective buffer geometry match the requested client
size after scale and transform.
If a client has not acknowledged and committed the final configure within 500 If a client has not acknowledged and committed the final configure within 500
ms, Ferese MUST stop waiting for visual completion, retain the target layout, ms, Ferese MUST stop waiting for visual completion, retain the target layout,