From 28c87310aa0b2d28c7f68b55788d815acd911e4e Mon Sep 17 00:00:00 2001 From: drendog Date: Wed, 3 Dec 2025 19:26:30 +0100 Subject: [PATCH] feat: add callback registration methods for shell --- crates/composition/src/shell.rs | 144 +++++++++++++++++++++++++++++++- 1 file changed, 143 insertions(+), 1 deletion(-) diff --git a/crates/composition/src/shell.rs b/crates/composition/src/shell.rs index dd6f5ff..efd680d 100644 --- a/crates/composition/src/shell.rs +++ b/crates/composition/src/shell.rs @@ -1,13 +1,16 @@ use crate::shell_composition::ShellWindowDefinition; use crate::shell_runtime::ShellRuntime; use crate::system::{EventContext, PopupCommand, ShellControl}; +use crate::value_conversion::IntoValue; use crate::{Error, Result}; use layer_shika_adapters::errors::EventLoopError; use layer_shika_adapters::platform::calloop::{ EventSource, Generic, Interest, Mode, PostAction, RegistrationToken, TimeoutAction, Timer, channel, }; -use layer_shika_adapters::platform::slint_interpreter::{CompilationResult, ComponentInstance}; +use layer_shika_adapters::platform::slint_interpreter::{ + CompilationResult, ComponentInstance, Value, +}; use layer_shika_adapters::platform::wayland::Anchor; use layer_shika_adapters::{ AppState, ShellWindowConfig, WaylandWindowConfig, WindowState, WindowingSystemFacade, @@ -334,6 +337,145 @@ impl Shell { pub fn compilation_result(&self) -> &Rc { &self.compilation_result } + + pub fn on(&self, shell_window_name: &str, callback_name: &str, handler: F) -> Result<()> + where + F: Fn(ShellControl) -> R + 'static, + R: IntoValue, + { + if !self.windows.contains_key(shell_window_name) { + return Err(Error::Domain(DomainError::Configuration { + message: format!("Shell window '{}' not found", shell_window_name), + })); + } + + let control = self.control(); + let handler = Rc::new(handler); + let facade = self.inner.borrow(); + let system = facade.inner_ref(); + + for window in system.app_state().windows_by_shell_name(shell_window_name) { + let handler_rc = Rc::clone(&handler); + let control_clone = control.clone(); + if let Err(e) = window + .component_instance() + .set_callback(callback_name, move |_args| { + handler_rc(control_clone.clone()).into_value() + }) + { + log::error!( + "Failed to register callback '{}' on window '{}': {}", + callback_name, + shell_window_name, + e + ); + } + } + + Ok(()) + } + + pub fn on_with_args( + &self, + shell_window_name: &str, + callback_name: &str, + handler: F, + ) -> Result<()> + where + F: Fn(&[Value], ShellControl) -> R + 'static, + R: IntoValue, + { + if !self.windows.contains_key(shell_window_name) { + return Err(Error::Domain(DomainError::Configuration { + message: format!("Shell window '{}' not found", shell_window_name), + })); + } + + let control = self.control(); + let handler = Rc::new(handler); + let facade = self.inner.borrow(); + let system = facade.inner_ref(); + + for window in system.app_state().windows_by_shell_name(shell_window_name) { + let handler_rc = Rc::clone(&handler); + let control_clone = control.clone(); + if let Err(e) = window + .component_instance() + .set_callback(callback_name, move |args| { + handler_rc(args, control_clone.clone()).into_value() + }) + { + log::error!( + "Failed to register callback '{}' on window '{}': {}", + callback_name, + shell_window_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 facade = self.inner.borrow(); + let system = facade.inner_ref(); + + for window in system.app_state().all_outputs() { + let handler_rc = Rc::clone(&handler); + let control_clone = control.clone(); + if let Err(e) = window + .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 facade = self.inner.borrow(); + let system = facade.inner_ref(); + + for window in system.app_state().all_outputs() { + let handler_rc = Rc::clone(&handler); + let control_clone = control.clone(); + if let Err(e) = window + .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(()) + } } impl ShellRuntime for Shell {