From 11f17a4fc1ea07c317840dfe96cb648fa0e3f90b Mon Sep 17 00:00:00 2001 From: drendog Date: Wed, 5 Nov 2025 07:42:06 +0100 Subject: [PATCH] fix: popup position clamping to avoid exceeding output boundaries --- .../src/wayland/surfaces/popup_manager.rs | 9 ++++++ composition/src/system.rs | 31 +++++++++++++------ domain/src/value_objects/popup_config.rs | 20 +++++++++--- 3 files changed, 47 insertions(+), 13 deletions(-) diff --git a/adapters/src/wayland/surfaces/popup_manager.rs b/adapters/src/wayland/surfaces/popup_manager.rs index c767221..8983923 100644 --- a/adapters/src/wayland/surfaces/popup_manager.rs +++ b/adapters/src/wayland/surfaces/popup_manager.rs @@ -179,12 +179,21 @@ impl PopupManager { params.positioning_mode ); + let output_size = self.output_size(); + #[allow(clippy::cast_precision_loss)] + let output_logical_size = ( + output_size.width as f32 / scale_factor, + output_size.height as f32 / scale_factor, + ); + let popup_config = PopupConfig::new( params.reference_x, params.reference_y, params.width, params.height, params.positioning_mode, + output_logical_size.0, + output_logical_size.1, ); #[allow(clippy::cast_possible_truncation)] diff --git a/composition/src/system.rs b/composition/src/system.rs index bac3538..d49f7cb 100644 --- a/composition/src/system.rs +++ b/composition/src/system.rs @@ -28,11 +28,7 @@ use std::time::{Duration, Instant}; enum PopupCommand { Show(PopupRequest), Close(PopupHandle), - Resize { - key: usize, - width: f32, - height: f32, - }, + Resize { key: usize, width: f32, height: f32 }, } pub struct EventLoopHandle { @@ -142,7 +138,11 @@ impl RuntimeState<'_> { self.window_state.compilation_result() } - pub fn show_popup(&mut self, req: PopupRequest, resize_sender: Option>) -> Result { + pub fn show_popup( + &mut self, + req: PopupRequest, + resize_sender: Option>, + ) -> Result { let compilation_result = self.compilation_result().ok_or_else(|| { Error::Domain(DomainError::Configuration { message: "No compilation result available for popup creation".to_string(), @@ -229,7 +229,13 @@ impl RuntimeState<'_> { Ok(()) } - pub fn resize_popup(&mut self, key: usize, width: f32, height: f32, resize_sender: Option>) -> Result<()> { + pub fn resize_popup( + &mut self, + key: usize, + width: f32, + height: f32, + resize_sender: Option>, + ) -> Result<()> { let popup_manager = self .window_state .popup_manager() @@ -416,7 +422,9 @@ impl WindowingSystem { match command { PopupCommand::Show(request) => { - if let Err(e) = runtime_state.show_popup(request, Some(sender_for_handler.clone())) { + if let Err(e) = + runtime_state.show_popup(request, Some(sender_for_handler.clone())) + { log::error!("Failed to show popup: {}", e); } } @@ -426,7 +434,12 @@ impl WindowingSystem { } } PopupCommand::Resize { key, width, height } => { - if let Err(e) = runtime_state.resize_popup(key, width, height, Some(sender_for_handler.clone())) { + if let Err(e) = runtime_state.resize_popup( + key, + width, + height, + Some(sender_for_handler.clone()), + ) { log::error!("Failed to resize popup: {}", e); } } diff --git a/domain/src/value_objects/popup_config.rs b/domain/src/value_objects/popup_config.rs index ddcaf38..910fd4b 100644 --- a/domain/src/value_objects/popup_config.rs +++ b/domain/src/value_objects/popup_config.rs @@ -7,6 +7,8 @@ pub struct PopupConfig { width: f32, height: f32, positioning_mode: PopupPositioningMode, + output_width: f32, + output_height: f32, } impl PopupConfig { @@ -17,6 +19,8 @@ impl PopupConfig { width: f32, height: f32, positioning_mode: PopupPositioningMode, + output_width: f32, + output_height: f32, ) -> Self { Self { reference_x, @@ -24,6 +28,8 @@ impl PopupConfig { width, height, positioning_mode, + output_width, + output_height, } } @@ -54,19 +60,25 @@ impl PopupConfig { #[must_use] pub fn calculated_top_left_x(&self) -> f32 { - if self.positioning_mode.center_x() { + let unclamped_x = if self.positioning_mode.center_x() { self.reference_x - (self.width / 2.0) } else { self.reference_x - } + }; + + let max_x = self.output_width - self.width; + unclamped_x.max(0.0).min(max_x) } #[must_use] pub fn calculated_top_left_y(&self) -> f32 { - if self.positioning_mode.center_y() { + let unclamped_y = if self.positioning_mode.center_y() { self.reference_y - (self.height / 2.0) } else { self.reference_y - } + }; + + let max_y = self.output_height - self.height; + unclamped_y.max(0.0).min(max_y) } }