refactor: display metrics consolidation

This commit is contained in:
drendog 2025-11-13 08:59:15 +01:00
parent a46ba14254
commit 06453367bd
Signed by: dwenya
GPG key ID: 8DD77074645332D0
6 changed files with 225 additions and 38 deletions

View file

@ -60,7 +60,10 @@ impl WaylandWindowingSystem {
Rc::clone(&connection),
);
let popup_manager = Rc::new(PopupManager::new(popup_context, state.scale_factor()));
let popup_manager = Rc::new(PopupManager::new(
popup_context,
Rc::clone(state.display_metrics()),
));
let popup_service = Rc::new(PopupService::new(popup_manager));
let shared_serial = Rc::new(SharedPointerSerial::new());

View file

@ -0,0 +1,139 @@
use log::info;
use slint::PhysicalSize;
use std::cell::RefCell;
use std::rc::{Rc, Weak};
pub trait DisplayMetricsObserver {
fn on_scale_factor_changed(&self, new_scale: f32);
fn on_output_size_changed(&self, new_size: PhysicalSize);
}
pub struct DisplayMetrics {
scale_factor: f32,
output_size: PhysicalSize,
surface_size: PhysicalSize,
has_fractional_scale: bool,
observers: RefCell<Vec<Weak<dyn DisplayMetricsObserver>>>,
}
impl DisplayMetrics {
#[must_use]
pub fn new(scale_factor: f32, has_fractional_scale: bool) -> Self {
Self {
scale_factor,
output_size: PhysicalSize::new(0, 0),
surface_size: PhysicalSize::new(0, 0),
has_fractional_scale,
observers: RefCell::new(Vec::new()),
}
}
#[must_use]
pub fn with_output_size(mut self, output_size: PhysicalSize) -> Self {
self.output_size = output_size;
self
}
#[must_use]
pub const fn scale_factor(&self) -> f32 {
self.scale_factor
}
#[must_use]
pub const fn output_size(&self) -> PhysicalSize {
self.output_size
}
#[must_use]
pub const fn surface_size(&self) -> PhysicalSize {
self.surface_size
}
#[must_use]
pub const fn has_fractional_scale(&self) -> bool {
self.has_fractional_scale
}
pub fn register_observer(&self, observer: Weak<dyn DisplayMetricsObserver>) {
self.observers.borrow_mut().push(observer);
self.cleanup_dead_observers();
}
#[allow(clippy::cast_precision_loss)]
pub fn update_scale_factor(&mut self, scale_120ths: u32) -> f32 {
let new_scale_factor = scale_120ths as f32 / 120.0;
let old_scale_factor = self.scale_factor;
if (self.scale_factor - new_scale_factor).abs() > f32::EPSILON {
info!(
"DisplayMetrics: Updating scale factor from {} to {} ({}x)",
old_scale_factor, new_scale_factor, scale_120ths
);
self.scale_factor = new_scale_factor;
self.recalculate_surface_size();
self.notify_scale_factor_changed(new_scale_factor);
}
new_scale_factor
}
pub fn update_output_size(&mut self, output_size: PhysicalSize) {
if self.output_size != output_size {
info!(
"DisplayMetrics: Updating output size from {:?} to {:?}",
self.output_size, output_size
);
self.output_size = output_size;
self.recalculate_surface_size();
self.notify_output_size_changed(output_size);
}
}
pub fn update_surface_size(&mut self, surface_size: PhysicalSize) {
self.surface_size = surface_size;
}
#[allow(
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
clippy::cast_precision_loss
)]
fn recalculate_surface_size(&mut self) {
if self.output_size.width > 0 && self.output_size.height > 0 && self.scale_factor > 0.0 {
self.surface_size = PhysicalSize::new(
(self.output_size.width as f32 / self.scale_factor) as u32,
(self.output_size.height as f32 / self.scale_factor) as u32,
);
}
}
fn notify_scale_factor_changed(&self, new_scale: f32) {
self.observers.borrow_mut().retain(|observer| {
if let Some(obs) = observer.upgrade() {
obs.on_scale_factor_changed(new_scale);
true
} else {
false
}
});
}
fn notify_output_size_changed(&self, new_size: PhysicalSize) {
self.observers.borrow_mut().retain(|observer| {
if let Some(obs) = observer.upgrade() {
obs.on_output_size_changed(new_size);
true
} else {
false
}
});
}
fn cleanup_dead_observers(&self) {
self.observers
.borrow_mut()
.retain(|obs| obs.upgrade().is_some());
}
}
pub type SharedDisplayMetrics = Rc<RefCell<DisplayMetrics>>;

View file

