diff --git a/compositor/src/handlers/mod.rs b/compositor/src/handlers/mod.rs index 27e4803..fdabbe3 100644 --- a/compositor/src/handlers/mod.rs +++ b/compositor/src/handlers/mod.rs @@ -9,7 +9,7 @@ use smithay::{ }, reexports::wayland_server::{Resource, protocol::wl_surface::WlSurface}, wayland::{ - compositor::with_states, + compositor::{TraversalAction, with_states, with_surface_tree_downward}, fractional_scale::{FractionalScaleHandler, with_fractional_scale}, output::OutputHandler, pointer_constraints::{ @@ -52,12 +52,43 @@ impl OutputHandler for Ferese {} impl FractionalScaleHandler for Ferese { fn new_fractional_scale(&mut self, surface: WlSurface) { + let scale = self + .space + .outputs() + .next() + .map(|output| output.current_scale().fractional_scale()) + .unwrap_or(1.0); + with_states(&surface, |states| { - with_fractional_scale(states, |scale| scale.set_preferred_scale(1.0)); + with_fractional_scale(states, |surface_scale| { + surface_scale.set_preferred_scale(scale); + }); }); } } +impl Ferese { + pub fn update_fractional_scale(&self, scale: f64) { + for window in self.space.elements() { + let Some(toplevel) = window.toplevel() else { + continue; + }; + + with_surface_tree_downward( + toplevel.wl_surface(), + (), + |_, _, &()| TraversalAction::DoChildren(()), + |_, states, &()| { + with_fractional_scale(states, |surface_scale| { + surface_scale.set_preferred_scale(scale); + }); + }, + |_, _, &()| true, + ); + } + } +} + impl PointerConstraintsHandler for Ferese { fn new_constraint(&mut self, _surface: &WlSurface, pointer: &PointerHandle) { self.activate_focused_pointer_constraint(pointer); diff --git a/compositor/src/winit.rs b/compositor/src/winit.rs index 2498ebe..7d37aa0 100644 --- a/compositor/src/winit.rs +++ b/compositor/src/winit.rs @@ -9,7 +9,7 @@ use smithay::{ winit::{self, WinitEvent}, }, desktop::utils::OutputPresentationFeedback, - output::{Mode, Output, PhysicalProperties, Subpixel}, + output::{Mode, Output, PhysicalProperties, Scale, Subpixel}, reexports::calloop::EventLoop, reexports::wayland_protocols::wp::presentation_time::server::wp_presentation_feedback::Kind, utils::{Clock, Monotonic, Rectangle, Transform}, @@ -20,6 +20,7 @@ use crate::Ferese; pub fn init(event_loop: &mut EventLoop, state: &mut Ferese) -> Result<(), Box> { let (mut backend, event_source) = winit::init()?; + let initial_scale = normalized_scale(backend.scale_factor()); let mode = Mode { size: backend.window_size(), refresh: 60_000, @@ -37,7 +38,7 @@ pub fn init(event_loop: &mut EventLoop, state: &mut Ferese) -> Result<() output.change_current_state( Some(mode), Some(Transform::Flipped180), - None, + Some(Scale::Fractional(initial_scale)), Some((0, 0).into()), ); output.set_preferred(mode); @@ -46,18 +47,29 @@ pub fn init(event_loop: &mut EventLoop, state: &mut Ferese) -> Result<() let mut damage_tracker = OutputDamageTracker::from_output(&output); let clock = Clock::::new(); let mut sequence = 0_u64; + let mut output_scale = initial_scale; + event_loop .handle() .insert_source(event_source, move |event, _, state| match event { - WinitEvent::Resized { size, .. } => output.change_current_state( - Some(Mode { - size, - refresh: 60_000, - }), - None, - None, - None, - ), + WinitEvent::Resized { size, scale_factor } => { + let scale = normalized_scale(scale_factor); + + output.change_current_state( + Some(Mode { + size, + refresh: 60_000, + }), + None, + Some(Scale::Fractional(scale)), + None, + ); + + if scale != output_scale { + output_scale = scale; + state.update_fractional_scale(scale); + } + } WinitEvent::Input(event) => state.process_input_event(event), WinitEvent::Redraw => { let damage = Rectangle::from_size(backend.window_size()); @@ -124,3 +136,28 @@ pub fn init(event_loop: &mut EventLoop, state: &mut Ferese) -> Result<() })?; Ok(()) } + +fn normalized_scale(scale: f64) -> f64 { + if scale.is_finite() && scale > 0.0 { + scale + } else { + 1.0 + } +} + +#[cfg(test)] +mod tests { + use super::normalized_scale; + + #[test] + fn accepts_positive_finite_scale() { + assert_eq!(normalized_scale(1.25), 1.25); + } + + #[test] + fn rejects_invalid_scale() { + assert_eq!(normalized_scale(0.0), 1.0); + assert_eq!(normalized_scale(f64::NAN), 1.0); + assert_eq!(normalized_scale(f64::INFINITY), 1.0); + } +}