From ebc630b6dc3c9632cc704be54a1a525dff414c91 Mon Sep 17 00:00:00 2001 From: drendog Date: Sun, 7 Dec 2025 01:55:26 +0100 Subject: [PATCH] refactor: unify surface registry --- crates/composition/src/lib.rs | 7 +- crates/composition/src/shell.rs | 72 +++----- crates/composition/src/surface_registry.rs | 198 +++++++++++++++++++++ 3 files changed, 230 insertions(+), 47 deletions(-) create mode 100644 crates/composition/src/surface_registry.rs diff --git a/crates/composition/src/lib.rs b/crates/composition/src/lib.rs index 753f3c1..83dd4a0 100644 --- a/crates/composition/src/lib.rs +++ b/crates/composition/src/lib.rs @@ -6,6 +6,7 @@ mod popup_builder; mod shell; mod shell_config; mod shell_runtime; +mod surface_registry; mod system; pub mod value_conversion; @@ -37,9 +38,11 @@ pub use layer_surface::{LayerSurfaceHandle, ShellSurfaceConfigHandler}; pub use shell::{ DEFAULT_COMPONENT_NAME, Shell, ShellBuilder, ShellEventContext, ShellEventLoopHandle, - SurfaceConfigBuilder, SurfaceDefinition, + SurfaceConfigBuilder, }; +pub use surface_registry::{SurfaceDefinition, SurfaceEntry, SurfaceMetadata, SurfaceRegistry}; + pub use shell_config::{CompiledUiSource, ShellConfig, SurfaceComponentConfig}; pub mod calloop { @@ -71,7 +74,7 @@ pub mod prelude { PopupPositioningMode, PopupRequest, PopupSize, PopupWindow, Result, Shell, ShellBuilder, ShellConfig, ShellControl, ShellEventContext, ShellEventLoopHandle, ShellRuntime, ShellSurfaceConfigHandler, SurfaceComponentConfig, SurfaceConfigBuilder, SurfaceDefinition, - SurfaceHandle, + SurfaceEntry, SurfaceHandle, SurfaceMetadata, SurfaceRegistry, }; pub use crate::calloop::{Generic, Interest, Mode, PostAction, RegistrationToken, Timer}; diff --git a/crates/composition/src/shell.rs b/crates/composition/src/shell.rs index 3df18af..6637eca 100644 --- a/crates/composition/src/shell.rs +++ b/crates/composition/src/shell.rs @@ -3,6 +3,7 @@ use crate::layer_surface::LayerSurfaceHandle; use crate::popup_builder::PopupBuilder; use crate::shell_config::{CompiledUiSource, ShellConfig}; use crate::shell_runtime::ShellRuntime; +use crate::surface_registry::{SurfaceDefinition, SurfaceEntry, SurfaceRegistry}; use crate::system::{PopupCommand, ShellControl}; use crate::value_conversion::IntoValue; use crate::{Error, Result}; @@ -25,18 +26,11 @@ use layer_shika_domain::value_objects::output_handle::OutputHandle; use layer_shika_domain::value_objects::output_info::OutputInfo; use spin_on::spin_on; use std::cell::RefCell; -use std::collections::HashMap; use std::path::{Path, PathBuf}; use std::rc::Rc; pub const DEFAULT_COMPONENT_NAME: &str = "Main"; -#[derive(Debug, Clone)] -pub struct SurfaceDefinition { - pub component: String, - pub config: SurfaceConfig, -} - enum CompilationSource { File { path: PathBuf, compiler: Compiler }, Source { code: String, compiler: Compiler }, @@ -224,8 +218,7 @@ type OutputDisconnectedHandler = Box; pub struct Shell { inner: Rc>, - surfaces: HashMap, - surface_handles: HashMap, + registry: SurfaceRegistry, compilation_result: Rc, popup_command_sender: channel::Sender, output_connected_handlers: Rc>>, @@ -401,16 +394,14 @@ impl Shell { let (sender, receiver) = channel::channel(); - let mut surfaces = HashMap::new(); - let mut surface_handles = HashMap::new(); + let mut registry = SurfaceRegistry::new(); let handle = SurfaceHandle::new(); - surface_handles.insert(handle, definition.component.clone()); - surfaces.insert(definition.component.clone(), definition); + let entry = SurfaceEntry::new(handle, definition.component.clone(), definition); + registry.insert(entry)?; let shell = Self { inner: Rc::clone(&inner_rc), - surfaces, - surface_handles, + registry, compilation_result, popup_command_sender: sender, output_connected_handlers: Rc::new(RefCell::new(Vec::new())), @@ -461,18 +452,16 @@ impl Shell { let (sender, receiver) = channel::channel(); - let mut surfaces = HashMap::new(); - let mut surface_handles = HashMap::new(); + let mut registry = SurfaceRegistry::new(); for definition in definitions { let handle = SurfaceHandle::new(); - surface_handles.insert(handle, definition.component.clone()); - surfaces.insert(definition.component.clone(), definition); + let entry = SurfaceEntry::new(handle, definition.component.clone(), definition); + registry.insert(entry)?; } let shell = Self { inner: Rc::clone(&inner_rc), - surfaces, - surface_handles, + registry, compilation_result, popup_command_sender: sender, output_connected_handlers: Rc::new(RefCell::new(Vec::new())), @@ -539,11 +528,11 @@ impl Shell { } pub fn surface_names(&self) -> Vec<&str> { - self.surfaces.keys().map(String::as_str).collect() + self.registry.surface_names() } pub fn has_surface(&self, name: &str) -> bool { - self.surfaces.contains_key(name) + self.registry.contains_name(name) } pub fn event_loop_handle(&self) -> ShellEventLoopHandle { @@ -553,7 +542,7 @@ impl Shell { pub fn run(&mut self) -> Result<()> { log::info!( "Starting Shell event loop with {} windows", - self.surfaces.len() + self.registry.len() ); self.inner.borrow_mut().run()?; Ok(()) @@ -588,10 +577,8 @@ impl Shell { let handles = system.spawn_surface(&shell_config)?; let surface_handle = SurfaceHandle::new(); - self.surface_handles - .insert(surface_handle, definition.component.clone()); - self.surfaces - .insert(definition.component.clone(), definition); + let entry = SurfaceEntry::new(surface_handle, definition.component.clone(), definition); + self.registry.insert(entry)?; log::info!( "Spawned surface with handle {:?}, created {} output instances", @@ -603,20 +590,18 @@ impl Shell { } pub fn despawn_surface(&mut self, handle: SurfaceHandle) -> Result<()> { - let surface_name = self.surface_handles.remove(&handle).ok_or_else(|| { + let entry = self.registry.remove(handle).ok_or_else(|| { Error::Domain(DomainError::Configuration { message: format!("Surface handle {:?} not found", handle), }) })?; - self.surfaces.remove(&surface_name); - let mut system = self.inner.borrow_mut(); - system.despawn_surface(&surface_name)?; + system.despawn_surface(&entry.name)?; log::info!( "Despawned surface '{}' with handle {:?}", - surface_name, + entry.name, handle ); @@ -644,21 +629,18 @@ impl Shell { } pub fn get_surface_handle(&self, name: &str) -> Option { - self.surface_handles - .iter() - .find(|(_, n)| n.as_str() == name) - .map(|(h, _)| *h) + self.registry.handle_by_name(name) } pub fn get_surface_name(&self, handle: SurfaceHandle) -> Option<&str> { - self.surface_handles.get(&handle).map(String::as_str) + self.registry.name_by_handle(handle) } pub fn with_surface(&self, name: &str, f: F) -> Result where F: FnOnce(&ComponentInstance) -> R, { - if !self.surfaces.contains_key(name) { + if !self.registry.contains_name(name) { return Err(Error::Domain(DomainError::Configuration { message: format!("Window '{}' not found", name), })); @@ -684,7 +666,7 @@ impl Shell { { let system = self.inner.borrow(); - for name in self.surfaces.keys() { + for name in self.registry.surface_names() { for surface in system.app_state().surfaces_by_name(name) { f(name, surface.component_instance()); } @@ -732,7 +714,7 @@ impl Shell { F: Fn(ShellControl) -> R + 'static, R: IntoValue, { - if !self.surfaces.contains_key(surface_name) { + if !self.registry.contains_name(surface_name) { return Err(Error::Domain(DomainError::Configuration { message: format!("Window '{}' not found", surface_name), })); @@ -773,7 +755,7 @@ impl Shell { F: Fn(&[Value], ShellControl) -> R + 'static, R: IntoValue, { - if !self.surfaces.contains_key(surface_name) { + if !self.registry.contains_name(surface_name) { return Err(Error::Domain(DomainError::Configuration { message: format!("Window '{}' not found", surface_name), })); @@ -868,7 +850,7 @@ impl Shell { { let system = self.inner.borrow(); - if self.surfaces.contains_key(surface_name) { + if self.registry.contains_name(surface_name) { for surface in system.app_state().surfaces_by_name(surface_name) { let surface_handle = LayerSurfaceHandle::from_window_state(surface); f(surface.component_instance(), surface_handle); @@ -918,7 +900,7 @@ impl ShellRuntime for Shell { { let system = self.inner.borrow(); - if self.surfaces.contains_key(name) { + if self.registry.contains_name(name) { for surface in system.app_state().surfaces_by_name(name) { f(surface.component_instance()); } @@ -931,7 +913,7 @@ impl ShellRuntime for Shell { { let system = self.inner.borrow(); - for name in self.surfaces.keys() { + for name in self.registry.surface_names() { for surface in system.app_state().surfaces_by_name(name) { f(name, surface.component_instance()); } diff --git a/crates/composition/src/surface_registry.rs b/crates/composition/src/surface_registry.rs new file mode 100644 index 0000000..b752757 --- /dev/null +++ b/crates/composition/src/surface_registry.rs @@ -0,0 +1,198 @@ +use crate::{Error, Result}; +use layer_shika_adapters::platform::slint_interpreter::ComponentInstance; +use layer_shika_domain::config::SurfaceConfig; +use layer_shika_domain::errors::DomainError; +use layer_shika_domain::value_objects::handle::SurfaceHandle; +use layer_shika_domain::value_objects::output_handle::OutputHandle; +use std::collections::HashMap; +use std::rc::Rc; + +#[derive(Debug, Clone)] +pub struct SurfaceDefinition { + pub component: String, + pub config: SurfaceConfig, +} + +#[derive(Clone, Default)] +pub struct SurfaceMetadata { + pub spawn_order: usize, + pub creation_timestamp: u64, +} + +pub struct SurfaceEntry { + pub handle: SurfaceHandle, + pub name: String, + pub component: String, + pub definition: SurfaceDefinition, + pub output_instances: HashMap>, + pub metadata: SurfaceMetadata, +} + +impl SurfaceEntry { + pub fn new(handle: SurfaceHandle, name: String, definition: SurfaceDefinition) -> Self { + let component = definition.component.clone(); + Self { + handle, + name, + component, + definition, + output_instances: HashMap::new(), + metadata: SurfaceMetadata::default(), + } + } + + pub fn add_output_instance(&mut self, output: OutputHandle, instance: Rc) { + self.output_instances.insert(output, instance); + } + + pub fn remove_output_instance( + &mut self, + output: OutputHandle, + ) -> Option> { + self.output_instances.remove(&output) + } + + pub fn get_output_instance(&self, output: OutputHandle) -> Option<&Rc> { + self.output_instances.get(&output) + } + + pub fn outputs(&self) -> Vec { + self.output_instances.keys().copied().collect() + } +} + +pub struct SurfaceRegistry { + entries: HashMap, + by_name: HashMap, + by_component: HashMap>, + next_spawn_order: usize, +} + +impl SurfaceRegistry { + pub fn new() -> Self { + Self { + entries: HashMap::new(), + by_name: HashMap::new(), + by_component: HashMap::new(), + next_spawn_order: 0, + } + } + + pub fn insert(&mut self, mut entry: SurfaceEntry) -> Result<()> { + if self.by_name.contains_key(&entry.name) { + return Err(Error::Domain(DomainError::Configuration { + message: format!("Surface with name '{}' already exists", entry.name), + })); + } + + entry.metadata.spawn_order = self.next_spawn_order; + self.next_spawn_order += 1; + + let handle = entry.handle; + let name = entry.name.clone(); + let component = entry.component.clone(); + + self.by_name.insert(name, handle); + + self.by_component.entry(component).or_default().push(handle); + + self.entries.insert(handle, entry); + + Ok(()) + } + + pub fn remove(&mut self, handle: SurfaceHandle) -> Option { + let entry = self.entries.remove(&handle)?; + + self.by_name.remove(&entry.name); + + if let Some(handles) = self.by_component.get_mut(&entry.component) { + handles.retain(|&h| h != handle); + if handles.is_empty() { + self.by_component.remove(&entry.component); + } + } + + Some(entry) + } + + pub fn get(&self, handle: SurfaceHandle) -> Option<&SurfaceEntry> { + self.entries.get(&handle) + } + + pub fn get_mut(&mut self, handle: SurfaceHandle) -> Option<&mut SurfaceEntry> { + self.entries.get_mut(&handle) + } + + pub fn by_name(&self, name: &str) -> Option<&SurfaceEntry> { + self.by_name.get(name).and_then(|h| self.entries.get(h)) + } + + pub fn by_name_mut(&mut self, name: &str) -> Option<&mut SurfaceEntry> { + self.by_name.get(name).and_then(|h| self.entries.get_mut(h)) + } + + pub fn handle_by_name(&self, name: &str) -> Option { + self.by_name.get(name).copied() + } + + pub fn name_by_handle(&self, handle: SurfaceHandle) -> Option<&str> { + self.entries.get(&handle).map(|e| e.name.as_str()) + } + + pub fn by_component(&self, component: &str) -> Vec<&SurfaceEntry> { + self.by_component + .get(component) + .map(|handles| handles.iter().filter_map(|h| self.entries.get(h)).collect()) + .unwrap_or_default() + } + + pub fn all(&self) -> impl Iterator { + self.entries.values() + } + + pub fn all_mut(&mut self) -> impl Iterator { + self.entries.values_mut() + } + + pub fn handles(&self) -> impl Iterator + '_ { + self.entries.keys().copied() + } + + pub fn outputs_for_surface(&self, handle: SurfaceHandle) -> Vec { + self.entries + .get(&handle) + .map(SurfaceEntry::outputs) + .unwrap_or_default() + } + + pub fn surface_names(&self) -> Vec<&str> { + self.by_name.keys().map(String::as_str).collect() + } + + pub fn component_names(&self) -> Vec<&str> { + self.by_component.keys().map(String::as_str).collect() + } + + pub fn len(&self) -> usize { + self.entries.len() + } + + pub fn is_empty(&self) -> bool { + self.entries.is_empty() + } + + pub fn contains(&self, handle: SurfaceHandle) -> bool { + self.entries.contains_key(&handle) + } + + pub fn contains_name(&self, name: &str) -> bool { + self.by_name.contains_key(name) + } +} + +impl Default for SurfaceRegistry { + fn default() -> Self { + Self::new() + } +}