refactor: unify surface registry

This commit is contained in:
drendog 2025-12-07 01:55:26 +01:00
parent 8e96e49c76
commit ebc630b6dc
Signed by: dwenya
GPG key ID: 8DD77074645332D0
3 changed files with 230 additions and 47 deletions

View file

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

View file

@ -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<dyn Fn(OutputHandle)>;
pub struct Shell {
inner: Rc<RefCell<dyn WaylandSystemOps>>,
surfaces: HashMap<String, SurfaceDefinition>,
surface_handles: HashMap<SurfaceHandle, String>,
registry: SurfaceRegistry,
compilation_result: Rc<CompilationResult>,
popup_command_sender: channel::Sender<PopupCommand>,
output_connected_handlers: Rc<RefCell<Vec<OutputConnectedHandler>>>,
@ -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<SurfaceHandle> {
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<F, R>(&self, name: &str, f: F) -> Result<R>
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());
}

View file

@ -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<OutputHandle, Rc<ComponentInstance>>,
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<ComponentInstance>) {
self.output_instances.insert(output, instance);
}
pub fn remove_output_instance(
&mut self,
output: OutputHandle,
) -> Option<Rc<ComponentInstance>> {
self.output_instances.remove(&output)
}
pub fn get_output_instance(&self, output: OutputHandle) -> Option<&Rc<ComponentInstance>> {
self.output_instances.get(&output)
}
pub fn outputs(&self) -> Vec<OutputHandle> {
self.output_instances.keys().copied().collect()
}
}
pub struct SurfaceRegistry {
entries: HashMap<SurfaceHandle, SurfaceEntry>,
by_name: HashMap<String, SurfaceHandle>,
by_component: HashMap<String, Vec<SurfaceHandle>>,
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<SurfaceEntry> {
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<SurfaceHandle> {
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<Item = &SurfaceEntry> {
self.entries.values()
}
pub fn all_mut(&mut self) -> impl Iterator<Item = &mut SurfaceEntry> {
self.entries.values_mut()
}
pub fn handles(&self) -> impl Iterator<Item = SurfaceHandle> + '_ {
self.entries.keys().copied()
}
pub fn outputs_for_surface(&self, handle: SurfaceHandle) -> Vec<OutputHandle> {
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()
}
}