mirror of
https://codeberg.org/waydeer/layer-shika.git
synced 2025-12-14 10:15:56 +00:00
docs: add more and update docs comments
This commit is contained in:
parent
69a33d8cad
commit
3a9157300e
9 changed files with 267 additions and 20 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue