diff --git a/crates/composition/src/event_loop.rs b/crates/composition/src/event_loop.rs index 9c08d9d..75218df 100644 --- a/crates/composition/src/event_loop.rs +++ b/crates/composition/src/event_loop.rs @@ -39,8 +39,7 @@ impl ShellEventLoop { /// Handle for registering custom event sources with the event loop /// -/// Allows adding timers, channels, and file descriptors to the event loop. -/// Obtained via `Shell::event_loop_handle()`. +/// Supports timers, channels, file descriptors, and custom event sources. pub struct EventLoopHandle { system: Weak>, } @@ -73,7 +72,7 @@ impl EventLoopHandle { /// Add a timer that fires after the specified duration /// - /// Callback receives the deadline and can return `TimeoutAction::ToInstant` to reschedule. + /// Return `TimeoutAction::Drop` for one-shot, `ToDuration(d)` to repeat, or `ToInstant(i)` for next deadline. pub fn add_timer(&self, duration: Duration, mut callback: F) -> Result where F: FnMut(Instant, &mut AppState) -> TimeoutAction + 'static, @@ -99,7 +98,7 @@ impl EventLoopHandle { /// Add a channel for sending messages to the event loop from any thread /// - /// Returns a registration token and sender. Messages sent via the sender trigger the callback. + /// The sender can be cloned and sent across threads. Messages are queued and processed on the main thread. pub fn add_channel( &self, mut callback: F, diff --git a/crates/composition/src/layer_surface.rs b/crates/composition/src/layer_surface.rs index 1a8b6f7..67ad8ea 100644 --- a/crates/composition/src/layer_surface.rs +++ b/crates/composition/src/layer_surface.rs @@ -6,6 +6,9 @@ use layer_shika_domain::value_objects::keyboard_interactivity::KeyboardInteracti use layer_shika_domain::value_objects::layer::Layer; use layer_shika_domain::value_objects::margins::Margins; +/// Low-level handle for configuring layer-shell surface properties +/// +/// Always call `commit()` after changes to apply them to the compositor. pub struct LayerSurfaceHandle<'a> { window_state: &'a SurfaceState, } @@ -15,10 +18,12 @@ impl<'a> LayerSurfaceHandle<'a> { Self { window_state } } + /// Sets the anchor using Wayland anchor flags pub fn set_anchor(&self, anchor: Anchor) { self.window_state.layer_surface().set_anchor(anchor); } + /// Sets the anchor edges for positioning pub fn set_anchor_edges(&self, anchor: AnchorEdges) { let wayland_anchor = Self::convert_anchor(anchor); self.window_state.layer_surface().set_anchor(wayland_anchor); @@ -43,14 +48,19 @@ impl<'a> LayerSurfaceHandle<'a> { result } + /// Sets the surface size in pixels pub fn set_size(&self, width: u32, height: u32) { self.window_state.layer_surface().set_size(width, height); } + /// Sets the exclusive zone in pixels + /// + /// Positive values reserve space, `0` means no reservation, `-1` for auto-calculation. pub fn set_exclusive_zone(&self, zone: i32) { self.window_state.layer_surface().set_exclusive_zone(zone); } + /// Sets the margins around the surface pub fn set_margins(&self, margins: Margins) { self.window_state.layer_surface().set_margin( margins.top, @@ -60,6 +70,7 @@ impl<'a> LayerSurfaceHandle<'a> { ); } + /// Sets the keyboard interactivity mode pub fn set_keyboard_interactivity(&self, mode: KeyboardInteractivity) { let wayland_mode = match mode { KeyboardInteractivity::None => WaylandKeyboardInteractivity::None, @@ -71,6 +82,9 @@ impl<'a> LayerSurfaceHandle<'a> { .set_keyboard_interactivity(wayland_mode); } + /// Sets the layer (stacking order) + /// + /// From bottom to top: Background, Bottom, Top, Overlay. pub fn set_layer(&self, layer: Layer) { let wayland_layer = match layer { Layer::Background => WaylandLayer::Background, @@ -81,6 +95,7 @@ impl<'a> LayerSurfaceHandle<'a> { self.window_state.layer_surface().set_layer(wayland_layer); } + /// Commits all pending changes to the compositor pub fn commit(&self) { self.window_state.commit_surface(); } diff --git a/crates/composition/src/popup_builder.rs b/crates/composition/src/popup_builder.rs index 4f36f57..4cec8aa 100644 --- a/crates/composition/src/popup_builder.rs +++ b/crates/composition/src/popup_builder.rs @@ -5,6 +5,9 @@ use layer_shika_domain::prelude::AnchorStrategy; use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode; use layer_shika_domain::value_objects::popup_request::{PopupPlacement, PopupRequest, PopupSize}; +/// Builder for configuring and displaying popup windows +/// +/// Useful for context menus, tooltips, dropdowns, and other transient UI. pub struct PopupBuilder<'a> { shell: &'a Shell, component: String, @@ -30,120 +33,142 @@ impl<'a> PopupBuilder<'a> { } } + /// Positions the popup at the current cursor location #[must_use] pub fn relative_to_cursor(mut self) -> Self { self.reference = PopupPlacement::AtCursor; self } + /// Positions the popup at the specified coordinates #[must_use] pub fn relative_to_point(mut self, x: f32, y: f32) -> Self { self.reference = PopupPlacement::AtPosition { x, y }; self } + /// Positions the popup relative to a rectangular area #[must_use] pub fn relative_to_rect(mut self, x: f32, y: f32, w: f32, h: f32) -> Self { self.reference = PopupPlacement::AtRect { x, y, w, h }; self } + /// Sets the anchor point for positioning the popup #[must_use] pub const fn anchor(mut self, anchor: PopupPositioningMode) -> Self { self.anchor = anchor; self } + /// Anchors popup to top-left corner #[must_use] pub fn anchor_top_left(mut self) -> Self { self.anchor = PopupPositioningMode::TopLeft; self } + /// Anchors popup to top-center #[must_use] pub fn anchor_top_center(mut self) -> Self { self.anchor = PopupPositioningMode::TopCenter; self } + /// Anchors popup to top-right corner #[must_use] pub fn anchor_top_right(mut self) -> Self { self.anchor = PopupPositioningMode::TopRight; self } + /// Anchors popup to center-left #[must_use] pub fn anchor_center_left(mut self) -> Self { self.anchor = PopupPositioningMode::CenterLeft; self } + /// Anchors popup to center #[must_use] pub fn anchor_center(mut self) -> Self { self.anchor = PopupPositioningMode::Center; self } + /// Anchors popup to center-right #[must_use] pub fn anchor_center_right(mut self) -> Self { self.anchor = PopupPositioningMode::CenterRight; self } + /// Anchors popup to bottom-left corner #[must_use] pub fn anchor_bottom_left(mut self) -> Self { self.anchor = PopupPositioningMode::BottomLeft; self } + /// Anchors popup to bottom-center #[must_use] pub fn anchor_bottom_center(mut self) -> Self { self.anchor = PopupPositioningMode::BottomCenter; self } + /// Anchors popup to bottom-right corner #[must_use] pub fn anchor_bottom_right(mut self) -> Self { self.anchor = PopupPositioningMode::BottomRight; self } + /// Sets the popup size strategy + /// + /// Use `PopupSize::Content` for auto-sizing or `PopupSize::Fixed { w, h }` for explicit dimensions. #[must_use] pub const fn size(mut self, size: PopupSize) -> Self { self.size = size; self } + /// Sets a fixed size for the popup #[must_use] pub fn fixed_size(mut self, w: f32, h: f32) -> Self { self.size = PopupSize::Fixed { w, h }; self } + /// Uses content-based sizing for the popup #[must_use] pub fn content_size(mut self) -> Self { self.size = PopupSize::Content; self } + /// Enables or disables keyboard/pointer grab for modal behavior #[must_use] pub const fn grab(mut self, enable: bool) -> Self { self.grab = enable; self } + /// Registers a callback that will close the popup when invoked #[must_use] pub fn close_on(mut self, callback_name: impl Into) -> Self { self.close_callback = Some(callback_name.into()); self } + /// Registers a callback that will resize the popup when invoked #[must_use] pub fn resize_on(mut self, callback_name: impl Into) -> Self { self.resize_callback = Some(callback_name.into()); self } + /// Binds the popup to show when the specified Slint callback is triggered pub fn bind(self, trigger_callback: &str) -> Result<()> { let request = self.build_request(); let control = self.shell.control(); @@ -169,6 +194,7 @@ impl<'a> PopupBuilder<'a> { Ok(()) } + /// Binds the popup to toggle visibility when the specified callback is triggered pub fn toggle(self, trigger_callback: &str) -> Result<()> { let request = self.build_request(); let control = self.shell.control(); diff --git a/crates/composition/src/selection.rs b/crates/composition/src/selection.rs index f430465..1df9312 100644 --- a/crates/composition/src/selection.rs +++ b/crates/composition/src/selection.rs @@ -7,8 +7,7 @@ use layer_shika_domain::errors::DomainError; /// A selection of surfaces matching a selector /// -/// Provides methods to interact with all matching surfaces at once, such as -/// setting up callbacks, modifying properties, or accessing component instances. +/// Provides methods to interact with all matching surfaces at once. /// Created via `Shell::select()`. pub struct Selection<'a> { shell: &'a Shell, @@ -20,6 +19,9 @@ impl<'a> Selection<'a> { Self { shell, selector } } + /// Registers a callback handler for all matching surfaces + /// + /// Handler receives a `CallbackContext` with surface identity and shell control. pub fn on_callback(&mut self, callback_name: &str, handler: F) -> &mut Self where F: Fn(crate::CallbackContext) -> R + Clone + 'static, @@ -30,6 +32,7 @@ impl<'a> Selection<'a> { self } + /// Registers a callback handler that receives arguments for all matching surfaces pub fn on_callback_with_args(&mut self, callback_name: &str, handler: F) -> &mut Self where F: Fn(&[Value], crate::CallbackContext) -> R + Clone + 'static, @@ -40,6 +43,7 @@ impl<'a> Selection<'a> { self } + /// Executes a function with each matching component instance pub fn with_component(&self, mut f: F) where F: FnMut(&ComponentInstance), @@ -49,6 +53,7 @@ impl<'a> Selection<'a> { }); } + /// Sets a property value on all matching surfaces pub fn set_property(&self, name: &str, value: &Value) -> Result<(), Error> { let mut result = Ok(()); self.shell.with_selected(&self.selector, |_, component| { @@ -62,6 +67,7 @@ impl<'a> Selection<'a> { result } + /// Gets property values from all matching surfaces pub fn get_property(&self, name: &str) -> Result, Error> { let mut values = Vec::new(); let mut result = Ok(()); @@ -79,6 +85,7 @@ impl<'a> Selection<'a> { result.map(|()| values) } + /// Executes a configuration function with component and surface handle for matching surfaces pub fn configure(&self, mut f: F) where F: FnMut(&ComponentInstance, LayerSurfaceHandle<'_>), @@ -89,14 +96,17 @@ impl<'a> Selection<'a> { }); } + /// Returns the number of surfaces matching the selector pub fn count(&self) -> usize { self.shell.count_selected(&self.selector) } + /// Checks if no surfaces match the selector pub fn is_empty(&self) -> bool { self.count() == 0 } + /// Returns information about all matching surfaces pub fn info(&self) -> Vec { self.shell.get_selected_info(&self.selector) } diff --git a/crates/composition/src/selector.rs b/crates/composition/src/selector.rs index e0a47ff..f0ba95d 100644 --- a/crates/composition/src/selector.rs +++ b/crates/composition/src/selector.rs @@ -13,7 +13,7 @@ pub struct SurfaceInfo { /// Selector for targeting surfaces when setting up callbacks or runtime configuration /// -/// Use `Surface::named()` to target a specific surface, or combine selectors for complex targeting. +/// Combine with `.or()`, `.except()`, or `.on()` for complex targeting. #[derive(Clone)] pub enum Surface { /// Select all surfaces @@ -31,18 +31,22 @@ pub enum Surface { } impl Surface { + /// Selects all surfaces pub fn all() -> Self { Self::All } + /// Selects a surface by exact name pub fn named(name: impl Into) -> Self { Self::Named(name.into()) } + /// Selects surfaces matching any of the given names pub fn any(names: impl IntoIterator>) -> Self { Self::Any(names.into_iter().map(Into::into).collect()) } + /// Selects surfaces matching a custom predicate pub fn matching(predicate: F) -> Self where F: Fn(&SurfaceInfo) -> bool + Send + Sync + 'static, @@ -50,6 +54,7 @@ impl Surface { Self::Filter(Arc::new(predicate)) } + /// Combines this surface selector with an output selector pub fn on(self, output: Output) -> Selector { Selector { surface: self, @@ -57,11 +62,13 @@ impl Surface { } } + /// Inverts the selection to exclude matching surfaces #[must_use] pub fn except(self, other: impl Into) -> Self { Self::Not(Box::new(other.into())) } + /// Combines this selector with another using OR logic #[must_use] pub fn or(self, other: impl Into) -> Self { match self { @@ -120,26 +127,32 @@ pub enum Output { } impl Output { + /// Selects all outputs pub fn all() -> Self { Self::All } + /// Selects the primary output pub fn primary() -> Self { Self::Primary } + /// Selects the currently active output pub fn active() -> Self { Self::Active } + /// Selects an output by handle pub fn handle(handle: OutputHandle) -> Self { Self::Handle(handle) } + /// Selects an output by name pub fn named(name: impl Into) -> Self { Self::Named(name.into()) } + /// Selects outputs matching a custom predicate pub fn matching(predicate: F) -> Self where F: Fn(&OutputInfo) -> bool + Send + Sync + 'static, @@ -147,11 +160,13 @@ impl Output { Self::Filter(Arc::new(predicate)) } + /// Inverts the selection to exclude matching outputs #[must_use] pub fn except(self, other: impl Into) -> Self { Self::Not(Box::new(other.into())) } + /// Combines this selector with another using OR logic #[must_use] pub fn or(self, other: impl Into) -> Self { match self { @@ -202,8 +217,7 @@ impl Debug for Output { /// Combined surface and output selector for precise targeting /// -/// Combines a surface selector with an output selector to target specific -/// surface instances on specific outputs. +/// Targets specific surface instances on specific outputs. #[derive(Clone, Debug)] pub struct Selector { pub surface: Surface, @@ -211,6 +225,7 @@ pub struct Selector { } impl Selector { + /// Creates a selector matching all surfaces on all outputs pub fn all() -> Self { Self { surface: Surface::All, diff --git a/crates/composition/src/shell.rs b/crates/composition/src/shell.rs index f404f1c..194c6b0 100644 --- a/crates/composition/src/shell.rs +++ b/crates/composition/src/shell.rs @@ -44,14 +44,15 @@ enum CompilationSource { /// Builder for configuring and creating a Shell with one or more surfaces /// -/// Created via `Shell::from_file()`, `Shell::from_source()`, or `Shell::from_compilation()`. /// Chain `.surface()` calls to configure multiple surfaces, then call `.build()` or `.run()`. +/// If no surfaces are configured, a default "Main" surface is created. pub struct ShellBuilder { compilation: CompilationSource, surfaces: Vec, } impl ShellBuilder { + /// Starts configuration for a new surface with the given component name pub fn surface(self, component: impl Into) -> SurfaceConfigBuilder { SurfaceConfigBuilder { shell_builder: self, @@ -60,6 +61,7 @@ impl ShellBuilder { } } + /// Discovers and registers multiple surfaces by component names #[must_use] pub fn discover_surfaces( mut self, @@ -74,6 +76,7 @@ impl ShellBuilder { self } + /// Builds the shell from the configured surfaces pub fn build(self) -> Result { let surfaces = if self.surfaces.is_empty() { vec![SurfaceDefinition { @@ -127,9 +130,8 @@ impl ShellBuilder { /// Builder for configuring a single surface within a Shell /// -/// Created by calling `.surface()` on `ShellBuilder`. Chain configuration methods -/// like `.height()`, `.anchor()`, `.exclusive_zone()`, then either start a new surface -/// with `.surface()` or finalize with `.build()` or `.run()`. +/// Chain configuration methods, then either start a new surface with `.surface()` +/// or finalize with `.build()` or `.run()`. pub struct SurfaceConfigBuilder { shell_builder: ShellBuilder, component: String, @@ -137,82 +139,101 @@ pub struct SurfaceConfigBuilder { } impl SurfaceConfigBuilder { + /// Sets both width and height for the surface #[must_use] pub fn size(mut self, width: u32, height: u32) -> Self { self.config.dimensions = SurfaceDimension::new(width, height); self } + /// Sets the height of the surface #[must_use] pub fn height(mut self, height: u32) -> Self { self.config.dimensions = SurfaceDimension::new(self.config.dimensions.width(), height); self } + /// Sets the width of the surface #[must_use] pub fn width(mut self, width: u32) -> Self { self.config.dimensions = SurfaceDimension::new(width, self.config.dimensions.height()); self } + /// Sets the layer (stacking order) for the surface #[must_use] pub const fn layer(mut self, layer: Layer) -> Self { self.config.layer = layer; self } + /// Sets the margins around the surface #[must_use] pub fn margin(mut self, margin: impl Into) -> Self { self.config.margin = margin.into(); self } + /// Sets the anchor edges for positioning #[must_use] pub const fn anchor(mut self, anchor: AnchorEdges) -> Self { self.config.anchor = anchor; self } + /// Sets the exclusive zone in pixels + /// + /// Reserves screen space that other windows avoid. Positive values reserve from anchored edge, + /// `0` means no reservation, `-1` lets compositor decide. #[must_use] pub const fn exclusive_zone(mut self, zone: i32) -> Self { self.config.exclusive_zone = zone; self } + /// Sets the namespace identifier for the surface #[must_use] pub fn namespace(mut self, namespace: impl Into) -> Self { self.config.namespace = namespace.into(); self } + /// Sets the scale factor for the surface #[must_use] pub fn scale_factor(mut self, sf: impl TryInto) -> Self { self.config.scale_factor = sf.try_into().unwrap_or_default(); self } + /// Sets the keyboard interactivity mode #[must_use] pub const fn keyboard_interactivity(mut self, mode: KeyboardInteractivity) -> Self { self.config.keyboard_interactivity = mode; self } + /// Sets the output policy for multi-monitor configuration + /// + /// Controls which monitors display this surface. Default is `OutputPolicy::All`. #[must_use] pub fn output_policy(mut self, policy: OutputPolicy) -> Self { self.config.output_policy = policy; self } + /// Starts configuration for another surface #[must_use] pub fn surface(self, component: impl Into) -> SurfaceConfigBuilder { let shell_builder = self.complete(); shell_builder.surface(component) } + /// Builds the shell with all configured surfaces pub fn build(self) -> Result { self.complete().build() } + /// Builds and runs the shell pub fn run(self) -> Result<()> { let mut shell = self.build()?; shell.run() @@ -232,8 +253,10 @@ type OutputDisconnectedHandler = Box; /// Main runtime for managing Wayland layer-shell surfaces with Slint UI /// -/// Manages the lifecycle of one or more layer surfaces, event loop integration, -/// and Slint component instantiation. Create via builder methods or `from_config()`. +/// Manages surface lifecycle, event loop integration, and component instantiation. +/// Supports multiple surfaces across monitors, dynamic spawning, and popup windows. +/// +/// Create via `Shell::from_file()`, `from_source()`, or `from_compilation()`. pub struct Shell { inner: Rc>, registry: SurfaceRegistry, @@ -244,6 +267,7 @@ pub struct Shell { } impl Shell { + /// Creates a shell builder from a Slint file path pub fn from_file(path: impl AsRef) -> ShellBuilder { ShellBuilder { compilation: CompilationSource::File { @@ -254,6 +278,9 @@ impl Shell { } } + /// Creates a shell builder from a Slint file path with a custom compiler + /// + /// Useful for configuring include paths, style overrides, or compilation settings. pub fn from_file_with_compiler(path: impl AsRef, compiler: Compiler) -> ShellBuilder { ShellBuilder { compilation: CompilationSource::File { @@ -264,6 +291,7 @@ impl Shell { } } + /// Creates a shell builder from Slint source code pub fn from_source(code: impl Into) -> ShellBuilder { ShellBuilder { compilation: CompilationSource::Source { @@ -274,6 +302,7 @@ impl Shell { } } + /// Creates a shell builder from Slint source code with a custom compiler pub fn from_source_with_compiler(code: impl Into, compiler: Compiler) -> ShellBuilder { ShellBuilder { compilation: CompilationSource::Source { @@ -284,6 +313,7 @@ impl Shell { } } + /// Creates a shell builder from a pre-compiled Slint compilation result pub fn from_compilation(result: Rc) -> ShellBuilder { ShellBuilder { compilation: CompilationSource::Compiled(result), @@ -291,6 +321,7 @@ impl Shell { } } + /// Creates an empty shell builder for manual configuration pub fn builder() -> ShellBuilder { ShellBuilder { compilation: CompilationSource::Source { @@ -301,6 +332,7 @@ impl Shell { } } + /// Compiles a Slint file and returns the compilation result pub fn compile_file(path: impl AsRef) -> Result> { let compiler = Compiler::default(); let result = spin_on(compiler.build_from_path(path.as_ref())); @@ -319,6 +351,7 @@ impl Shell { Ok(Rc::new(result)) } + /// Compiles Slint source code and returns the compilation result pub fn compile_source(code: impl Into) -> Result> { let compiler = Compiler::default(); let result = spin_on(compiler.build_from_source(code.into(), PathBuf::default())); @@ -333,6 +366,7 @@ impl Shell { Ok(Rc::new(result)) } + /// Creates a shell from a complete configuration object pub fn from_config(config: ShellConfig) -> Result { let compilation_result = match config.ui_source { CompiledUiSource::File(path) => Self::compile_file(&path)?, @@ -725,23 +759,28 @@ impl Shell { } } + /// Returns a control handle for sending commands to the shell #[must_use] pub fn control(&self) -> ShellControl { ShellControl::new(self.command_sender.clone()) } + /// Returns the names of all registered surfaces pub fn surface_names(&self) -> Vec<&str> { self.registry.surface_names() } + /// Checks if a surface with the given name exists pub fn has_surface(&self, name: &str) -> bool { self.registry.contains_name(name) } + /// Returns a handle to the event loop for registering custom event sources pub fn event_loop_handle(&self) -> EventLoopHandle { EventLoopHandle::new(Rc::downgrade(&self.inner)) } + /// Starts the event loop and runs the shell until exit pub fn run(&mut self) -> Result<()> { log::info!( "Starting Shell event loop with {} windows", @@ -751,6 +790,9 @@ impl Shell { Ok(()) } + /// Spawns a new surface at runtime from the given definition + /// + /// The surface is instantiated on outputs according to its `OutputPolicy`. pub fn spawn_surface(&mut self, definition: SurfaceDefinition) -> Result> { let component_definition = self .compilation_result @@ -794,6 +836,7 @@ impl Shell { Ok(vec![surface_handle]) } + /// Removes and destroys a surface by its handle pub fn despawn_surface(&mut self, handle: SurfaceHandle) -> Result<()> { let entry = self.registry.remove(handle).ok_or_else(|| { Error::Domain(DomainError::Configuration { @@ -813,6 +856,9 @@ impl Shell { Ok(()) } + /// Registers a handler called when a new output (monitor) is connected + /// + /// Surfaces with `OutputPolicy::All` spawn automatically on new outputs. pub fn on_output_connected(&mut self, handler: F) -> Result<()> where F: Fn(&OutputInfo) + 'static, @@ -823,6 +869,7 @@ impl Shell { Ok(()) } + /// Registers a handler called when an output is disconnected pub fn on_output_disconnected(&mut self, handler: F) -> Result<()> where F: Fn(OutputHandle) + 'static, @@ -833,14 +880,17 @@ impl Shell { Ok(()) } + /// Returns the handle for a surface by name pub fn get_surface_handle(&self, name: &str) -> Option { self.registry.handle_by_name(name) } + /// Returns the name of a surface by its handle pub fn get_surface_name(&self, handle: SurfaceHandle) -> Option<&str> { self.registry.name_by_handle(handle) } + /// Executes a function with access to a surface component instance by name pub fn with_surface(&self, name: &str, f: F) -> Result where F: FnOnce(&ComponentInstance) -> R, @@ -865,6 +915,7 @@ impl Shell { }) } + /// Executes a function with each surface name and component instance pub fn with_all_surfaces(&self, mut f: F) where F: FnMut(&str, &ComponentInstance), @@ -878,6 +929,7 @@ impl Shell { } } + /// Executes a function with access to a surface on a specific output pub fn with_output(&self, handle: OutputHandle, f: F) -> Result where F: FnOnce(&ComponentInstance) -> R, @@ -894,6 +946,7 @@ impl Shell { Ok(f(window.component_instance())) } + /// Executes a function with each output handle and component instance pub fn with_all_outputs(&self, mut f: F) where F: FnMut(OutputHandle, &ComponentInstance), @@ -904,31 +957,37 @@ impl Shell { } } + /// Returns the Slint compilation result used by this shell #[must_use] pub fn compilation_result(&self) -> &Rc { &self.compilation_result } + /// Creates a popup builder for showing a popup window #[must_use] pub fn popup(&self, component_name: impl Into) -> PopupBuilder<'_> { PopupBuilder::new(self, component_name.into()) } + /// Returns the registry of all connected outputs pub fn output_registry(&self) -> OutputRegistry { let system = self.inner.borrow(); system.app_state().output_registry().clone() } + /// Returns information about a specific output by handle pub fn get_output_info(&self, handle: OutputHandle) -> Option { let system = self.inner.borrow(); system.app_state().get_output_info(handle).cloned() } + /// Returns information about all connected outputs pub fn all_output_info(&self) -> Vec { let system = self.inner.borrow(); system.app_state().all_output_info().cloned().collect() } + /// Creates a selection for targeting specific surfaces by criteria pub fn select(&self, selector: impl Into) -> crate::Selection<'_> { crate::Selection::new(self, selector.into()) } @@ -1216,6 +1275,7 @@ impl<'a> FromAppState<'a> for ShellEventContext<'a> { } impl ShellEventContext<'_> { + /// Returns the component instance for a surface by name pub fn get_surface_component(&self, name: &str) -> Option<&ComponentInstance> { self.app_state .surfaces_by_name(name) @@ -1223,12 +1283,14 @@ impl ShellEventContext<'_> { .map(|s| s.component_instance()) } + /// Returns all surface component instances pub fn all_surface_components(&self) -> impl Iterator { self.app_state .all_outputs() .map(SurfaceState::component_instance) } + /// Renders a new frame for all dirty surfaces pub fn render_frame_if_dirty(&mut self) -> Result<()> { for surface in self.app_state.all_outputs() { surface.render_frame_if_dirty()?; @@ -1236,46 +1298,55 @@ impl ShellEventContext<'_> { Ok(()) } + /// Returns the primary output handle #[must_use] pub fn primary_output_handle(&self) -> Option { self.app_state.primary_output_handle() } + /// Returns the active output handle #[must_use] pub fn active_output_handle(&self) -> Option { self.app_state.active_output_handle() } + /// Returns the output registry pub fn output_registry(&self) -> &OutputRegistry { self.app_state.output_registry() } + /// Returns all outputs with their handles and component instances pub fn outputs(&self) -> impl Iterator { self.app_state .outputs_with_handles() .map(|(handle, surface)| (handle, surface.component_instance())) } + /// Returns the component instance for a specific output pub fn get_output_component(&self, handle: OutputHandle) -> Option<&ComponentInstance> { self.app_state .get_output_by_handle(handle) .map(SurfaceState::component_instance) } + /// Returns information about a specific output pub fn get_output_info(&self, handle: OutputHandle) -> Option<&OutputInfo> { self.app_state.get_output_info(handle) } + /// Returns information about all outputs pub fn all_output_info(&self) -> impl Iterator { self.app_state.all_output_info() } + /// Returns all outputs with their info and component instances pub fn outputs_with_info(&self) -> impl Iterator { self.app_state .outputs_with_info() .map(|(info, surface)| (info, surface.component_instance())) } + /// Returns the compilation result if available #[must_use] pub fn compilation_result(&self) -> Option> { self.app_state diff --git a/crates/composition/src/shell_config.rs b/crates/composition/src/shell_config.rs index 974669e..b2ff2c7 100644 --- a/crates/composition/src/shell_config.rs +++ b/crates/composition/src/shell_config.rs @@ -64,8 +64,7 @@ impl From for CompiledUiSource { /// Declarative configuration for creating a shell with multiple surfaces /// -/// Use this for programmatic or externally-driven configuration. -/// For fluent builder API, use `Shell::from_file()` instead. +/// Useful for loading configuration from files or programmatic generation. pub struct ShellConfig { pub ui_source: CompiledUiSource, pub surfaces: Vec, @@ -81,6 +80,7 @@ pub struct SurfaceComponentConfig { } impl ShellConfig { + /// Creates a new shell configuration from a UI source pub fn new(ui_source: impl Into) -> Self { Self { ui_source: ui_source.into(), @@ -88,6 +88,7 @@ impl ShellConfig { } } + /// Adds a surface with the given component name #[must_use] pub fn with_surface(mut self, component: impl Into) -> Self { self.surfaces.push(SurfaceComponentConfig { @@ -97,6 +98,7 @@ impl ShellConfig { self } + /// Adds a surface with a complete configuration #[must_use] pub fn with_surface_config( mut self, @@ -110,6 +112,7 @@ impl ShellConfig { self } + /// Adds a surface and returns a mutable reference to it pub fn add_surface(&mut self, component: impl Into) -> &mut SurfaceComponentConfig { self.surfaces.push(SurfaceComponentConfig { component: component.into(), @@ -120,6 +123,7 @@ impl ShellConfig { .unwrap_or_else(|| unreachable!("just pushed")) } + /// Adds a surface with configuration and returns a mutable reference to it pub fn add_surface_config( &mut self, component: impl Into, diff --git a/crates/composition/src/surface_registry.rs b/crates/composition/src/surface_registry.rs index 1dc814a..1176377 100644 --- a/crates/composition/src/surface_registry.rs +++ b/crates/composition/src/surface_registry.rs @@ -6,18 +6,28 @@ use layer_shika_domain::value_objects::output_handle::OutputHandle; use std::collections::HashMap; use std::rc::Rc; +/// Definition of a surface including component name and configuration +/// +/// Pairs a Slint component with its layer-shell settings. #[derive(Debug, Clone)] pub struct SurfaceDefinition { pub component: String, pub config: SurfaceConfig, } +/// Metadata tracked for each registered surface +/// +/// Includes spawn order for deterministic iteration and creation timestamps. #[derive(Clone, Default)] pub struct SurfaceMetadata { pub spawn_order: usize, pub creation_timestamp: u64, } +/// Registry entry for a surface with handle, name, and output instances +/// +/// Tracks all instances of a surface across multiple outputs and maintains +/// the component definition and metadata. pub struct SurfaceEntry { pub handle: SurfaceHandle, pub name: String, @@ -28,6 +38,7 @@ pub struct SurfaceEntry { } impl SurfaceEntry { + /// Creates a new surface entry pub fn new(handle: SurfaceHandle, name: String, definition: SurfaceDefinition) -> Self { let component = definition.component.clone(); Self { @@ -40,10 +51,12 @@ impl SurfaceEntry { } } + /// Adds a component instance for a specific output pub fn add_output_instance(&mut self, output: OutputHandle, instance: Rc) { self.output_instances.insert(output, instance); } + /// Removes and returns a component instance for a specific output pub fn remove_output_instance( &mut self, output: OutputHandle, @@ -51,15 +64,20 @@ impl SurfaceEntry { self.output_instances.remove(&output) } + /// Returns a component instance for a specific output pub fn get_output_instance(&self, output: OutputHandle) -> Option<&Rc> { self.output_instances.get(&output) } + /// Returns all output handles for this surface pub fn outputs(&self) -> Vec { self.output_instances.keys().copied().collect() } } +/// Central registry for managing surface entries and lookups +/// +/// Maintains indices for efficient lookup by handle, name, or component. pub struct SurfaceRegistry { entries: HashMap, by_name: HashMap>, @@ -68,6 +86,7 @@ pub struct SurfaceRegistry { } impl SurfaceRegistry { + /// Creates a new empty surface registry pub fn new() -> Self { Self { entries: HashMap::new(), @@ -77,6 +96,7 @@ impl SurfaceRegistry { } } + /// Inserts a new surface entry into the registry pub fn insert(&mut self, mut entry: SurfaceEntry) -> Result<()> { entry.metadata.spawn_order = self.next_spawn_order; self.next_spawn_order += 1; @@ -94,6 +114,7 @@ impl SurfaceRegistry { Ok(()) } + /// Removes and returns a surface entry by handle pub fn remove(&mut self, handle: SurfaceHandle) -> Option { let entry = self.entries.remove(&handle)?; @@ -114,22 +135,27 @@ impl SurfaceRegistry { Some(entry) } + /// Returns a reference to a surface entry by handle pub fn get(&self, handle: SurfaceHandle) -> Option<&SurfaceEntry> { self.entries.get(&handle) } + /// Alias for `get` pub fn by_handle(&self, handle: SurfaceHandle) -> Option<&SurfaceEntry> { self.entries.get(&handle) } + /// Returns a mutable reference to a surface entry by handle pub fn get_mut(&mut self, handle: SurfaceHandle) -> Option<&mut SurfaceEntry> { self.entries.get_mut(&handle) } + /// Alias for `get_mut` pub fn by_handle_mut(&mut self, handle: SurfaceHandle) -> Option<&mut SurfaceEntry> { self.entries.get_mut(&handle) } + /// Returns all surface entries with the given name pub fn by_name(&self, name: &str) -> Vec<&SurfaceEntry> { self.by_name .get(name) @@ -137,6 +163,7 @@ impl SurfaceRegistry { .unwrap_or_default() } + /// Returns mutable references to all surface entries with the given name pub fn by_name_mut(&mut self, name: &str) -> Vec<&mut SurfaceEntry> { let handles: Vec = self.by_name.get(name).cloned().unwrap_or_default(); @@ -148,20 +175,24 @@ impl SurfaceRegistry { .collect() } + /// Returns the first surface handle with the given name pub fn handle_by_name(&self, name: &str) -> Option { self.by_name .get(name) .and_then(|handles| handles.first().copied()) } + /// Returns all surface handles with the given name pub fn handles_by_name(&self, name: &str) -> Vec { self.by_name.get(name).cloned().unwrap_or_default() } + /// Returns the name for a surface handle pub fn name_by_handle(&self, handle: SurfaceHandle) -> Option<&str> { self.entries.get(&handle).map(|e| e.name.as_str()) } + /// Returns all surface entries for the given component pub fn by_component(&self, component: &str) -> Vec<&SurfaceEntry> { self.by_component .get(component) @@ -169,18 +200,22 @@ impl SurfaceRegistry { .unwrap_or_default() } + /// Returns an iterator over all surface entries pub fn all(&self) -> impl Iterator { self.entries.values() } + /// Returns an iterator over all mutable surface entries pub fn all_mut(&mut self) -> impl Iterator { self.entries.values_mut() } + /// Returns an iterator over all surface handles pub fn handles(&self) -> impl Iterator + '_ { self.entries.keys().copied() } + /// Returns all output handles for a surface pub fn outputs_for_surface(&self, handle: SurfaceHandle) -> Vec { self.entries .get(&handle) @@ -188,26 +223,32 @@ impl SurfaceRegistry { .unwrap_or_default() } + /// Returns all surface names in the registry pub fn surface_names(&self) -> Vec<&str> { self.by_name.keys().map(String::as_str).collect() } + /// Returns all component names in the registry pub fn component_names(&self) -> Vec<&str> { self.by_component.keys().map(String::as_str).collect() } + /// Returns the number of surfaces in the registry pub fn len(&self) -> usize { self.entries.len() } + /// Checks if the registry is empty pub fn is_empty(&self) -> bool { self.entries.is_empty() } + /// Checks if a surface handle exists in the registry pub fn contains(&self, handle: SurfaceHandle) -> bool { self.entries.contains_key(&handle) } + /// Checks if a surface name exists in the registry pub fn contains_name(&self, name: &str) -> bool { self.by_name.contains_key(name) } diff --git a/crates/composition/src/system.rs b/crates/composition/src/system.rs index 15d42fb..d4217b9 100644 --- a/crates/composition/src/system.rs +++ b/crates/composition/src/system.rs @@ -89,6 +89,9 @@ pub enum ShellCommand { Render, } +/// Context provided to callback handlers with surface and control information +/// +/// Provides surface identity, output info, and control handle for runtime operations. pub struct CallbackContext { instance_id: SurfaceInstanceId, surface_name: String, @@ -108,38 +111,47 @@ impl CallbackContext { } } + /// Returns the surface instance identifier pub const fn instance_id(&self) -> &SurfaceInstanceId { &self.instance_id } + /// Returns the surface handle pub const fn surface_handle(&self) -> SurfaceHandle { self.instance_id.surface() } + /// Returns the output handle pub const fn output_handle(&self) -> OutputHandle { self.instance_id.output() } + /// Returns the surface name pub fn surface_name(&self) -> &str { &self.surface_name } + /// Returns a reference to the shell control handle pub const fn control(&self) -> &ShellControl { &self.control } + /// Returns a control handle for this specific surface instance pub fn this_instance(&self) -> SurfaceControlHandle { self.control.surface_instance(&self.instance_id) } + /// Returns a control handle for all instances of this surface pub fn all_surface_instances(&self) -> SurfaceControlHandle { self.control.surface_by_handle(self.surface_handle()) } + /// Returns a control handle for all surfaces with this name pub fn all_named(&self) -> SurfaceControlHandle { self.control.surface_by_name(&self.surface_name) } + /// Returns a control handle for all surfaces with this name on the current output pub fn all_named_on_this_output(&self) -> SurfaceControlHandle { self.control .surface_by_name_and_output(&self.surface_name, self.output_handle()) @@ -148,8 +160,7 @@ impl CallbackContext { /// Handle for runtime control of shell operations /// -/// Provides methods to manipulate surfaces, show popups, and request redraws. -/// Obtained from callbacks via the control parameter. +/// Cloneable and can be sent across threads for triggering shell operations. #[derive(Clone)] pub struct ShellControl { sender: channel::Sender, @@ -160,6 +171,7 @@ impl ShellControl { Self { sender } } + /// Shows a popup from a popup request pub fn show_popup(&self, request: &PopupRequest) -> Result<()> { self.sender .send(ShellCommand::Popup(PopupCommand::Show(request.clone()))) @@ -170,6 +182,7 @@ impl ShellControl { }) } + /// Shows a popup at the current cursor position pub fn show_popup_at_cursor(&self, component: impl Into) -> Result<()> { let request = PopupRequest::builder(component.into()) .placement(PopupPlacement::AtCursor) @@ -177,6 +190,7 @@ impl ShellControl { self.show_popup(&request) } + /// Shows a popup centered on screen pub fn show_popup_centered(&self, component: impl Into) -> Result<()> { let request = PopupRequest::builder(component.into()) .placement(PopupPlacement::AtCursor) @@ -185,6 +199,7 @@ impl ShellControl { self.show_popup(&request) } + /// Shows a popup at the specified position pub fn show_popup_at_position( &self, component: impl Into, @@ -197,6 +212,7 @@ impl ShellControl { self.show_popup(&request) } + /// Closes a popup by its handle pub fn close_popup(&self, handle: PopupHandle) -> Result<()> { self.sender .send(ShellCommand::Popup(PopupCommand::Close(handle))) @@ -207,6 +223,7 @@ impl ShellControl { }) } + /// Resizes a popup to the specified dimensions pub fn resize_popup(&self, handle: PopupHandle, width: f32, height: f32) -> Result<()> { self.sender .send(ShellCommand::Popup(PopupCommand::Resize { @@ -221,6 +238,7 @@ impl ShellControl { }) } + /// Requests a redraw of all surfaces pub fn request_redraw(&self) -> Result<()> { self.sender.send(ShellCommand::Render).map_err(|_| { Error::Domain(DomainError::Configuration { @@ -229,6 +247,7 @@ impl ShellControl { }) } + /// Returns a control handle for a specific surface instance pub fn surface_instance(&self, id: &SurfaceInstanceId) -> SurfaceControlHandle { SurfaceControlHandle { target: SurfaceTarget::ByInstance(*id), @@ -236,6 +255,7 @@ impl ShellControl { } } + /// Returns a control handle for all instances of a surface by handle pub fn surface_by_handle(&self, handle: SurfaceHandle) -> SurfaceControlHandle { SurfaceControlHandle { target: SurfaceTarget::ByHandle(handle), @@ -243,6 +263,7 @@ impl ShellControl { } } + /// Returns a control handle for all surfaces with the given name pub fn surface_by_name(&self, name: impl Into) -> SurfaceControlHandle { SurfaceControlHandle { target: SurfaceTarget::ByName(name.into()), @@ -250,6 +271,7 @@ impl ShellControl { } } + /// Returns a control handle for surfaces with the given name on a specific output pub fn surface_by_name_and_output( &self, name: impl Into, @@ -264,6 +286,7 @@ impl ShellControl { } } + /// Alias for `surface_by_name` pub fn surface(&self, name: impl Into) -> SurfaceControlHandle { self.surface_by_name(name) } @@ -271,7 +294,7 @@ impl ShellControl { /// Handle for runtime control of a specific surface /// -/// Allows modifying surface properties like size, anchor, layer, and margins at runtime. +/// Operations apply to all matching instances. Changes are queued and applied asynchronously. /// Obtained via `ShellControl::surface()`. pub struct SurfaceControlHandle { target: SurfaceTarget, @@ -279,6 +302,7 @@ pub struct SurfaceControlHandle { } impl SurfaceControlHandle { + /// Resizes the surface to the specified dimensions pub fn resize(&self, width: u32, height: u32) -> Result<()> { self.sender .send(ShellCommand::Surface(SurfaceCommand::Resize { @@ -293,14 +317,17 @@ impl SurfaceControlHandle { }) } + /// Sets the surface width pub fn set_width(&self, width: u32) -> Result<()> { self.resize(width, 0) } + /// Sets the surface height pub fn set_height(&self, height: u32) -> Result<()> { self.resize(0, height) } + /// Sets the anchor edges for the surface pub fn set_anchor(&self, anchor: AnchorEdges) -> Result<()> { self.sender .send(ShellCommand::Surface(SurfaceCommand::SetAnchor { @@ -315,6 +342,7 @@ impl SurfaceControlHandle { }) } + /// Sets the exclusive zone for the surface pub fn set_exclusive_zone(&self, zone: i32) -> Result<()> { self.sender .send(ShellCommand::Surface(SurfaceCommand::SetExclusiveZone { @@ -329,6 +357,7 @@ impl SurfaceControlHandle { }) } + /// Sets the margins for the surface pub fn set_margins(&self, margins: impl Into) -> Result<()> { self.sender .send(ShellCommand::Surface(SurfaceCommand::SetMargins { @@ -343,6 +372,7 @@ impl SurfaceControlHandle { }) } + /// Sets the layer for the surface pub fn set_layer(&self, layer: Layer) -> Result<()> { self.sender .send(ShellCommand::Surface(SurfaceCommand::SetLayer { @@ -356,6 +386,7 @@ impl SurfaceControlHandle { }) } + /// Sets the output policy for the surface pub fn set_output_policy(&self, policy: OutputPolicy) -> Result<()> { self.sender .send(ShellCommand::Surface(SurfaceCommand::SetOutputPolicy { @@ -370,6 +401,7 @@ impl SurfaceControlHandle { }) } + /// Sets the scale factor for the surface pub fn set_scale_factor(&self, factor: ScaleFactor) -> Result<()> { self.sender .send(ShellCommand::Surface(SurfaceCommand::SetScaleFactor { @@ -384,6 +416,7 @@ impl SurfaceControlHandle { }) } + /// Sets the keyboard interactivity mode for the surface pub fn set_keyboard_interactivity(&self, mode: KeyboardInteractivity) -> Result<()> { self.sender .send(ShellCommand::Surface( @@ -401,6 +434,7 @@ impl SurfaceControlHandle { }) } + /// Applies a complete surface configuration pub fn apply_config(&self, config: SurfaceConfig) -> Result<()> { self.sender .send(ShellCommand::Surface(SurfaceCommand::ApplyConfig { @@ -415,6 +449,7 @@ impl SurfaceControlHandle { }) } + /// Returns a builder for configuring multiple properties at once pub fn configure(self) -> RuntimeSurfaceConfigBuilder { RuntimeSurfaceConfigBuilder { handle: self, @@ -427,78 +462,93 @@ impl SurfaceControlHandle { /// /// Created via `SurfaceControlHandle::configure()`. Chain configuration methods /// and call `.apply()` to commit all changes atomically. +/// Builder for applying multiple configuration changes to a surface at once +/// +/// All changes are committed together in one compositor round-trip for efficiency. pub struct RuntimeSurfaceConfigBuilder { handle: SurfaceControlHandle, config: SurfaceConfig, } impl RuntimeSurfaceConfigBuilder { + /// Sets the surface size #[must_use] pub fn size(mut self, width: u32, height: u32) -> Self { self.config.dimensions = SurfaceDimension::from_raw(width, height); self } + /// Sets the surface width #[must_use] pub fn width(mut self, width: u32) -> Self { self.config.dimensions = SurfaceDimension::from_raw(width, self.config.dimensions.height()); self } + /// Sets the surface height #[must_use] pub fn height(mut self, height: u32) -> Self { self.config.dimensions = SurfaceDimension::from_raw(self.config.dimensions.width(), height); self } + /// Sets the layer #[must_use] pub const fn layer(mut self, layer: Layer) -> Self { self.config.layer = layer; self } + /// Sets the margins #[must_use] pub fn margins(mut self, margins: impl Into) -> Self { self.config.margin = margins.into(); self } + /// Sets the anchor edges #[must_use] pub const fn anchor(mut self, anchor: AnchorEdges) -> Self { self.config.anchor = anchor; self } + /// Sets the exclusive zone #[must_use] pub const fn exclusive_zone(mut self, zone: i32) -> Self { self.config.exclusive_zone = zone; self } + /// Sets the namespace #[must_use] pub fn namespace(mut self, namespace: impl Into) -> Self { self.config.namespace = namespace.into(); self } + /// Sets the keyboard interactivity mode #[must_use] pub const fn keyboard_interactivity(mut self, mode: KeyboardInteractivity) -> Self { self.config.keyboard_interactivity = mode; self } + /// Sets the output policy #[must_use] pub fn output_policy(mut self, policy: OutputPolicy) -> Self { self.config.output_policy = policy; self } + /// Sets the scale factor #[must_use] pub fn scale_factor(mut self, sf: impl TryInto) -> Self { self.config.scale_factor = sf.try_into().unwrap_or_default(); self } + /// Applies the configured changes to the surface pub fn apply(self) -> Result<()> { self.handle.apply_config(self.config) } @@ -586,6 +636,7 @@ impl EventDispatchContext<'_> { .map(|s| s.component_instance()) } + /// Returns the primary component instance #[must_use] pub fn component_instance(&self) -> Option<&ComponentInstance> { self.app_state @@ -593,46 +644,55 @@ impl EventDispatchContext<'_> { .map(SurfaceState::component_instance) } + /// Returns all component instances across all outputs pub fn all_component_instances(&self) -> impl Iterator { self.app_state .all_outputs() .map(SurfaceState::component_instance) } + /// Returns the output registry pub const fn output_registry(&self) -> &OutputRegistry { self.app_state.output_registry() } + /// Returns the primary output handle #[must_use] pub fn primary_output_handle(&self) -> Option { self.app_state.primary_output_handle() } + /// Returns the active output handle #[must_use] pub fn active_output_handle(&self) -> Option { self.app_state.active_output_handle() } + /// Returns all outputs with their handles and components pub fn outputs(&self) -> impl Iterator { self.app_state .outputs_with_handles() .map(|(handle, surface)| (handle, surface.component_instance())) } + /// Returns the component for a specific output pub fn get_output_component(&self, handle: OutputHandle) -> Option<&ComponentInstance> { self.app_state .get_output_by_handle(handle) .map(SurfaceState::component_instance) } + /// Returns information about a specific output pub fn get_output_info(&self, handle: OutputHandle) -> Option<&OutputInfo> { self.app_state.get_output_info(handle) } + /// Returns information about all outputs pub fn all_output_info(&self) -> impl Iterator { self.app_state.all_output_info() } + /// Returns all outputs with their info and components pub fn outputs_with_info(&self) -> impl Iterator { self.app_state .outputs_with_info() @@ -645,6 +705,7 @@ impl EventDispatchContext<'_> { .or_else(|| self.app_state.primary_output()) } + /// Renders a new frame for all dirty surfaces pub fn render_frame_if_dirty(&mut self) -> Result<()> { for surface in self.app_state.all_outputs() { surface.render_frame_if_dirty()?; @@ -652,6 +713,7 @@ impl EventDispatchContext<'_> { Ok(()) } + /// Returns the compilation result if available #[must_use] pub fn compilation_result(&self) -> Option> { self.app_state @@ -659,6 +721,7 @@ impl EventDispatchContext<'_> { .and_then(SurfaceState::compilation_result) } + /// Shows a popup from a popup request pub fn show_popup( &mut self, req: &PopupRequest, @@ -756,6 +819,7 @@ impl EventDispatchContext<'_> { Ok(popup_handle) } + /// Closes a popup by its handle pub fn close_popup(&mut self, handle: PopupHandle) -> Result<()> { if let Some(active_surface) = self.active_or_primary_output() { if let Some(popup_manager) = active_surface.popup_manager() { @@ -765,6 +829,7 @@ impl EventDispatchContext<'_> { Ok(()) } + /// Closes the currently active popup pub fn close_current_popup(&mut self) -> Result<()> { if let Some(active_surface) = self.active_or_primary_output() { if let Some(popup_manager) = active_surface.popup_manager() { @@ -774,6 +839,7 @@ impl EventDispatchContext<'_> { Ok(()) } + /// Resizes a popup to the specified dimensions pub fn resize_popup(&mut self, handle: PopupHandle, width: f32, height: f32) -> Result<()> { let active_surface = self.active_or_primary_output().ok_or_else(|| { Error::Domain(DomainError::Configuration {