diff --git a/crates/adapters/src/rendering/femtovg/renderable_window.rs b/crates/adapters/src/rendering/femtovg/renderable_window.rs index b735b13..c85950c 100644 --- a/crates/adapters/src/rendering/femtovg/renderable_window.rs +++ b/crates/adapters/src/rendering/femtovg/renderable_window.rs @@ -10,6 +10,46 @@ pub enum RenderState { Dirty, } +#[derive(Debug, Clone, Copy)] +pub struct FractionalScaleConfig { + pub render_scale: f32, + pub render_physical_size: PhysicalSize, + pub logical_width: f32, + pub logical_height: f32, +} + +impl FractionalScaleConfig { + #[allow(clippy::cast_possible_truncation)] + #[allow(clippy::cast_sign_loss)] + #[must_use] + pub fn new(logical_width: f32, logical_height: f32, scale_factor: f32) -> Self { + let render_scale = Self::render_scale(scale_factor); + Self { + render_scale, + render_physical_size: PhysicalSize::new( + (logical_width * render_scale) as u32, + (logical_height * render_scale) as u32, + ), + logical_width, + logical_height, + } + } + + #[must_use] + pub fn render_scale(scale_factor: f32) -> f32 { + scale_factor.ceil() + } + + pub fn apply_to(&self, window: &W) { + window.set_scale_factor(self.render_scale); + window.set_size_with_exact_logical( + self.render_physical_size, + self.logical_width, + self.logical_height, + ); + } +} + pub trait RenderableWindow: WindowAdapter { fn render_frame_if_dirty(&self) -> Result<()>; fn set_scale_factor(&self, scale_factor: f32); @@ -31,4 +71,16 @@ pub trait RenderableWindow: WindowAdapter { size: size.to_logical(self.scale_factor()), }); } + + fn set_size_with_exact_logical( + &self, + physical: slint::PhysicalSize, + logical_width: f32, + logical_height: f32, + ) { + self.size_cell().set(physical); + self.window().dispatch_event(WindowEvent::Resized { + size: slint::LogicalSize::new(logical_width, logical_height), + }); + } } diff --git a/crates/adapters/src/wayland/session_lock/manager/state.rs b/crates/adapters/src/wayland/session_lock/manager/state.rs index 1a09867..cf83668 100644 --- a/crates/adapters/src/wayland/session_lock/manager/state.rs +++ b/crates/adapters/src/wayland/session_lock/manager/state.rs @@ -1,7 +1,7 @@ use super::callbacks::{LockCallbackContext, LockCallbackExt, LockPropertyOperationExt}; use crate::errors::Result; use crate::rendering::femtovg::main_window::FemtoVGWindow; -use crate::rendering::femtovg::renderable_window::RenderableWindow; +use crate::rendering::femtovg::renderable_window::{FractionalScaleConfig, RenderableWindow}; use crate::rendering::slint_integration::platform::CustomSlintPlatform; use crate::wayland::session_lock::lock_surface::LockSurface; use crate::wayland::surfaces::component_state::ComponentState; @@ -308,7 +308,22 @@ impl ActiveLockSurface { scale_factor: f32, ) { match mode { - LockScalingMode::FractionalWithViewport | LockScalingMode::FractionalOnly => { + LockScalingMode::FractionalWithViewport => { + let config = FractionalScaleConfig::new( + dimensions.logical_width() as f32, + dimensions.logical_height() as f32, + scale_factor, + ); + info!( + "Lock FractionalWithViewport: render scale {} (from {}), physical {}x{}", + config.render_scale, + scale_factor, + config.render_physical_size.width, + config.render_physical_size.height + ); + config.apply_to(self.window.as_ref()); + } + LockScalingMode::FractionalOnly => { RenderableWindow::set_scale_factor(self.window.as_ref(), scale_factor); self.window.set_size(WindowSize::Logical(LogicalSize::new( dimensions.logical_width() as f32, diff --git a/crates/adapters/src/wayland/surfaces/popup_manager.rs b/crates/adapters/src/wayland/surfaces/popup_manager.rs index 15b3e18..22e782e 100644 --- a/crates/adapters/src/wayland/surfaces/popup_manager.rs +++ b/crates/adapters/src/wayland/surfaces/popup_manager.rs @@ -1,6 +1,7 @@ use crate::errors::{LayerShikaError, Result}; use crate::rendering::egl::context_factory::RenderContextFactory; -use crate::rendering::femtovg::{popup_window::PopupWindow, renderable_window::RenderableWindow}; +use crate::rendering::femtovg::popup_window::PopupWindow; +use crate::rendering::femtovg::renderable_window::{FractionalScaleConfig, RenderableWindow}; use crate::wayland::surfaces::display_metrics::{DisplayMetrics, SharedDisplayMetrics}; use layer_shika_domain::dimensions::LogicalSize as DomainLogicalSize; use layer_shika_domain::surface_dimensions::SurfaceDimensions; @@ -9,7 +10,7 @@ use layer_shika_domain::value_objects::popup_behavior::ConstraintAdjustment; use layer_shika_domain::value_objects::popup_config::PopupConfig; use layer_shika_domain::value_objects::popup_position::PopupPosition; use log::info; -use slint::{platform::femtovg_renderer::FemtoVGRenderer, PhysicalSize, WindowSize}; +use slint::{platform::femtovg_renderer::FemtoVGRenderer, PhysicalSize}; use smithay_client_toolkit::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1; use std::cell::{Cell, RefCell}; use std::collections::{HashMap, VecDeque}; @@ -200,8 +201,9 @@ impl PopupManager { pub fn update_scale_factor(&self, scale_factor: f32) { self.scale_factor.set(scale_factor); + let render_scale = FractionalScaleConfig::render_scale(scale_factor); for popup in self.state.borrow().popups.values() { - popup.window.set_scale_factor(scale_factor); + popup.window.set_scale_factor(render_scale); } self.mark_all_popups_dirty(); } @@ -322,11 +324,16 @@ impl PopupManager { let popup_window = PopupWindow::new_with_callback(renderer, on_close); popup_window.set_popup_id(popup_id.to_handle()); - popup_window.set_scale_factor(scale_factor); - popup_window.set_size(WindowSize::Logical(slint::LogicalSize::new( - params.width, - params.height, - ))); + + let config = FractionalScaleConfig::new(params.width, params.height, scale_factor); + info!( + "Popup using render scale {} (from {}), render_physical {}x{}", + config.render_scale, + scale_factor, + config.render_physical_size.width, + config.render_physical_size.height + ); + config.apply_to(popup_window.as_ref()); let mut state = self.state.borrow_mut(); state.popups.insert( @@ -489,7 +496,6 @@ impl PopupManager { ActiveWindow::None } - #[allow(clippy::cast_precision_loss)] pub fn update_scale_for_fractional_scale_object( &self, fractional_scale_proxy: &WpFractionalScaleV1, @@ -500,8 +506,12 @@ impl PopupManager { if let Some(popup_key) = self.find_popup_key_by_fractional_scale_id(&fractional_scale_id) { if let Some(popup_surface) = self.get_popup_window(popup_key) { let new_scale_factor = DisplayMetrics::scale_factor_from_120ths(scale_120ths); - info!("Updating popup scale factor to {new_scale_factor} ({scale_120ths}x)"); - popup_surface.set_scale_factor(new_scale_factor); + let render_scale = FractionalScaleConfig::render_scale(new_scale_factor); + info!( + "Updating popup scale factor to {} (render scale {}, from {}x)", + new_scale_factor, render_scale, scale_120ths + ); + popup_surface.set_scale_factor(render_scale); popup_surface.request_redraw(); } } diff --git a/crates/adapters/src/wayland/surfaces/surface_renderer.rs b/crates/adapters/src/wayland/surfaces/surface_renderer.rs index 19884dc..49b9dbe 100644 --- a/crates/adapters/src/wayland/surfaces/surface_renderer.rs +++ b/crates/adapters/src/wayland/surfaces/surface_renderer.rs @@ -1,5 +1,5 @@ use crate::errors::Result; -use crate::rendering::femtovg::renderable_window::RenderableWindow; +use crate::rendering::femtovg::renderable_window::{FractionalScaleConfig, RenderableWindow}; use crate::wayland::managed_proxies::{ ManagedWlSurface, ManagedZwlrLayerSurfaceV1, ManagedWpFractionalScaleV1, ManagedWpViewport, }; @@ -92,12 +92,19 @@ impl SurfaceRenderer { ) { match mode { ScalingMode::FractionalWithViewport => { - self.window.set_scale_factor(scale_factor); - self.window - .set_size(slint::WindowSize::Logical(slint::LogicalSize::new( - dimensions.logical_width() as f32, - dimensions.logical_height() as f32, - ))); + let config = FractionalScaleConfig::new( + dimensions.logical_width() as f32, + dimensions.logical_height() as f32, + scale_factor, + ); + info!( + "FractionalWithViewport: render scale {} (from {}), physical {}x{}", + config.render_scale, + scale_factor, + config.render_physical_size.width, + config.render_physical_size.height + ); + config.apply_to(self.window.as_ref()); } ScalingMode::FractionalOnly => { self.window @@ -154,15 +161,30 @@ impl SurfaceRenderer { self.apply_surface_dimensions(dimensions, scale_factor); } + #[allow(clippy::cast_precision_loss)] pub fn apply_surface_dimensions(&mut self, dimensions: SurfaceDimensions, scale_factor: f32) { let scaling_mode = self.determine_scaling_mode(); + let render_physical_size = match scaling_mode { + ScalingMode::FractionalWithViewport => { + FractionalScaleConfig::new( + dimensions.logical_width() as f32, + dimensions.logical_height() as f32, + scale_factor, + ) + .render_physical_size + } + _ => dimensions.to_slint_physical_size(), + }; + info!( - "Updating window size: logical {}x{}, physical {}x{}, scale {}, buffer_scale {}, mode {:?}", + "Updating window size: logical {}x{}, physical {}x{}, render_physical {}x{}, scale {}, buffer_scale {}, mode {:?}", dimensions.logical_width(), dimensions.logical_height(), dimensions.physical_width(), dimensions.physical_height(), + render_physical_size.width, + render_physical_size.height, scale_factor, dimensions.buffer_scale(), scaling_mode @@ -173,7 +195,7 @@ impl SurfaceRenderer { info!("Window physical size: {:?}", self.window.size()); - self.size = dimensions.to_slint_physical_size(); + self.size = render_physical_size; self.logical_size = dimensions.to_slint_logical_size(); RenderableWindow::request_redraw(self.window.as_ref()); }