mirror of
				https://codeberg.org/waydeer/layer-shika.git
				synced 2025-11-04 03:04:23 +00:00 
			
		
		
		
	feat: add popup positioning mode
This commit is contained in:
		
							parent
							
								
									d646306a7a
								
							
						
					
					
						commit
						47487b7062
					
				
					 9 changed files with 251 additions and 122 deletions
				
			
		| 
						 | 
					@ -6,9 +6,7 @@ pub mod wayland;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub use rendering::femtovg::popup_window::PopupWindow;
 | 
					pub use rendering::femtovg::popup_window::PopupWindow;
 | 
				
			||||||
pub use rendering::slint_integration::platform::{
 | 
					pub use rendering::slint_integration::platform::{
 | 
				
			||||||
    clear_popup_position_override, close_current_popup, get_popup_position_override,
 | 
					    clear_popup_config, close_current_popup, get_popup_config, set_popup_config,
 | 
				
			||||||
    set_popup_position_override, clear_popup_size_override, get_popup_size_override,
 | 
					 | 
				
			||||||
    set_popup_size_override,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub mod platform {
 | 
					pub mod platform {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,4 @@
 | 
				
			||||||
 | 
					use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode;
 | 
				
			||||||
use slint::{
 | 
					use slint::{
 | 
				
			||||||
    PlatformError,
 | 
					    PlatformError,
 | 
				
			||||||
    platform::{Platform, WindowAdapter},
 | 
					    platform::{Platform, WindowAdapter},
 | 
				
			||||||
| 
						 | 
					@ -9,6 +10,7 @@ use crate::rendering::femtovg::main_window::FemtoVGWindow;
 | 
				
			||||||
use crate::rendering::femtovg::popup_window::PopupWindow;
 | 
					use crate::rendering::femtovg::popup_window::PopupWindow;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type PopupCreator = dyn Fn() -> Result<Rc<dyn WindowAdapter>, PlatformError>;
 | 
					type PopupCreator = dyn Fn() -> Result<Rc<dyn WindowAdapter>, PlatformError>;
 | 
				
			||||||
 | 
					type PopupConfigData = (f32, f32, f32, f32, PopupPositioningMode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
thread_local! {
 | 
					thread_local! {
 | 
				
			||||||
    static CURRENT_PLATFORM: RefCell<Option<Weak<CustomSlintPlatform>>> = const { RefCell::new(None) };
 | 
					    static CURRENT_PLATFORM: RefCell<Option<Weak<CustomSlintPlatform>>> = const { RefCell::new(None) };
 | 
				
			||||||
| 
						 | 
					@ -24,61 +26,43 @@ pub fn close_current_popup() {
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn set_popup_position_override(x: f32, y: f32) {
 | 
					pub fn set_popup_config(
 | 
				
			||||||
 | 
					    reference_x: f32,
 | 
				
			||||||
 | 
					    reference_y: f32,
 | 
				
			||||||
 | 
					    width: f32,
 | 
				
			||||||
 | 
					    height: f32,
 | 
				
			||||||
 | 
					    positioning_mode: PopupPositioningMode,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
    CURRENT_PLATFORM.with(|platform| {
 | 
					    CURRENT_PLATFORM.with(|platform| {
 | 
				
			||||||
        if let Some(weak_platform) = platform.borrow().as_ref() {
 | 
					        if let Some(weak_platform) = platform.borrow().as_ref() {
 | 
				
			||||||
            if let Some(strong_platform) = weak_platform.upgrade() {
 | 
					            if let Some(strong_platform) = weak_platform.upgrade() {
 | 
				
			||||||
                strong_platform.set_popup_position(x, y);
 | 
					                strong_platform.set_popup_config(
 | 
				
			||||||
 | 
					                    reference_x,
 | 
				
			||||||
 | 
					                    reference_y,
 | 
				
			||||||
 | 
					                    width,
 | 
				
			||||||
 | 
					                    height,
 | 
				
			||||||
 | 
					                    positioning_mode,
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn get_popup_position_override() -> Option<(f32, f32)> {
 | 
					pub fn get_popup_config() -> Option<PopupConfigData> {
 | 
				
			||||||
    CURRENT_PLATFORM.with(|platform| {
 | 
					    CURRENT_PLATFORM.with(|platform| {
 | 
				
			||||||
        platform
 | 
					        platform
 | 
				
			||||||
            .borrow()
 | 
					            .borrow()
 | 
				
			||||||
            .as_ref()
 | 
					            .as_ref()
 | 
				
			||||||
            .and_then(Weak::upgrade)
 | 
					            .and_then(Weak::upgrade)
 | 
				
			||||||
            .and_then(|strong| strong.get_popup_position())
 | 
					            .and_then(|strong| strong.get_popup_config())
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn clear_popup_position_override() {
 | 
					pub fn clear_popup_config() {
 | 
				
			||||||
    CURRENT_PLATFORM.with(|platform| {
 | 
					    CURRENT_PLATFORM.with(|platform| {
 | 
				
			||||||
        if let Some(weak_platform) = platform.borrow().as_ref() {
 | 
					        if let Some(weak_platform) = platform.borrow().as_ref() {
 | 
				
			||||||
            if let Some(strong_platform) = weak_platform.upgrade() {
 | 
					            if let Some(strong_platform) = weak_platform.upgrade() {
 | 
				
			||||||
                strong_platform.clear_popup_position();
 | 
					                strong_platform.clear_popup_config();
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn set_popup_size_override(width: f32, height: f32) {
 | 
					 | 
				
			||||||
    CURRENT_PLATFORM.with(|platform| {
 | 
					 | 
				
			||||||
        if let Some(weak_platform) = platform.borrow().as_ref() {
 | 
					 | 
				
			||||||
            if let Some(strong_platform) = weak_platform.upgrade() {
 | 
					 | 
				
			||||||
                strong_platform.set_popup_size(width, height);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn get_popup_size_override() -> Option<(f32, f32)> {
 | 
					 | 
				
			||||||
    CURRENT_PLATFORM.with(|platform| {
 | 
					 | 
				
			||||||
        platform
 | 
					 | 
				
			||||||
            .borrow()
 | 
					 | 
				
			||||||
            .as_ref()
 | 
					 | 
				
			||||||
            .and_then(Weak::upgrade)
 | 
					 | 
				
			||||||
            .and_then(|strong| strong.get_popup_size())
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn clear_popup_size_override() {
 | 
					 | 
				
			||||||
    CURRENT_PLATFORM.with(|platform| {
 | 
					 | 
				
			||||||
        if let Some(weak_platform) = platform.borrow().as_ref() {
 | 
					 | 
				
			||||||
            if let Some(strong_platform) = weak_platform.upgrade() {
 | 
					 | 
				
			||||||
                strong_platform.clear_popup_size();
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
| 
						 | 
					@ -89,8 +73,7 @@ pub struct CustomSlintPlatform {
 | 
				
			||||||
    popup_creator: RefCell<Option<Rc<PopupCreator>>>,
 | 
					    popup_creator: RefCell<Option<Rc<PopupCreator>>>,
 | 
				
			||||||
    first_call: Cell<bool>,
 | 
					    first_call: Cell<bool>,
 | 
				
			||||||
    last_popup: RefCell<Option<Weak<PopupWindow>>>,
 | 
					    last_popup: RefCell<Option<Weak<PopupWindow>>>,
 | 
				
			||||||
    popup_position: RefCell<Option<(f32, f32)>>,
 | 
					    popup_config: RefCell<Option<PopupConfigData>>,
 | 
				
			||||||
    popup_size: RefCell<Option<(f32, f32)>>,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl CustomSlintPlatform {
 | 
					impl CustomSlintPlatform {
 | 
				
			||||||
| 
						 | 
					@ -101,8 +84,7 @@ impl CustomSlintPlatform {
 | 
				
			||||||
            popup_creator: RefCell::new(None),
 | 
					            popup_creator: RefCell::new(None),
 | 
				
			||||||
            first_call: Cell::new(true),
 | 
					            first_call: Cell::new(true),
 | 
				
			||||||
            last_popup: RefCell::new(None),
 | 
					            last_popup: RefCell::new(None),
 | 
				
			||||||
            popup_position: RefCell::new(None),
 | 
					            popup_config: RefCell::new(None),
 | 
				
			||||||
            popup_size: RefCell::new(None),
 | 
					 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        CURRENT_PLATFORM.with(|current| {
 | 
					        CURRENT_PLATFORM.with(|current| {
 | 
				
			||||||
| 
						 | 
					@ -133,29 +115,25 @@ impl CustomSlintPlatform {
 | 
				
			||||||
        *self.last_popup.borrow_mut() = None;
 | 
					        *self.last_popup.borrow_mut() = None;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn set_popup_position(&self, x: f32, y: f32) {
 | 
					    pub fn set_popup_config(
 | 
				
			||||||
        *self.popup_position.borrow_mut() = Some((x, y));
 | 
					        &self,
 | 
				
			||||||
 | 
					        reference_x: f32,
 | 
				
			||||||
 | 
					        reference_y: f32,
 | 
				
			||||||
 | 
					        width: f32,
 | 
				
			||||||
 | 
					        height: f32,
 | 
				
			||||||
 | 
					        positioning_mode: PopupPositioningMode,
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        *self.popup_config.borrow_mut() =
 | 
				
			||||||
 | 
					            Some((reference_x, reference_y, width, height, positioning_mode));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[must_use]
 | 
					    #[must_use]
 | 
				
			||||||
    pub fn get_popup_position(&self) -> Option<(f32, f32)> {
 | 
					    pub fn get_popup_config(&self) -> Option<PopupConfigData> {
 | 
				
			||||||
        *self.popup_position.borrow()
 | 
					        *self.popup_config.borrow()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn clear_popup_position(&self) {
 | 
					    pub fn clear_popup_config(&self) {
 | 
				
			||||||
        *self.popup_position.borrow_mut() = None;
 | 
					        *self.popup_config.borrow_mut() = None;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn set_popup_size(&self, width: f32, height: f32) {
 | 
					 | 
				
			||||||
        *self.popup_size.borrow_mut() = Some((width, height));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn get_popup_size(&self) -> Option<(f32, f32)> {
 | 
					 | 
				
			||||||
        *self.popup_size.borrow()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn clear_popup_size(&self) {
 | 
					 | 
				
			||||||
        *self.popup_size.borrow_mut() = None;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@ use crate::wayland::{
 | 
				
			||||||
    config::{LayerSurfaceParams, WaylandWindowConfig},
 | 
					    config::{LayerSurfaceParams, WaylandWindowConfig},
 | 
				
			||||||
    globals::context::GlobalContext,
 | 
					    globals::context::GlobalContext,
 | 
				
			||||||
    surfaces::layer_surface::{SurfaceCtx, SurfaceSetupParams},
 | 
					    surfaces::layer_surface::{SurfaceCtx, SurfaceSetupParams},
 | 
				
			||||||
    surfaces::popup_manager::{PopupContext, PopupManager},
 | 
					    surfaces::popup_manager::{CreatePopupParams, PopupContext, PopupManager},
 | 
				
			||||||
    surfaces::{
 | 
					    surfaces::{
 | 
				
			||||||
        surface_builder::WindowStateBuilder,
 | 
					        surface_builder::WindowStateBuilder,
 | 
				
			||||||
        surface_state::{SharedPointerSerial, WindowState},
 | 
					        surface_state::{SharedPointerSerial, WindowState},
 | 
				
			||||||
| 
						 | 
					@ -11,13 +11,15 @@ use crate::wayland::{
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    errors::{EventLoopError, LayerShikaError, RenderingError, Result},
 | 
					    errors::{EventLoopError, LayerShikaError, RenderingError, Result},
 | 
				
			||||||
    rendering::{
 | 
					    rendering::{
 | 
				
			||||||
        egl::context::EGLContext, femtovg::main_window::FemtoVGWindow,
 | 
					        egl::context::EGLContext,
 | 
				
			||||||
        slint_integration::platform::CustomSlintPlatform,
 | 
					        femtovg::main_window::FemtoVGWindow,
 | 
				
			||||||
 | 
					        slint_integration::platform::{CustomSlintPlatform, clear_popup_config, get_popup_config},
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use core::result::Result as CoreResult;
 | 
					use core::result::Result as CoreResult;
 | 
				
			||||||
use layer_shika_domain::errors::DomainError;
 | 
					use layer_shika_domain::errors::DomainError;
 | 
				
			||||||
use layer_shika_domain::ports::windowing::WindowingSystemPort;
 | 
					use layer_shika_domain::ports::windowing::WindowingSystemPort;
 | 
				
			||||||
 | 
					use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode;
 | 
				
			||||||
use log::{error, info};
 | 
					use log::{error, info};
 | 
				
			||||||
use slint::{
 | 
					use slint::{
 | 
				
			||||||
    LogicalPosition, PhysicalSize, PlatformError, WindowPosition,
 | 
					    LogicalPosition, PhysicalSize, PlatformError, WindowPosition,
 | 
				
			||||||
| 
						 | 
					@ -173,14 +175,45 @@ impl WaylandWindowingSystem {
 | 
				
			||||||
        let layer_surface = state.layer_surface();
 | 
					        let layer_surface = state.layer_surface();
 | 
				
			||||||
        let queue_handle = event_queue.handle();
 | 
					        let queue_handle = event_queue.handle();
 | 
				
			||||||
        let serial_holder = Rc::clone(shared_serial);
 | 
					        let serial_holder = Rc::clone(shared_serial);
 | 
				
			||||||
 | 
					        let output_size = *state.output_size();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        #[allow(clippy::cast_precision_loss)]
 | 
				
			||||||
 | 
					        let default_width = output_size.width as f32;
 | 
				
			||||||
 | 
					        #[allow(clippy::cast_precision_loss)]
 | 
				
			||||||
 | 
					        let default_height = output_size.height as f32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        platform.set_popup_creator(move || {
 | 
					        platform.set_popup_creator(move || {
 | 
				
			||||||
            info!("Popup creator called! Creating popup window...");
 | 
					            info!("Popup creator called! Creating popup window...");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let serial = serial_holder.get();
 | 
					            let serial = serial_holder.get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let (reference_x, reference_y, width, height, positioning_mode) = get_popup_config()
 | 
				
			||||||
 | 
					                .unwrap_or_else(|| {
 | 
				
			||||||
 | 
					                    log::warn!("No popup config provided, using output size as defaults");
 | 
				
			||||||
 | 
					                    (
 | 
				
			||||||
 | 
					                        0.0,
 | 
				
			||||||
 | 
					                        0.0,
 | 
				
			||||||
 | 
					                        default_width,
 | 
				
			||||||
 | 
					                        default_height,
 | 
				
			||||||
 | 
					                        PopupPositioningMode::TopLeft,
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            clear_popup_config();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let popup_window = popup_manager_clone
 | 
					            let popup_window = popup_manager_clone
 | 
				
			||||||
                .create_popup(&queue_handle, &layer_surface, serial)
 | 
					                .create_popup(
 | 
				
			||||||
 | 
					                    &queue_handle,
 | 
				
			||||||
 | 
					                    &layer_surface,
 | 
				
			||||||
 | 
					                    CreatePopupParams {
 | 
				
			||||||
 | 
					                        last_pointer_serial: serial,
 | 
				
			||||||
 | 
					                        reference_x,
 | 
				
			||||||
 | 
					                        reference_y,
 | 
				
			||||||
 | 
					                        width,
 | 
				
			||||||
 | 
					                        height,
 | 
				
			||||||
 | 
					                        positioning_mode,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
                .map_err(|e| PlatformError::Other(format!("Failed to create popup: {e}")))?;
 | 
					                .map_err(|e| PlatformError::Other(format!("Failed to create popup: {e}")))?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if let Some(platform) = platform_weak.upgrade() {
 | 
					            if let Some(platform) = platform_weak.upgrade() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,8 @@
 | 
				
			||||||
use crate::errors::{LayerShikaError, Result};
 | 
					use crate::errors::{LayerShikaError, Result};
 | 
				
			||||||
use crate::rendering::egl::context::EGLContext;
 | 
					use crate::rendering::egl::context::EGLContext;
 | 
				
			||||||
use crate::rendering::femtovg::popup_window::PopupWindow;
 | 
					use crate::rendering::femtovg::popup_window::PopupWindow;
 | 
				
			||||||
use crate::rendering::slint_integration::platform::{
 | 
					use layer_shika_domain::value_objects::popup_config::PopupConfig;
 | 
				
			||||||
    clear_popup_position_override, get_popup_position_override,
 | 
					use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode;
 | 
				
			||||||
    clear_popup_size_override, get_popup_size_override,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
use log::info;
 | 
					use log::info;
 | 
				
			||||||
use slab::Slab;
 | 
					use slab::Slab;
 | 
				
			||||||
use slint::{platform::femtovg_renderer::FemtoVGRenderer, PhysicalSize, WindowSize};
 | 
					use slint::{platform::femtovg_renderer::FemtoVGRenderer, PhysicalSize, WindowSize};
 | 
				
			||||||
| 
						 | 
					@ -23,6 +21,16 @@ use wayland_protocols::xdg::shell::client::xdg_wm_base::XdgWmBase;
 | 
				
			||||||
use super::popup_surface::PopupSurface;
 | 
					use super::popup_surface::PopupSurface;
 | 
				
			||||||
use super::surface_state::WindowState;
 | 
					use super::surface_state::WindowState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, Copy)]
 | 
				
			||||||
 | 
					pub struct CreatePopupParams {
 | 
				
			||||||
 | 
					    pub last_pointer_serial: u32,
 | 
				
			||||||
 | 
					    pub reference_x: f32,
 | 
				
			||||||
 | 
					    pub reference_y: f32,
 | 
				
			||||||
 | 
					    pub width: f32,
 | 
				
			||||||
 | 
					    pub height: f32,
 | 
				
			||||||
 | 
					    pub positioning_mode: PopupPositioningMode,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct PopupContext {
 | 
					pub struct PopupContext {
 | 
				
			||||||
    compositor: WlCompositor,
 | 
					    compositor: WlCompositor,
 | 
				
			||||||
    xdg_wm_base: Option<XdgWmBase>,
 | 
					    xdg_wm_base: Option<XdgWmBase>,
 | 
				
			||||||
| 
						 | 
					@ -89,7 +97,7 @@ impl PopupManager {
 | 
				
			||||||
        self: &Rc<Self>,
 | 
					        self: &Rc<Self>,
 | 
				
			||||||
        queue_handle: &QueueHandle<WindowState>,
 | 
					        queue_handle: &QueueHandle<WindowState>,
 | 
				
			||||||
        parent_layer_surface: &ZwlrLayerSurfaceV1,
 | 
					        parent_layer_surface: &ZwlrLayerSurfaceV1,
 | 
				
			||||||
        last_pointer_serial: u32,
 | 
					        params: CreatePopupParams,
 | 
				
			||||||
    ) -> Result<Rc<PopupWindow>> {
 | 
					    ) -> Result<Rc<PopupWindow>> {
 | 
				
			||||||
        let xdg_wm_base = self.context.xdg_wm_base.as_ref().ok_or_else(|| {
 | 
					        let xdg_wm_base = self.context.xdg_wm_base.as_ref().ok_or_else(|| {
 | 
				
			||||||
            LayerShikaError::WindowConfiguration {
 | 
					            LayerShikaError::WindowConfiguration {
 | 
				
			||||||
| 
						 | 
					@ -97,41 +105,32 @@ impl PopupManager {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        })?;
 | 
					        })?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let pointer_position = if let Some((x, y)) = get_popup_position_override() {
 | 
					 | 
				
			||||||
            info!("Using explicit popup position: ({}, {})", x, y);
 | 
					 | 
				
			||||||
            clear_popup_position_override();
 | 
					 | 
				
			||||||
            slint::LogicalPosition::new(x, y)
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            log::error!("No popup position provided - using (0, 0) as fallback");
 | 
					 | 
				
			||||||
            slint::LogicalPosition::new(0.0, 0.0)
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let scale_factor = *self.current_scale_factor.borrow();
 | 
					        let scale_factor = *self.current_scale_factor.borrow();
 | 
				
			||||||
        let output_size = *self.current_output_size.borrow();
 | 
					 | 
				
			||||||
        info!(
 | 
					        info!(
 | 
				
			||||||
            "Creating popup window with scale factor {scale_factor} and output size {output_size:?}"
 | 
					            "Creating popup window with scale factor {scale_factor}, reference=({}, {}), size=({} x {}), mode={:?}",
 | 
				
			||||||
 | 
					            params.reference_x,
 | 
				
			||||||
 | 
					            params.reference_y,
 | 
				
			||||||
 | 
					            params.width,
 | 
				
			||||||
 | 
					            params.height,
 | 
				
			||||||
 | 
					            params.positioning_mode
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let popup_config = PopupConfig::new(
 | 
				
			||||||
 | 
					            params.reference_x,
 | 
				
			||||||
 | 
					            params.reference_y,
 | 
				
			||||||
 | 
					            params.width,
 | 
				
			||||||
 | 
					            params.height,
 | 
				
			||||||
 | 
					            params.positioning_mode,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #[allow(clippy::cast_precision_loss)]
 | 
					 | 
				
			||||||
        let logical_size = if let Some((width, height)) = get_popup_size_override() {
 | 
					 | 
				
			||||||
            info!("Using explicit popup size: ({}, {})", width, height);
 | 
					 | 
				
			||||||
            clear_popup_size_override();
 | 
					 | 
				
			||||||
            slint::LogicalSize::new(width, height)
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            info!("No popup size override - using full output size");
 | 
					 | 
				
			||||||
            slint::LogicalSize::new(
 | 
					 | 
				
			||||||
                output_size.width as f32 / scale_factor,
 | 
					 | 
				
			||||||
                output_size.height as f32 / scale_factor,
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        #[allow(clippy::cast_possible_truncation)]
 | 
					        #[allow(clippy::cast_possible_truncation)]
 | 
				
			||||||
        #[allow(clippy::cast_sign_loss)]
 | 
					        #[allow(clippy::cast_sign_loss)]
 | 
				
			||||||
        let popup_size = PhysicalSize::new(
 | 
					        let popup_size = PhysicalSize::new(
 | 
				
			||||||
            (logical_size.width * scale_factor) as u32,
 | 
					            (params.width * scale_factor) as u32,
 | 
				
			||||||
            (logical_size.height * scale_factor) as u32,
 | 
					            (params.height * scale_factor) as u32,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        info!("Popup logical size: {logical_size:?}, physical size: {popup_size:?}");
 | 
					        info!("Popup physical size: {popup_size:?}");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let popup_surface = PopupSurface::create(&super::popup_surface::PopupSurfaceParams {
 | 
					        let popup_surface = PopupSurface::create(&super::popup_surface::PopupSurfaceParams {
 | 
				
			||||||
            compositor: &self.context.compositor,
 | 
					            compositor: &self.context.compositor,
 | 
				
			||||||
| 
						 | 
					@ -140,12 +139,12 @@ impl PopupManager {
 | 
				
			||||||
            fractional_scale_manager: self.context.fractional_scale_manager.as_ref(),
 | 
					            fractional_scale_manager: self.context.fractional_scale_manager.as_ref(),
 | 
				
			||||||
            viewporter: self.context.viewporter.as_ref(),
 | 
					            viewporter: self.context.viewporter.as_ref(),
 | 
				
			||||||
            queue_handle,
 | 
					            queue_handle,
 | 
				
			||||||
            position: pointer_position,
 | 
					            popup_config,
 | 
				
			||||||
            size: popup_size,
 | 
					            physical_size: popup_size,
 | 
				
			||||||
            scale_factor,
 | 
					            scale_factor,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        popup_surface.grab(&self.context.seat, last_pointer_serial);
 | 
					        popup_surface.grab(&self.context.seat, params.last_pointer_serial);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let context = EGLContext::builder()
 | 
					        let context = EGLContext::builder()
 | 
				
			||||||
            .with_display_id(self.context.display.id())
 | 
					            .with_display_id(self.context.display.id())
 | 
				
			||||||
| 
						 | 
					@ -158,7 +157,10 @@ impl PopupManager {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let popup_window = PopupWindow::new(renderer);
 | 
					        let popup_window = PopupWindow::new(renderer);
 | 
				
			||||||
        popup_window.set_scale_factor(scale_factor);
 | 
					        popup_window.set_scale_factor(scale_factor);
 | 
				
			||||||
        popup_window.set_size(WindowSize::Logical(logical_size));
 | 
					        popup_window.set_size(WindowSize::Logical(slint::LogicalSize::new(
 | 
				
			||||||
 | 
					            params.width,
 | 
				
			||||||
 | 
					            params.height,
 | 
				
			||||||
 | 
					        )));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let key = self.popups.borrow_mut().insert(ActivePopup {
 | 
					        let key = self.popups.borrow_mut().insert(ActivePopup {
 | 
				
			||||||
            surface: popup_surface,
 | 
					            surface: popup_surface,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
 | 
					use layer_shika_domain::value_objects::popup_config::PopupConfig;
 | 
				
			||||||
use log::info;
 | 
					use log::info;
 | 
				
			||||||
use slint::{LogicalPosition, PhysicalSize};
 | 
					use slint::PhysicalSize;
 | 
				
			||||||
use smithay_client_toolkit::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1;
 | 
					use smithay_client_toolkit::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1;
 | 
				
			||||||
use std::rc::Rc;
 | 
					use std::rc::Rc;
 | 
				
			||||||
use wayland_client::{
 | 
					use wayland_client::{
 | 
				
			||||||
| 
						 | 
					@ -30,8 +31,8 @@ pub struct PopupSurfaceParams<'a> {
 | 
				
			||||||
    pub fractional_scale_manager: Option<&'a WpFractionalScaleManagerV1>,
 | 
					    pub fractional_scale_manager: Option<&'a WpFractionalScaleManagerV1>,
 | 
				
			||||||
    pub viewporter: Option<&'a WpViewporter>,
 | 
					    pub viewporter: Option<&'a WpViewporter>,
 | 
				
			||||||
    pub queue_handle: &'a QueueHandle<WindowState>,
 | 
					    pub queue_handle: &'a QueueHandle<WindowState>,
 | 
				
			||||||
    pub position: LogicalPosition,
 | 
					    pub popup_config: PopupConfig,
 | 
				
			||||||
    pub size: PhysicalSize,
 | 
					    pub physical_size: PhysicalSize,
 | 
				
			||||||
    pub scale_factor: f32,
 | 
					    pub scale_factor: f32,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -76,14 +77,14 @@ impl PopupSurface {
 | 
				
			||||||
        #[allow(clippy::cast_precision_loss)]
 | 
					        #[allow(clippy::cast_precision_loss)]
 | 
				
			||||||
        #[allow(clippy::cast_possible_truncation)]
 | 
					        #[allow(clippy::cast_possible_truncation)]
 | 
				
			||||||
        if let Some(ref vp) = viewport {
 | 
					        if let Some(ref vp) = viewport {
 | 
				
			||||||
            let logical_width = (params.size.width as f32 / params.scale_factor) as i32;
 | 
					            let logical_width = (params.physical_size.width as f32 / params.scale_factor) as i32;
 | 
				
			||||||
            let logical_height = (params.size.height as f32 / params.scale_factor) as i32;
 | 
					            let logical_height = (params.physical_size.height as f32 / params.scale_factor) as i32;
 | 
				
			||||||
            info!(
 | 
					            info!(
 | 
				
			||||||
                "Setting viewport destination to logical size: {}x{} (physical: {}x{}, scale: {})",
 | 
					                "Setting viewport destination to logical size: {}x{} (physical: {}x{}, scale: {})",
 | 
				
			||||||
                logical_width,
 | 
					                logical_width,
 | 
				
			||||||
                logical_height,
 | 
					                logical_height,
 | 
				
			||||||
                params.size.width,
 | 
					                params.physical_size.width,
 | 
				
			||||||
                params.size.height,
 | 
					                params.physical_size.height,
 | 
				
			||||||
                params.scale_factor
 | 
					                params.scale_factor
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            vp.set_destination(logical_width, logical_height);
 | 
					            vp.set_destination(logical_width, logical_height);
 | 
				
			||||||
| 
						 | 
					@ -102,24 +103,29 @@ impl PopupSurface {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[allow(clippy::cast_possible_truncation)]
 | 
					    #[allow(clippy::cast_possible_truncation)]
 | 
				
			||||||
    #[allow(clippy::cast_possible_wrap)]
 | 
					    #[allow(clippy::cast_possible_wrap)]
 | 
				
			||||||
 | 
					    #[allow(clippy::cast_sign_loss)]
 | 
				
			||||||
 | 
					    #[allow(clippy::cast_precision_loss)]
 | 
				
			||||||
    fn create_positioner(params: &PopupSurfaceParams<'_>) -> XdgPositioner {
 | 
					    fn create_positioner(params: &PopupSurfaceParams<'_>) -> XdgPositioner {
 | 
				
			||||||
        let positioner = params
 | 
					        let positioner = params
 | 
				
			||||||
            .xdg_wm_base
 | 
					            .xdg_wm_base
 | 
				
			||||||
            .create_positioner(params.queue_handle, ());
 | 
					            .create_positioner(params.queue_handle, ());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let x = params.position.x as i32;
 | 
					        let calculated_x = params.popup_config.calculated_top_left_x() as i32;
 | 
				
			||||||
        let y = params.position.y as i32;
 | 
					        let calculated_y = params.popup_config.calculated_top_left_y() as i32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        #[allow(clippy::cast_possible_truncation)]
 | 
					        info!(
 | 
				
			||||||
        #[allow(clippy::cast_sign_loss)]
 | 
					            "Popup positioning: reference=({}, {}), mode={:?}, calculated_top_left=({}, {})",
 | 
				
			||||||
        #[allow(clippy::cast_precision_loss)]
 | 
					            params.popup_config.reference_x(),
 | 
				
			||||||
        let logical_width = (params.size.width as f32 / params.scale_factor) as i32;
 | 
					            params.popup_config.reference_y(),
 | 
				
			||||||
        #[allow(clippy::cast_possible_truncation)]
 | 
					            params.popup_config.positioning_mode(),
 | 
				
			||||||
        #[allow(clippy::cast_sign_loss)]
 | 
					            calculated_x,
 | 
				
			||||||
        #[allow(clippy::cast_precision_loss)]
 | 
					            calculated_y
 | 
				
			||||||
        let logical_height = (params.size.height as f32 / params.scale_factor) as i32;
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        positioner.set_anchor_rect(x, y, 1, 1);
 | 
					        let logical_width = (params.physical_size.width as f32 / params.scale_factor) as i32;
 | 
				
			||||||
 | 
					        let logical_height = (params.physical_size.height as f32 / params.scale_factor) as i32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        positioner.set_anchor_rect(calculated_x, calculated_y, 1, 1);
 | 
				
			||||||
        positioner.set_size(logical_width, logical_height);
 | 
					        positioner.set_size(logical_width, logical_height);
 | 
				
			||||||
        positioner.set_anchor(Anchor::TopLeft);
 | 
					        positioner.set_anchor(Anchor::TopLeft);
 | 
				
			||||||
        positioner.set_gravity(Gravity::BottomRight);
 | 
					        positioner.set_gravity(Gravity::BottomRight);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,11 +11,9 @@ pub use builder::LayerShika;
 | 
				
			||||||
pub use layer_shika_adapters::PopupWindow;
 | 
					pub use layer_shika_adapters::PopupWindow;
 | 
				
			||||||
pub use layer_shika_adapters::close_current_popup;
 | 
					pub use layer_shika_adapters::close_current_popup;
 | 
				
			||||||
pub use layer_shika_adapters::platform::{calloop, slint, slint_interpreter};
 | 
					pub use layer_shika_adapters::platform::{calloop, slint, slint_interpreter};
 | 
				
			||||||
pub use layer_shika_adapters::{
 | 
					pub use layer_shika_adapters::{clear_popup_config, get_popup_config, set_popup_config};
 | 
				
			||||||
    clear_popup_position_override, get_popup_position_override, set_popup_position_override,
 | 
					 | 
				
			||||||
    clear_popup_size_override, get_popup_size_override, set_popup_size_override,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
pub use layer_shika_domain::value_objects::anchor::AnchorEdges;
 | 
					pub use layer_shika_domain::value_objects::anchor::AnchorEdges;
 | 
				
			||||||
 | 
					pub use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub type Result<T> = StdResult<T, Error>;
 | 
					pub type Result<T> = StdResult<T, Error>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,3 +2,5 @@ pub mod anchor;
 | 
				
			||||||
pub mod dimensions;
 | 
					pub mod dimensions;
 | 
				
			||||||
pub mod layer;
 | 
					pub mod layer;
 | 
				
			||||||
pub mod margins;
 | 
					pub mod margins;
 | 
				
			||||||
 | 
					pub mod popup_config;
 | 
				
			||||||
 | 
					pub mod popup_positioning_mode;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										72
									
								
								domain/src/value_objects/popup_config.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								domain/src/value_objects/popup_config.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,72 @@
 | 
				
			||||||
 | 
					use super::popup_positioning_mode::PopupPositioningMode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, Copy)]
 | 
				
			||||||
 | 
					pub struct PopupConfig {
 | 
				
			||||||
 | 
					    reference_x: f32,
 | 
				
			||||||
 | 
					    reference_y: f32,
 | 
				
			||||||
 | 
					    width: f32,
 | 
				
			||||||
 | 
					    height: f32,
 | 
				
			||||||
 | 
					    positioning_mode: PopupPositioningMode,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl PopupConfig {
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub const fn new(
 | 
				
			||||||
 | 
					        reference_x: f32,
 | 
				
			||||||
 | 
					        reference_y: f32,
 | 
				
			||||||
 | 
					        width: f32,
 | 
				
			||||||
 | 
					        height: f32,
 | 
				
			||||||
 | 
					        positioning_mode: PopupPositioningMode,
 | 
				
			||||||
 | 
					    ) -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            reference_x,
 | 
				
			||||||
 | 
					            reference_y,
 | 
				
			||||||
 | 
					            width,
 | 
				
			||||||
 | 
					            height,
 | 
				
			||||||
 | 
					            positioning_mode,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub const fn reference_x(&self) -> f32 {
 | 
				
			||||||
 | 
					        self.reference_x
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub const fn reference_y(&self) -> f32 {
 | 
				
			||||||
 | 
					        self.reference_y
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub const fn width(&self) -> f32 {
 | 
				
			||||||
 | 
					        self.width
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub const fn height(&self) -> f32 {
 | 
				
			||||||
 | 
					        self.height
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub const fn positioning_mode(&self) -> PopupPositioningMode {
 | 
				
			||||||
 | 
					        self.positioning_mode
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub fn calculated_top_left_x(&self) -> f32 {
 | 
				
			||||||
 | 
					        if self.positioning_mode.center_x() {
 | 
				
			||||||
 | 
					            self.reference_x - (self.width / 2.0)
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            self.reference_x
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub fn calculated_top_left_y(&self) -> f32 {
 | 
				
			||||||
 | 
					        if self.positioning_mode.center_y() {
 | 
				
			||||||
 | 
					            self.reference_y - (self.height / 2.0)
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            self.reference_y
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										40
									
								
								domain/src/value_objects/popup_positioning_mode.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								domain/src/value_objects/popup_positioning_mode.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,40 @@
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 | 
				
			||||||
 | 
					pub enum PopupPositioningMode {
 | 
				
			||||||
 | 
					    TopLeft,
 | 
				
			||||||
 | 
					    TopCenter,
 | 
				
			||||||
 | 
					    TopRight,
 | 
				
			||||||
 | 
					    CenterLeft,
 | 
				
			||||||
 | 
					    Center,
 | 
				
			||||||
 | 
					    CenterRight,
 | 
				
			||||||
 | 
					    BottomLeft,
 | 
				
			||||||
 | 
					    BottomCenter,
 | 
				
			||||||
 | 
					    BottomRight,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl PopupPositioningMode {
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub const fn center_x(self) -> bool {
 | 
				
			||||||
 | 
					        matches!(self, Self::TopCenter | Self::Center | Self::BottomCenter)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub const fn center_y(self) -> bool {
 | 
				
			||||||
 | 
					        matches!(self, Self::CenterLeft | Self::Center | Self::CenterRight)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub const fn from_flags(center_x: bool, center_y: bool) -> Self {
 | 
				
			||||||
 | 
					        match (center_x, center_y) {
 | 
				
			||||||
 | 
					            (false, false) => Self::TopLeft,
 | 
				
			||||||
 | 
					            (true, false) => Self::TopCenter,
 | 
				
			||||||
 | 
					            (false, true) => Self::CenterLeft,
 | 
				
			||||||
 | 
					            (true, true) => Self::Center,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Default for PopupPositioningMode {
 | 
				
			||||||
 | 
					    fn default() -> Self {
 | 
				
			||||||
 | 
					        Self::TopLeft
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue