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 {
let current = pointer.current_location();
let scale = self
let (scale_x, scale_y) = self
.window_under_visual(current)
.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 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 position = pointer.current_location();
let focus = self.surface_under(position);
let scale = self
let (scale_x, scale_y) = self
.window_under_visual(position)
.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_unaccel = event.delta_unaccel();
@@ -185,8 +185,9 @@ impl Ferese {
self,
focus,
&RelativeMotionEvent {
delta: (delta.x / scale, delta.y / scale).into(),
delta_unaccel: (delta_unaccel.x / scale, delta_unaccel.y / scale).into(),
delta: (delta.x / scale_x, delta.y / scale_y).into(),
delta_unaccel: (delta_unaccel.x / scale_x, delta_unaccel.y / scale_y)
.into(),
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)?;
self.window_geometry.get(id)?.visual_scale()
}
+1 -1
View File
@@ -232,7 +232,7 @@ pub(crate) fn animated_window_elements(
constrain,
ConstrainBehavior {
reference: ConstrainReference::Geometry,
behavior: ConstrainScaleBehavior::Zoom,
behavior: ConstrainScaleBehavior::Stretch,
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)> {
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 visual = self.visual.current;
if source.width <= 0 || source.height <= 0 || visual.width <= 0.0 || visual.height <= 0.0 {
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]
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 mut geometry = WindowGeometry::new(initial, Some(ClientSize::from_rect(initial)));
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!(
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
used for hit testing.
During a non-interactive resize, committed content is scaled uniformly to cover
the visual content box and clipped to that box, anchored at its top-left content
origin. Ferese MUST NOT expose uninitialized regions. When a matching commit
arrives it replaces the scaled 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.
During a non-interactive resize, committed content is scaled independently on
each axis to fill the visual content box and clipped to that box, anchored at
its top-left content origin. This avoids the oversized crop produced by uniform
cover scaling when only one dimension changes. Ferese MUST NOT expose
uninitialized regions. When a matching commit arrives it replaces the scaled
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
ms, Ferese MUST stop waiting for visual completion, retain the target layout,