docs: add more and update docs comments

This commit is contained in:
drendog 2025-12-13 02:34:06 +01:00
parent 69a33d8cad
commit 3a9157300e
Signed by: dwenya
GPG key ID: 8DD77074645332D0
9 changed files with 267 additions and 20 deletions

View file

@ -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<RefCell<dyn WaylandSystemOps>>,
}
@ -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<F>(&self, duration: Duration, mut callback: F) -> Result<RegistrationToken>
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<T, F>(
&self,
mut callback: F,

View file

@ -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();
}

View file

@ -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<String>) -> 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<String>) -> 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();

View file

@ -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<F, R>(&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<F, R>(&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<F>(&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<Vec<Value>, 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<F>(&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<SurfaceInfo> {
self.shell.get_selected_info(&self.selector)
}

View file

@ -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<String>) -> Self {
Self::Named(name.into())
}
/// Selects surfaces matching any of the given names
pub fn any(names: impl IntoIterator<Item = impl Into<String>>) -> Self {
Self::Any(names.into_iter().map(Into::into).collect())
}
/// Selects surfaces matching a custom predicate
pub fn matching<F>(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<Surface>) -> Self {
Self::Not(Box::new(other.into()))
}
/// Combines this selector with another using OR logic
#[must_use]
pub fn or(self, other: impl Into<Surface>) -> 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<String>) -> Self {
Self::Named(name.into())
}
/// Selects outputs matching a custom predicate
pub fn matching<F>(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<Output>) -> Self {
Self::Not(Box::new(other.into()))
}
/// Combines this selector with another using OR logic
#[must_use]
pub fn or(self, other: impl Into<Output>) -> 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,

View file

@ -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<SurfaceDefinition>,
}
impl ShellBuilder {
/// Starts configuration for a new surface with the given component name
pub fn surface(self, component: impl Into<String>) -> 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<Shell> {
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<Margins>) -> 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<String>) -> 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<ScaleFactor, Error = DomainError>) -> 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<String>) -> SurfaceConfigBuilder {
let shell_builder = self.complete();
shell_builder.surface(component)
}
/// Builds the shell with all configured surfaces
pub fn build(self) -> Result<Shell> {
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<dyn Fn(OutputHandle)>;
/// 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<RefCell<dyn WaylandSystemOps>>,
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<Path>) -> 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<Path>, 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<String>) -> 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<String>, 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<CompilationResult>) -> 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<Path>) -> Result<Rc<CompilationResult>> {
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<String>) -> Result<Rc<CompilationResult>> {
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<Self> {
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<Vec<SurfaceHandle>> {
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<F>(&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<F>(&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<SurfaceHandle> {
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<F, R>(&self, name: &str, f: F) -> Result<R>
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<F>(&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<F, R>(&self, handle: OutputHandle, f: F) -> Result<R>
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<F>(&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<CompilationResult> {
&self.compilation_result
}
/// Creates a popup builder for showing a popup window
#[must_use]
pub fn popup(&self, component_name: impl Into<String>) -> 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<OutputInfo> {
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<OutputInfo> {
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::Selector>) -> 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<Item = &ComponentInstance> {
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<OutputHandle> {
self.app_state.primary_output_handle()
}
/// Returns the active output handle
#[must_use]
pub fn active_output_handle(&self) -> Option<OutputHandle> {
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<Item = (OutputHandle, &ComponentInstance)> {
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<Item = &OutputInfo> {
self.app_state.all_output_info()
}
/// Returns all outputs with their info and component instances
pub fn outputs_with_info(&self) -> impl Iterator<Item = (&OutputInfo, &ComponentInstance)> {
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<Rc<CompilationResult>> {
self.app_state

View file

@ -64,8 +64,7 @@ impl From<PathBuf> 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<SurfaceComponentConfig>,
@ -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<CompiledUiSource>) -> 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<String>) -> 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<String>) -> &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<String>,

View file

@ -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<ComponentInstance>) {
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<ComponentInstance>> {
self.output_instances.get(&output)
}
/// Returns all output handles for this surface
pub fn outputs(&self) -> Vec<OutputHandle> {
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<SurfaceHandle, SurfaceEntry>,
by_name: HashMap<String, Vec<SurfaceHandle>>,
@ -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<SurfaceEntry> {
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<SurfaceHandle> = 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<SurfaceHandle> {
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<SurfaceHandle> {
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<Item = &SurfaceEntry> {
self.entries.values()
}
/// Returns an iterator over all mutable surface entries
pub fn all_mut(&mut self) -> impl Iterator<Item = &mut SurfaceEntry> {
self.entries.values_mut()
}
/// Returns an iterator over all surface handles
pub fn handles(&self) -> impl Iterator<Item = SurfaceHandle> + '_ {
self.entries.keys().copied()
}
/// Returns all output handles for a surface
pub fn outputs_for_surface(&self, handle: SurfaceHandle) -> Vec<OutputHandle> {
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)
}

View file

@ -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<ShellCommand>,
@ -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<String>) -> 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<String>) -> 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<String>,
@ -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<String>) -> 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<String>,
@ -264,6 +286,7 @@ impl ShellControl {
}
}
/// Alias for `surface_by_name`
pub fn surface(&self, name: impl Into<String>) -> 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<Margins>) -> 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<Margins>) -> 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<String>) -> 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<ScaleFactor, Error = DomainError>) -> 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<Item = &ComponentInstance> {
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<OutputHandle> {
self.app_state.primary_output_handle()
}
/// Returns the active output handle
#[must_use]
pub fn active_output_handle(&self) -> Option<OutputHandle> {
self.app_state.active_output_handle()
}
/// Returns all outputs with their handles and components
pub fn outputs(&self) -> impl Iterator<Item = (OutputHandle, &ComponentInstance)> {
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<Item = &OutputInfo> {
self.app_state.all_output_info()
}
/// Returns all outputs with their info and components
pub fn outputs_with_info(&self) -> impl Iterator<Item = (&OutputInfo, &ComponentInstance)> {
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<Rc<CompilationResult>> {
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 {