@ -1,10 +1,10 @@
use crate::rendering::femtovg::main_window::FemtoVGWindow;
use crate::wayland::services::popup_service::{ActiveWindow, PopupService};
use crate::wayland::surfaces::display_metrics::SharedDisplayMetrics;
use crate::wayland::surfaces::event_bus::EventBus;
use crate::wayland::surfaces::popup_manager::PopupManager;
use crate::wayland::surfaces::window_events::{ScaleSource, WindowStateEvent};
use layer_shika_domain::value_objects::popup_request::PopupHandle;
use log::info;
use slint::platform::{WindowAdapter, WindowEvent};
use slint::{LogicalPosition, PhysicalSize};
use std::cell::Cell;
@ -43,8 +43,7 @@ pub struct EventContext {
main_surface_id: ObjectId,
popup_service: Option<Rc<PopupService>>,
event_bus: EventBus,
scale_factor: f32,
has_fractional_scale: bool,
display_metrics: SharedDisplayMetrics,
current_pointer_position: LogicalPosition,
last_pointer_serial: u32,
shared_pointer_serial: Option<Rc<SharedPointerSerial>>,
@ -55,16 +54,14 @@ impl EventContext {
pub fn new(
main_window: Rc<FemtoVGWindow>,
main_surface_id: ObjectId,
scale_factor: f32,
has_fractional_scale: bool,
display_metrics: SharedDisplayMetrics,
) -> Self {
Self {
main_window,
main_surface_id,
popup_service: None,
event_bus: EventBus::new(),
scale_factor,
has_fractional_scale,
display_metrics,
current_pointer_position: LogicalPosition::new(0.0, 0.0),
last_pointer_serial: 0,
shared_pointer_serial: None,
@ -95,19 +92,21 @@ impl EventContext {
.map(|service| Rc::clone(service.manager()))
}
pub const fn scale_factor(&self) -> f32 {
self.scale_factor
#[must_use]
pub fn scale_factor(&self) -> f32 {
self.display_metrics.borrow().scale_factor()
}
pub const fn display_metrics(&self) -> &SharedDisplayMetrics {
&self.display_metrics
}
#[allow(clippy::cast_precision_loss)]
pub fn update_scale_factor(&mut self, scale_120ths: u32) -> f32 {
let new_scale_factor = scale_120ths as f32 / 120.0;
let old_scale_factor = self.scale_factor;
info!(
"Updating scale factor from {} to {} ({}x)",
old_scale_factor, new_scale_factor, scale_120ths
);
self.scale_factor = new_scale_factor;
let new_scale_factor = self
.display_metrics
.borrow_mut()
.update_scale_factor(scale_120ths);
if let Some(popup_service) = &self.popup_service {
popup_service.update_scale_factor(new_scale_factor);
@ -128,12 +127,15 @@ impl EventContext {
#[allow(clippy::cast_possible_truncation)]
pub fn set_current_pointer_position(&mut self, physical_x: f64, physical_y: f64) {
let logical_position = if self.has_fractional_scale {
let has_fractional_scale = self.display_metrics.borrow().has_fractional_scale();
let scale_factor = self.display_metrics.borrow().scale_factor();
let logical_position = if has_fractional_scale {
LogicalPosition::new(physical_x as f32, physical_y as f32)
} else {
LogicalPosition::new(
(physical_x / f64::from(self.scale_factor)) as f32,
(physical_y / f64::from(self.scale_factor)) as f32,
(physical_x / f64::from(scale_factor)) as f32,
(physical_y / f64::from(scale_factor)) as f32,
)
};
self.current_pointer_position = logical_position;

View file

@ -1,5 +1,6 @@
pub mod component_state;
pub mod dimensions;
pub mod display_metrics;
pub mod event_bus;
pub mod event_context;
pub mod event_router;

View file

@ -1,6 +1,7 @@
use crate::errors::{LayerShikaError, Result};
use crate::rendering::egl::context::EGLContext;
use crate::rendering::femtovg::popup_window::PopupWindow;
use crate::wayland::surfaces::display_metrics::{DisplayMetricsObserver, SharedDisplayMetrics};
use layer_shika_domain::value_objects::popup_config::PopupConfig;
use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode;
use layer_shika_domain::value_objects::popup_request::PopupRequest;
@ -101,19 +102,17 @@ struct PendingPopup {
struct PopupManagerState {
popups: HashMap<PopupId, ActivePopup>,
scale_factor: f32,
output_size: PhysicalSize,
display_metrics: SharedDisplayMetrics,
current_popup_id: Option<PopupId>,
pending_popup: Option<PendingPopup>,
id_generator: usize,
}
impl PopupManagerState {
fn new(initial_scale_factor: f32) -> Self {
fn new(display_metrics: SharedDisplayMetrics) -> Self {
Self {
popups: HashMap::new(),
scale_factor: initial_scale_factor,
output_size: PhysicalSize::new(0, 0),
display_metrics,
current_popup_id: None,
pending_popup: None,
id_generator: 0,
@ -128,10 +127,10 @@ pub struct PopupManager {
impl PopupManager {
#[must_use]
pub fn new(context: PopupContext, initial_scale_factor: f32) -> Self {
pub fn new(context: PopupContext, display_metrics: SharedDisplayMetrics) -> Self {
Self {
context,
state: RefCell::new(PopupManagerState::new(initial_scale_factor)),
state: RefCell::new(PopupManagerState::new(display_metrics)),
}
}
@ -154,20 +153,34 @@ impl PopupManager {
#[must_use]
pub fn scale_factor(&self) -> f32 {
self.state.borrow().scale_factor
self.state.borrow().display_metrics.borrow().scale_factor()
}
#[must_use]
pub fn output_size(&self) -> PhysicalSize {
self.state.borrow().output_size
self.state.borrow().display_metrics.borrow().output_size()
}
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
pub fn update_scale_factor(&self, scale_factor: f32) {
self.state.borrow_mut().scale_factor = scale_factor;
let scale_120ths = (scale_factor * 120.0) as u32;
self.state
.borrow()
.display_metrics
.borrow_mut()
.update_scale_factor(scale_120ths);
for popup in self.state.borrow().popups.values() {
popup.window.set_scale_factor(scale_factor);
}
}
pub fn update_output_size(&self, output_size: PhysicalSize) {
self.state.borrow_mut().output_size = output_size;
self.state
.borrow()
.display_metrics
.borrow_mut()
.update_output_size(output_size);
}
pub fn close_current_popup(&self) {
@ -390,3 +403,16 @@ impl PopupManager {
}
}
}
impl DisplayMetricsObserver for PopupManager {
fn on_scale_factor_changed(&self, new_scale: f32) {
info!("PopupManager received scale factor change: {}", new_scale);
for popup in self.state.borrow().popups.values() {
popup.window.set_scale_factor(new_scale);
}
}
fn on_output_size_changed(&self, new_size: PhysicalSize) {
info!("PopupManager received output size change: {:?}", new_size);
}
}

View file

@ -6,6 +6,7 @@ use super::rendering_state::RenderingState;
use super::event_context::{EventContext, SharedPointerSerial};
use super::popup_manager::PopupManager;
use super::window_renderer::WindowRendererParams;
use super::display_metrics::{DisplayMetrics, SharedDisplayMetrics};
use crate::wayland::managed_proxies::{
ManagedWlPointer, ManagedWlSurface, ManagedZwlrLayerSurfaceV1,
ManagedWpFractionalScaleV1, ManagedWpViewport,
@ -28,9 +29,9 @@ pub struct WindowState {
component: ComponentState,
rendering: RenderingState,
event_context: EventContext,
display_metrics: SharedDisplayMetrics,
#[allow(dead_code)]
pointer: ManagedWlPointer,
output_size: PhysicalSize,
active_popup_key: RefCell<Option<usize>>,
main_surface: Rc<WlSurface>,
}
@ -90,11 +91,16 @@ impl WindowState {
let size = builder.size.unwrap_or_default();
let main_surface_id = (*surface_rc).id();
let display_metrics = Rc::new(RefCell::new(
DisplayMetrics::new(builder.scale_factor, has_fractional_scale)
.with_output_size(builder.output_size.unwrap_or_default()),
));
let event_context = EventContext::new(
Rc::clone(&window),
main_surface_id,
builder.scale_factor,
has_fractional_scale,
Rc::clone(&display_metrics),
);
let rendering = RenderingState::new(WindowRendererParams {
@ -112,8 +118,8 @@ impl WindowState {
component,
rendering,
event_context,
display_metrics,
pointer,
output_size: builder.output_size.unwrap_or_default(),
active_popup_key: RefCell::new(None),
main_surface: surface_rc,
})
@ -151,12 +157,14 @@ impl WindowState {
}
pub fn set_output_size(&mut self, output_size: PhysicalSize) {
self.output_size = output_size;
self.display_metrics
.borrow_mut()
.update_output_size(output_size);
self.event_context.update_output_size(output_size);
}
pub const fn output_size(&self) -> PhysicalSize {
self.output_size
pub fn output_size(&self) -> PhysicalSize {
self.display_metrics.borrow().output_size()
}
pub const fn component_instance(&self) -> &ComponentInstance {
@ -186,6 +194,10 @@ impl WindowState {
self.event_context.scale_factor()
}
pub const fn display_metrics(&self) -> &SharedDisplayMetrics {
&self.display_metrics
}
pub fn last_pointer_serial(&self) -> u32 {
self.event_context.last_pointer_serial()
}
@ -203,6 +215,10 @@ impl WindowState {
}
pub fn set_popup_manager(&mut self, popup_manager: Rc<PopupManager>) {
self.display_metrics
.borrow()
.register_observer(Rc::downgrade(&popup_manager) as _);
let popup_service = Rc::new(PopupService::new(popup_manager));
self.event_context.set_popup_service(popup_service);
}