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
+81 -13

No files matched your search

+33 -2
View File
@@ -9,7 +9,7 @@ use smithay::{
}, },
reexports::wayland_server::{Resource, protocol::wl_surface::WlSurface}, reexports::wayland_server::{Resource, protocol::wl_surface::WlSurface},
wayland::{ wayland::{
compositor::with_states, compositor::{TraversalAction, with_states, with_surface_tree_downward},
fractional_scale::{FractionalScaleHandler, with_fractional_scale}, fractional_scale::{FractionalScaleHandler, with_fractional_scale},
output::OutputHandler, output::OutputHandler,
pointer_constraints::{ pointer_constraints::{
@@ -52,12 +52,43 @@ impl OutputHandler for Ferese {}
impl FractionalScaleHandler for Ferese { impl FractionalScaleHandler for Ferese {
fn new_fractional_scale(&mut self, surface: WlSurface) { 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_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 { impl PointerConstraintsHandler for Ferese {
fn new_constraint(&mut self, _surface: &WlSurface, pointer: &PointerHandle<Self>) { fn new_constraint(&mut self, _surface: &WlSurface, pointer: &PointerHandle<Self>) {
self.activate_focused_pointer_constraint(pointer); self.activate_focused_pointer_constraint(pointer);
+48 -11
View File
@@ -9,7 +9,7 @@ use smithay::{
winit::{self, WinitEvent}, winit::{self, WinitEvent},
}, },
desktop::utils::OutputPresentationFeedback, desktop::utils::OutputPresentationFeedback,
output::{Mode, Output, PhysicalProperties, Subpixel}, output::{Mode, Output, PhysicalProperties, Scale, Subpixel},
reexports::calloop::EventLoop, reexports::calloop::EventLoop,
reexports::wayland_protocols::wp::presentation_time::server::wp_presentation_feedback::Kind, reexports::wayland_protocols::wp::presentation_time::server::wp_presentation_feedback::Kind,
utils::{Clock, Monotonic, Rectangle, Transform}, 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>> { pub fn init(event_loop: &mut EventLoop<Ferese>, state: &mut Ferese) -> Result<(), Box<dyn Error>> {
let (mut backend, event_source) = winit::init()?; let (mut backend, event_source) = winit::init()?;
let initial_scale = normalized_scale(backend.scale_factor());
let mode = Mode { let mode = Mode {
size: backend.window_size(), size: backend.window_size(),
refresh: 60_000, refresh: 60_000,
@@ -37,7 +38,7 @@ pub fn init(event_loop: &mut EventLoop<Ferese>, state: &mut Ferese) -> Result<()
output.change_current_state( output.change_current_state(
Some(mode), Some(mode),
Some(Transform::Flipped180), Some(Transform::Flipped180),
None, Some(Scale::Fractional(initial_scale)),
Some((0, 0).into()), Some((0, 0).into()),
); );
output.set_preferred(mode); 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 mut damage_tracker = OutputDamageTracker::from_output(&output);
let clock = Clock::<Monotonic>::new(); let clock = Clock::<Monotonic>::new();
let mut sequence = 0_u64; let mut sequence = 0_u64;
let mut output_scale = initial_scale;
event_loop event_loop
.handle() .handle()
.insert_source(event_source, move |event, _, state| match event { .insert_source(event_source, move |event, _, state| match event {
WinitEvent::Resized { size, .. } => output.change_current_state( WinitEvent::Resized { size, scale_factor } => {
Some(Mode { let scale = normalized_scale(scale_factor);
size,
refresh: 60_000, output.change_current_state(
}), Some(Mode {
None, size,
None, refresh: 60_000,
None, }),
), 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::Input(event) => state.process_input_event(event),
WinitEvent::Redraw => { WinitEvent::Redraw => {
let damage = Rectangle::from_size(backend.window_size()); 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(()) 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);
}
}