From dc950833ea674d31cf96f45372fcf8060c2aefc5 Mon Sep 17 00:00:00 2001 From: drendog Date: Thu, 11 Dec 2025 03:19:56 +0100 Subject: [PATCH] refactor: migrate to selector system for surface and output --- crates/composition/src/lib.rs | 18 +- crates/composition/src/selection.rs | 96 ++++++ crates/composition/src/selector.rs | 180 +++++++++++ crates/composition/src/shell.rs | 341 +++++++++++--------- examples/declarative-config/src/main.rs | 10 +- examples/multi-surface/src/main.rs | 24 +- examples/runtime-surface-config/src/main.rs | 174 +++++----- src/lib.rs | 7 +- src/prelude.rs | 7 +- src/shell.rs | 7 +- 10 files changed, 589 insertions(+), 275 deletions(-) create mode 100644 crates/composition/src/selection.rs create mode 100644 crates/composition/src/selector.rs diff --git a/crates/composition/src/lib.rs b/crates/composition/src/lib.rs index df8ff46..faa4af6 100644 --- a/crates/composition/src/lib.rs +++ b/crates/composition/src/lib.rs @@ -3,6 +3,8 @@ mod event_loop; mod layer_surface; mod popup_builder; +mod selector; +mod selection; mod shell; mod shell_config; mod shell_runtime; @@ -32,6 +34,8 @@ pub use layer_shika_domain::value_objects::popup_request::{ }; pub use layer_surface::{LayerSurfaceHandle, ShellSurfaceConfigHandler}; pub use popup_builder::PopupBuilder; +pub use selector::{Output, Selector, Surface, SurfaceInfo}; +pub use selection::Selection; pub use shell_runtime::{DEFAULT_SURFACE_NAME, ShellRuntime}; pub use system::{EventDispatchContext, ShellControl, SurfaceControlHandle}; pub use value_conversion::IntoValue; @@ -66,13 +70,13 @@ pub mod prelude { pub use crate::{ AnchorEdges, AnchorStrategy, CompiledUiSource, DEFAULT_COMPONENT_NAME, DEFAULT_SURFACE_NAME, EventDispatchContext, EventLoopHandle, Handle, IntoValue, - KeyboardInteractivity, Layer, LayerSurfaceHandle, OutputGeometry, OutputHandle, OutputInfo, - OutputPolicy, OutputRegistry, PopupBuilder, PopupHandle, PopupPlacement, - PopupPositioningMode, PopupRequest, PopupSize, PopupWindow, Result, Shell, ShellBuilder, - ShellConfig, ShellControl, ShellEventContext, ShellEventLoop, ShellRuntime, - ShellSurfaceConfigHandler, SurfaceComponentConfig, SurfaceConfigBuilder, - SurfaceControlHandle, SurfaceDefinition, SurfaceEntry, SurfaceHandle, SurfaceMetadata, - SurfaceRegistry, + KeyboardInteractivity, Layer, LayerSurfaceHandle, Output, OutputGeometry, OutputHandle, + OutputInfo, OutputPolicy, OutputRegistry, PopupBuilder, PopupHandle, PopupPlacement, + PopupPositioningMode, PopupRequest, PopupSize, PopupWindow, Result, Selection, Selector, + Shell, ShellBuilder, ShellConfig, ShellControl, ShellEventContext, ShellEventLoop, + ShellRuntime, ShellSurfaceConfigHandler, Surface, SurfaceComponentConfig, + SurfaceConfigBuilder, SurfaceControlHandle, SurfaceDefinition, SurfaceEntry, SurfaceHandle, + SurfaceInfo, SurfaceMetadata, SurfaceRegistry, }; pub use crate::calloop::{Generic, Interest, Mode, PostAction, RegistrationToken, Timer}; diff --git a/crates/composition/src/selection.rs b/crates/composition/src/selection.rs new file mode 100644 index 0000000..fc34bf7 --- /dev/null +++ b/crates/composition/src/selection.rs @@ -0,0 +1,96 @@ +use crate::{ + Error, LayerSurfaceHandle, Shell, + selector::{Selector, SurfaceInfo}, + slint_interpreter::{ComponentInstance, Value}, +}; +use layer_shika_domain::errors::DomainError; + +pub struct Selection<'a> { + shell: &'a Shell, + selector: Selector, +} + +impl<'a> Selection<'a> { + pub(crate) fn new(shell: &'a Shell, selector: Selector) -> Self { + Self { shell, selector } + } + + pub fn on_callback(&self, callback_name: &str, handler: F) + where + F: Fn(crate::ShellControl) -> R + Clone + 'static, + R: crate::IntoValue, + { + self.shell + .on_internal(&self.selector, callback_name, handler); + } + + pub fn on_callback_with_args(&self, callback_name: &str, handler: F) + where + F: Fn(&[Value], crate::ShellControl) -> R + Clone + 'static, + R: crate::IntoValue, + { + self.shell + .on_with_args_internal(&self.selector, callback_name, handler); + } + + pub fn with_component(&self, mut f: F) + where + F: FnMut(&ComponentInstance), + { + self.shell.with_selected(&self.selector, |_, component| { + f(component); + }); + } + + pub fn set_property(&self, name: &str, value: &Value) -> Result<(), Error> { + let mut result = Ok(()); + self.shell.with_selected(&self.selector, |_, component| { + if let Err(e) = component.set_property(name, value.clone()) { + log::error!("Failed to set property '{}': {}", name, e); + result = Err(Error::Domain(DomainError::Configuration { + message: format!("Failed to set property '{}': {}", name, e), + })); + } + }); + result + } + + pub fn get_property(&self, name: &str) -> Result, Error> { + let mut values = Vec::new(); + let mut result = Ok(()); + self.shell.with_selected(&self.selector, |_, component| { + match component.get_property(name) { + Ok(value) => values.push(value), + Err(e) => { + log::error!("Failed to get property '{}': {}", name, e); + result = Err(Error::Domain(DomainError::Configuration { + message: format!("Failed to get property '{}': {}", name, e), + })); + } + } + }); + result.map(|()| values) + } + + pub fn configure(&self, mut f: F) + where + F: FnMut(&ComponentInstance, LayerSurfaceHandle<'_>), + { + self.shell + .configure_selected(&self.selector, |component, handle| { + f(component, handle); + }); + } + + pub fn count(&self) -> usize { + self.shell.count_selected(&self.selector) + } + + pub fn is_empty(&self) -> bool { + self.count() == 0 + } + + pub fn info(&self) -> Vec { + self.shell.get_selected_info(&self.selector) + } +} diff --git a/crates/composition/src/selector.rs b/crates/composition/src/selector.rs new file mode 100644 index 0000000..1e00000 --- /dev/null +++ b/crates/composition/src/selector.rs @@ -0,0 +1,180 @@ +use crate::{OutputHandle, OutputInfo}; +use std::fmt::{Debug, Formatter, Result as FmtResult}; +use std::sync::Arc; + +#[derive(Debug, Clone)] +pub struct SurfaceInfo { + pub name: String, + pub output: OutputHandle, +} + +#[derive(Clone)] +pub enum Surface { + All, + Named(String), + Any(Vec), + Filter(Arc bool + Send + Sync>), +} + +impl Surface { + pub fn all() -> Self { + Self::All + } + + pub fn named(name: impl Into) -> Self { + Self::Named(name.into()) + } + + pub fn any(names: impl IntoIterator>) -> Self { + Self::Any(names.into_iter().map(Into::into).collect()) + } + + pub fn matching(predicate: F) -> Self + where + F: Fn(&SurfaceInfo) -> bool + Send + Sync + 'static, + { + Self::Filter(Arc::new(predicate)) + } + + pub fn on(self, output: Output) -> Selector { + Selector { + surface: self, + output, + } + } + + pub(crate) fn matches(&self, info: &SurfaceInfo) -> bool { + match self { + Self::All => true, + Self::Named(name) => &info.name == name, + Self::Any(names) => names.iter().any(|name| name == &info.name), + Self::Filter(predicate) => predicate(info), + } + } +} + +impl Debug for Surface { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match self { + Self::All => write!(f, "Surface::All"), + Self::Named(name) => write!(f, "Surface::Named({:?})", name), + Self::Any(names) => write!(f, "Surface::Any({:?})", names), + Self::Filter(_) => write!(f, "Surface::Filter()"), + } + } +} + +#[derive(Clone)] +pub enum Output { + All, + Primary, + Active, + Handle(OutputHandle), + Named(String), + Filter(Arc bool + Send + Sync>), +} + +impl Output { + pub fn all() -> Self { + Self::All + } + + pub fn primary() -> Self { + Self::Primary + } + + pub fn active() -> Self { + Self::Active + } + + pub fn handle(handle: OutputHandle) -> Self { + Self::Handle(handle) + } + + pub fn named(name: impl Into) -> Self { + Self::Named(name.into()) + } + + pub fn matching(predicate: F) -> Self + where + F: Fn(&OutputInfo) -> bool + Send + Sync + 'static, + { + Self::Filter(Arc::new(predicate)) + } + + pub(crate) fn matches( + &self, + handle: OutputHandle, + info: Option<&OutputInfo>, + primary: Option, + active: Option, + ) -> bool { + match self { + Self::All => true, + Self::Primary => primary == Some(handle), + Self::Active => active == Some(handle), + Self::Handle(h) => *h == handle, + Self::Named(name) => info.is_some_and(|i| i.name() == Some(name.as_str())), + Self::Filter(predicate) => info.is_some_and(|i| predicate(i)), + } + } +} + +impl Debug for Output { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + match self { + Self::All => write!(f, "Output::All"), + Self::Primary => write!(f, "Output::Primary"), + Self::Active => write!(f, "Output::Active"), + Self::Handle(h) => write!(f, "Output::Handle({:?})", h), + Self::Named(name) => write!(f, "Output::Named({:?})", name), + Self::Filter(_) => write!(f, "Output::Filter()"), + } + } +} + +#[derive(Clone, Debug)] +pub struct Selector { + pub surface: Surface, + pub output: Output, +} + +impl Selector { + pub fn all() -> Self { + Self { + surface: Surface::All, + output: Output::All, + } + } + + pub(crate) fn matches( + &self, + surface_info: &SurfaceInfo, + output_info: Option<&OutputInfo>, + primary: Option, + active: Option, + ) -> bool { + self.surface.matches(surface_info) + && self + .output + .matches(surface_info.output, output_info, primary, active) + } +} + +impl From for Selector { + fn from(surface: Surface) -> Self { + Self { + surface, + output: Output::All, + } + } +} + +impl From for Selector { + fn from(output: Output) -> Self { + Self { + surface: Surface::All, + output, + } + } +} diff --git a/crates/composition/src/shell.rs b/crates/composition/src/shell.rs index 7bfbb85..87c589c 100644 --- a/crates/composition/src/shell.rs +++ b/crates/composition/src/shell.rs @@ -828,167 +828,6 @@ impl Shell { PopupBuilder::new(self, component_name.into()) } - pub fn on(&self, surface_name: &str, callback_name: &str, handler: F) -> Result<()> - where - F: Fn(ShellControl) -> R + 'static, - R: IntoValue, - { - if !self.registry.contains_name(surface_name) { - return Err(Error::Domain(DomainError::Configuration { - message: format!("Window '{}' not found", surface_name), - })); - } - - let control = self.control(); - let handler = Rc::new(handler); - let system = self.inner.borrow(); - - for surface in system.app_state().surfaces_by_name(surface_name) { - let handler_rc = Rc::clone(&handler); - let control_clone = control.clone(); - if let Err(e) = surface - .component_instance() - .set_callback(callback_name, move |_args| { - handler_rc(control_clone.clone()).into_value() - }) - { - log::error!( - "Failed to register callback '{}' on surface '{}': {}", - callback_name, - surface_name, - e - ); - } - } - - Ok(()) - } - - pub fn on_with_args( - &self, - surface_name: &str, - callback_name: &str, - handler: F, - ) -> Result<()> - where - F: Fn(&[Value], ShellControl) -> R + 'static, - R: IntoValue, - { - if !self.registry.contains_name(surface_name) { - return Err(Error::Domain(DomainError::Configuration { - message: format!("Window '{}' not found", surface_name), - })); - } - - let control = self.control(); - let handler = Rc::new(handler); - let system = self.inner.borrow(); - - for surface in system.app_state().surfaces_by_name(surface_name) { - let handler_rc = Rc::clone(&handler); - let control_clone = control.clone(); - if let Err(e) = surface - .component_instance() - .set_callback(callback_name, move |args| { - handler_rc(args, control_clone.clone()).into_value() - }) - { - log::error!( - "Failed to register callback '{}' on surface '{}': {}", - callback_name, - surface_name, - e - ); - } - } - - Ok(()) - } - - pub fn on_global(&self, callback_name: &str, handler: F) -> Result<()> - where - F: Fn(ShellControl) -> R + 'static, - R: IntoValue, - { - let control = self.control(); - let handler = Rc::new(handler); - let system = self.inner.borrow(); - - for surface in system.app_state().all_outputs() { - let handler_rc = Rc::clone(&handler); - let control_clone = control.clone(); - if let Err(e) = surface - .component_instance() - .set_callback(callback_name, move |_args| { - handler_rc(control_clone.clone()).into_value() - }) - { - log::error!( - "Failed to register global callback '{}': {}", - callback_name, - e - ); - } - } - - Ok(()) - } - - pub fn on_global_with_args(&self, callback_name: &str, handler: F) -> Result<()> - where - F: Fn(&[Value], ShellControl) -> R + 'static, - R: IntoValue, - { - let control = self.control(); - let handler = Rc::new(handler); - let system = self.inner.borrow(); - - for surface in system.app_state().all_outputs() { - let handler_rc = Rc::clone(&handler); - let control_clone = control.clone(); - if let Err(e) = surface - .component_instance() - .set_callback(callback_name, move |args| { - handler_rc(args, control_clone.clone()).into_value() - }) - { - log::error!( - "Failed to register global callback '{}': {}", - callback_name, - e - ); - } - } - - Ok(()) - } - - pub fn apply_surface_config(&self, surface_name: &str, f: F) - where - F: Fn(&ComponentInstance, LayerSurfaceHandle<'_>), - { - let system = self.inner.borrow(); - - 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); - } - } - } - - pub fn apply_global_config(&self, f: F) - where - F: Fn(&ComponentInstance, LayerSurfaceHandle<'_>), - { - let system = self.inner.borrow(); - - for surface in system.app_state().all_outputs() { - let surface_handle = LayerSurfaceHandle::from_window_state(surface); - f(surface.component_instance(), surface_handle); - } - } - pub fn output_registry(&self) -> OutputRegistry { let system = self.inner.borrow(); system.app_state().output_registry().clone() @@ -1003,6 +842,186 @@ impl Shell { let system = self.inner.borrow(); system.app_state().all_output_info().cloned().collect() } + + pub fn select(&self, selector: impl Into) -> crate::Selection<'_> { + crate::Selection::new(self, selector.into()) + } + + fn get_output_handles(&self) -> (Option, Option) { + let registry = &self.output_registry(); + (registry.primary_handle(), registry.active_handle()) + } + + pub(crate) fn on_internal( + &self, + selector: &crate::Selector, + callback_name: &str, + handler: F, + ) where + F: Fn(ShellControl) -> R + Clone + 'static, + R: IntoValue, + { + let control = self.control(); + let handler = Rc::new(handler); + let system = self.inner.borrow(); + let (primary, active) = self.get_output_handles(); + + for (key, surface) in system.app_state().surfaces_with_keys() { + let surface_info = crate::SurfaceInfo { + name: key.surface_name.clone(), + output: key.output_handle, + }; + + let output_info = system.app_state().get_output_info(key.output_handle); + + if selector.matches(&surface_info, output_info, primary, active) { + let handler_rc = Rc::clone(&handler); + let control_clone = control.clone(); + if let Err(e) = surface + .component_instance() + .set_callback(callback_name, move |_args| { + handler_rc(control_clone.clone()).into_value() + }) + { + log::error!( + "Failed to register callback '{}' on surface '{}': {}", + callback_name, + key.surface_name, + e + ); + } + } + } + } + + pub(crate) fn on_with_args_internal( + &self, + selector: &crate::Selector, + callback_name: &str, + handler: F, + ) where + F: Fn(&[Value], ShellControl) -> R + Clone + 'static, + R: IntoValue, + { + let control = self.control(); + let handler = Rc::new(handler); + let system = self.inner.borrow(); + let (primary, active) = self.get_output_handles(); + + for (key, surface) in system.app_state().surfaces_with_keys() { + let surface_info = crate::SurfaceInfo { + name: key.surface_name.clone(), + output: key.output_handle, + }; + + let output_info = system.app_state().get_output_info(key.output_handle); + + if selector.matches(&surface_info, output_info, primary, active) { + let handler_rc = Rc::clone(&handler); + let control_clone = control.clone(); + if let Err(e) = surface + .component_instance() + .set_callback(callback_name, move |args| { + handler_rc(args, control_clone.clone()).into_value() + }) + { + log::error!( + "Failed to register callback '{}' on surface '{}': {}", + callback_name, + key.surface_name, + e + ); + } + } + } + } + + pub(crate) fn with_selected(&self, selector: &crate::Selector, mut f: F) + where + F: FnMut(&str, &ComponentInstance), + { + let system = self.inner.borrow(); + let (primary, active) = self.get_output_handles(); + + for (key, surface) in system.app_state().surfaces_with_keys() { + let surface_info = crate::SurfaceInfo { + name: key.surface_name.clone(), + output: key.output_handle, + }; + + let output_info = system.app_state().get_output_info(key.output_handle); + + if selector.matches(&surface_info, output_info, primary, active) { + f(&key.surface_name, surface.component_instance()); + } + } + } + + pub(crate) fn configure_selected(&self, selector: &crate::Selector, mut f: F) + where + F: FnMut(&ComponentInstance, LayerSurfaceHandle<'_>), + { + let system = self.inner.borrow(); + let (primary, active) = self.get_output_handles(); + + for (key, surface) in system.app_state().surfaces_with_keys() { + let surface_info = crate::SurfaceInfo { + name: key.surface_name.clone(), + output: key.output_handle, + }; + + let output_info = system.app_state().get_output_info(key.output_handle); + + if selector.matches(&surface_info, output_info, primary, active) { + let surface_handle = LayerSurfaceHandle::from_window_state(surface); + f(surface.component_instance(), surface_handle); + } + } + } + + pub(crate) fn count_selected(&self, selector: &crate::Selector) -> usize { + let system = self.inner.borrow(); + let (primary, active) = self.get_output_handles(); + + system + .app_state() + .surfaces_with_keys() + .filter(|(key, _)| { + let surface_info = crate::SurfaceInfo { + name: key.surface_name.clone(), + output: key.output_handle, + }; + + let output_info = system.app_state().get_output_info(key.output_handle); + + selector.matches(&surface_info, output_info, primary, active) + }) + .count() + } + + pub(crate) fn get_selected_info(&self, selector: &crate::Selector) -> Vec { + let system = self.inner.borrow(); + let (primary, active) = self.get_output_handles(); + + system + .app_state() + .surfaces_with_keys() + .filter_map(|(key, _)| { + let surface_info = crate::SurfaceInfo { + name: key.surface_name.clone(), + output: key.output_handle, + }; + + let output_info = system.app_state().get_output_info(key.output_handle); + + if selector.matches(&surface_info, output_info, primary, active) { + Some(surface_info) + } else { + None + } + }) + .collect() + } } impl ShellRuntime for Shell { diff --git a/examples/declarative-config/src/main.rs b/examples/declarative-config/src/main.rs index e429f68..1b6de14 100644 --- a/examples/declarative-config/src/main.rs +++ b/examples/declarative-config/src/main.rs @@ -19,10 +19,12 @@ fn main() -> Result<()> { log::info!("Shell has surfaces: {:?}", shell.surface_names()); log::info!("Has StatusBar surface: {}", shell.has_surface("StatusBar")); - shell.on("StatusBar", "settings-clicked", |_control| { - log::info!("Settings button clicked"); - Value::Void - })?; + shell + .select(Surface::named("StatusBar")) + .on_callback("settings-clicked", |_control| { + log::info!("Settings button clicked"); + Value::Void + }); log::info!("Registered callback for settings-clicked"); diff --git a/examples/multi-surface/src/main.rs b/examples/multi-surface/src/main.rs index 0f1ff34..d41fd54 100644 --- a/examples/multi-surface/src/main.rs +++ b/examples/multi-surface/src/main.rs @@ -24,17 +24,21 @@ fn main() -> Result<()> { .namespace("multi-surface-dock") .build()?; - shell.on("TopBar", "workspace_clicked", |_control| { - log::info!("Workspace button clicked in TopBar"); - Value::Void - })?; + shell + .select(Surface::named("TopBar")) + .on_callback("workspace_clicked", |_control| { + log::info!("Workspace button clicked in TopBar"); + Value::Void + }); - shell.on_with_args("Dock", "app_clicked", |args, _control| { - if let Some(Value::String(app_name)) = args.first() { - log::info!("App clicked in Dock: {}", app_name.as_str()); - } - Value::Void - })?; + shell + .select(Surface::named("Dock")) + .on_callback_with_args("app_clicked", |args, _control| { + if let Some(Value::String(app_name)) = args.first() { + log::info!("App clicked in Dock: {}", app_name.as_str()); + } + Value::Void + }); log::info!("Running shell with surfaces: {:?}", shell.surface_names()); diff --git a/examples/runtime-surface-config/src/main.rs b/examples/runtime-surface-config/src/main.rs index 8d842ca..d18a624 100644 --- a/examples/runtime-surface-config/src/main.rs +++ b/examples/runtime-surface-config/src/main.rs @@ -77,121 +77,127 @@ fn setup_toggle_size_callback( sender: &Rc>, shell: &Shell, state: &Rc>, -) -> Result<()> { +) { let state_clone = Rc::clone(state); let sender_clone = Rc::clone(sender); - shell.on("Bar", "toggle-size", move |control| { - let is_expanded = { - let mut st = state_clone.borrow_mut(); - st.is_expanded = !st.is_expanded; + shell + .select(Surface::named("Bar")) + .on_callback("toggle-size", move |control| { + let is_expanded = { + let mut st = state_clone.borrow_mut(); + st.is_expanded = !st.is_expanded; - let new_size = if st.is_expanded { 64 } else { 32 }; + let new_size = if st.is_expanded { 64 } else { 32 }; - let (width, height) = match st.current_anchor { - AnchorPosition::Top | AnchorPosition::Bottom => { - log::info!("Resizing horizontal bar to {}px", new_size); - (0, new_size) + let (width, height) = match st.current_anchor { + AnchorPosition::Top | AnchorPosition::Bottom => { + log::info!("Resizing horizontal bar to {}px", new_size); + (0, new_size) + } + }; + + let bar = control.surface("Bar"); + if let Err(e) = bar.resize(width, height) { + log::error!("Failed to resize bar: {}", e); } + + if let Err(e) = bar.set_exclusive_zone(new_size.try_into().unwrap_or(32)) { + log::error!("Failed to set exclusive zone: {}", e); + } + + if let Err(e) = control.surface("Bar").set_margins((0, 0, 0, 0)) { + log::error!("Failed to set margins: {}", e); + } + + log::info!( + "Updated bar state: size={}, is_expanded={}", + new_size, + st.is_expanded + ); + + st.is_expanded }; - let bar = control.surface("Bar"); - if let Err(e) = bar.resize(width, height) { - log::error!("Failed to resize bar: {}", e); + if let Err(e) = sender_clone.send(UiUpdate::IsExpanded(is_expanded)) { + log::error!("Failed to send UI update: {}", e); } - if let Err(e) = bar.set_exclusive_zone(new_size.try_into().unwrap_or(32)) { - log::error!("Failed to set exclusive zone: {}", e); - } - - if let Err(e) = control.surface("Bar").set_margins((0, 0, 0, 0)) { - log::error!("Failed to set margins: {}", e); - } - - log::info!( - "Updated bar state: size={}, is_expanded={}", - new_size, - st.is_expanded - ); - - st.is_expanded - }; - - if let Err(e) = sender_clone.send(UiUpdate::IsExpanded(is_expanded)) { - log::error!("Failed to send UI update: {}", e); - } - - Value::Struct(Struct::from_iter([("expanded".into(), is_expanded.into())])) - }) + Value::Struct(Struct::from_iter([("expanded".into(), is_expanded.into())])) + }); } fn setup_anchor_switch_callback( sender: &Rc>, shell: &Shell, state: &Rc>, -) -> Result<()> { +) { let state_clone = Rc::clone(state); let sender_clone = Rc::clone(sender); - shell.on("Bar", "switch-anchor", move |control| { - let anchor_name = { - let mut st = state_clone.borrow_mut(); - st.next_anchor(); + shell + .select(Surface::named("Bar")) + .on_callback("switch-anchor", move |control| { + let anchor_name = { + let mut st = state_clone.borrow_mut(); + st.next_anchor(); - log::info!("Switching to anchor: {}", st.anchor_name()); + log::info!("Switching to anchor: {}", st.anchor_name()); - let bar = control.surface("Bar"); - if let Err(e) = bar.set_anchor(st.get_anchor_edges()) { - log::error!("Failed to apply config: {}", e); + let bar = control.surface("Bar"); + if let Err(e) = bar.set_anchor(st.get_anchor_edges()) { + log::error!("Failed to apply config: {}", e); + } + + st.anchor_name() + }; + + if let Err(e) = sender_clone.send(UiUpdate::CurrentAnchor(anchor_name.to_string())) { + log::error!("Failed to send UI update: {}", e); } - st.anchor_name() - }; + log::info!("Switched to {} anchor", anchor_name); - if let Err(e) = sender_clone.send(UiUpdate::CurrentAnchor(anchor_name.to_string())) { - log::error!("Failed to send UI update: {}", e); - } - - log::info!("Switched to {} anchor", anchor_name); - - Value::Struct(Struct::from_iter([( - "anchor".into(), - SharedString::from(anchor_name).into(), - )])) - }) + Value::Struct(Struct::from_iter([( + "anchor".into(), + SharedString::from(anchor_name).into(), + )])) + }); } fn setup_layer_switch_callback( sender: &Rc>, shell: &Shell, state: &Rc>, -) -> Result<()> { +) { let state_clone = Rc::clone(state); let sender_clone = Rc::clone(sender); - shell.on("Bar", "switch-layer", move |control| { - let layer_name = { - let mut st = state_clone.borrow_mut(); - let new_layer = st.next_layer(); + shell + .select(Surface::named("Bar")) + .on_callback("switch-layer", move |control| { + let layer_name = { + let mut st = state_clone.borrow_mut(); + let new_layer = st.next_layer(); - log::info!("Switching to layer: {:?}", new_layer); + log::info!("Switching to layer: {:?}", new_layer); - let bar = control.surface("Bar"); - if let Err(e) = bar.set_layer(new_layer) { - log::error!("Failed to set layer: {}", e); + let bar = control.surface("Bar"); + if let Err(e) = bar.set_layer(new_layer) { + log::error!("Failed to set layer: {}", e); + } + + st.layer_name() + }; + + if let Err(e) = sender_clone.send(UiUpdate::CurrentLayer(layer_name.to_string())) { + log::error!("Failed to send UI update: {}", e); } - st.layer_name() - }; + log::info!("Switched to {} layer", layer_name); - if let Err(e) = sender_clone.send(UiUpdate::CurrentLayer(layer_name.to_string())) { - log::error!("Failed to send UI update: {}", e); - } - - log::info!("Switched to {} layer", layer_name); - - Value::Struct(Struct::from_iter([( - "layer".into(), - SharedString::from(layer_name).into(), - )])) - }) + Value::Struct(Struct::from_iter([( + "layer".into(), + SharedString::from(layer_name).into(), + )])) + }); } fn main() -> Result<()> { @@ -214,7 +220,7 @@ fn main() -> Result<()> { .namespace("runtime-control-example") .build()?; - shell.with_all_surfaces(|_name, component| { + shell.select(Surface::all()).with_component(|component| { log::info!("Initializing properties for Bar surface"); let state_ref = state.borrow(); @@ -270,9 +276,9 @@ fn main() -> Result<()> { let sender_rc = Rc::new(sender); - setup_toggle_size_callback(&sender_rc, &shell, &state)?; - setup_anchor_switch_callback(&sender_rc, &shell, &state)?; - setup_layer_switch_callback(&sender_rc, &shell, &state)?; + setup_toggle_size_callback(&sender_rc, &shell, &state); + setup_anchor_switch_callback(&sender_rc, &shell, &state); + setup_layer_switch_callback(&sender_rc, &shell, &state); shell.run()?; Ok(()) diff --git a/src/lib.rs b/src/lib.rs index 0e64ba8..8fead0e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -121,9 +121,10 @@ pub mod window; pub use layer_shika_composition::{Error, Handle, Result, SurfaceHandle}; pub use shell::{ - CompiledUiSource, DEFAULT_COMPONENT_NAME, DEFAULT_SURFACE_NAME, LayerSurfaceHandle, Shell, - ShellBuilder, ShellConfig, ShellControl, ShellEventContext, ShellRuntime, - ShellSurfaceConfigHandler, SurfaceComponentConfig, SurfaceConfigBuilder, SurfaceDefinition, + CompiledUiSource, Output, Selection, Selector, Surface, SurfaceInfo, DEFAULT_COMPONENT_NAME, + DEFAULT_SURFACE_NAME, LayerSurfaceHandle, Shell, ShellBuilder, ShellConfig, ShellControl, + ShellEventContext, ShellRuntime, ShellSurfaceConfigHandler, SurfaceComponentConfig, + SurfaceConfigBuilder, SurfaceDefinition, }; pub use window::{ diff --git a/src/prelude.rs b/src/prelude.rs index 89743a7..c3e25d9 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -9,9 +9,10 @@ #![allow(clippy::pub_use)] pub use crate::shell::{ - CompiledUiSource, DEFAULT_COMPONENT_NAME, DEFAULT_SURFACE_NAME, LayerSurfaceHandle, Shell, - ShellBuilder, ShellConfig, ShellControl, ShellEventContext, ShellRuntime, - ShellSurfaceConfigHandler, SurfaceComponentConfig, SurfaceConfigBuilder, SurfaceDefinition, + CompiledUiSource, Output, Selection, Selector, Surface, SurfaceInfo, DEFAULT_COMPONENT_NAME, + DEFAULT_SURFACE_NAME, LayerSurfaceHandle, Shell, ShellBuilder, ShellConfig, ShellControl, + ShellEventContext, ShellRuntime, ShellSurfaceConfigHandler, SurfaceComponentConfig, + SurfaceConfigBuilder, SurfaceDefinition, }; pub use crate::window::{ diff --git a/src/shell.rs b/src/shell.rs index 1825a5c..fd5d250 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -1,5 +1,6 @@ pub use layer_shika_composition::{ - CompiledUiSource, DEFAULT_COMPONENT_NAME, DEFAULT_SURFACE_NAME, LayerSurfaceHandle, Shell, - ShellBuilder, ShellConfig, ShellControl, ShellEventContext, ShellRuntime, - ShellSurfaceConfigHandler, SurfaceComponentConfig, SurfaceConfigBuilder, SurfaceDefinition, + CompiledUiSource, Output, Selection, Selector, Surface, SurfaceInfo, DEFAULT_COMPONENT_NAME, + DEFAULT_SURFACE_NAME, LayerSurfaceHandle, Shell, ShellBuilder, ShellConfig, ShellControl, + ShellEventContext, ShellRuntime, ShellSurfaceConfigHandler, SurfaceComponentConfig, + SurfaceConfigBuilder, SurfaceDefinition, };