feat: propagate nested output scale

This commit is contained in:
Samuel Onoja committed 2026-09-24 06:09:28 +01:00
1 parent 4f5f88b06f
commit 59ad6d40b2
2 files changed
+75 -7

No files matched your search

+33 -2
View File
@@ -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,9 +52,40 @@ 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,
);
}
}
}
+42 -5
View File
@@ -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<Ferese>, state: &mut Ferese) -> Result<(), Box<dyn Error>> {
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<Ferese>, 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<Ferese>, state: &mut Ferese) -> Result<()
let mut damage_tracker = OutputDamageTracker::from_output(&output);
let clock = Clock::<Monotonic>::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(
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,
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<Ferese>, 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);
}
}