From cc385fde3bde2927659cf7ff04376fe535567b35 Mon Sep 17 00:00:00 2001 From: drendog Date: Fri, 14 Nov 2025 21:50:41 +0100 Subject: [PATCH] feat: add facade for wayland adapter --- crates/adapters/src/lib.rs | 13 +- crates/adapters/src/wayland/facade.rs | 85 +++++++++ crates/adapters/src/wayland/mod.rs | 1 + .../src/wayland/surfaces/surface_state.rs | 2 +- crates/composition/src/system.rs | 171 +++++++++--------- crates/domain/src/ports/windowing.rs | 2 +- 6 files changed, 181 insertions(+), 93 deletions(-) create mode 100644 crates/adapters/src/wayland/facade.rs diff --git a/crates/adapters/src/lib.rs b/crates/adapters/src/lib.rs index d4b4588..4159a8c 100644 --- a/crates/adapters/src/lib.rs +++ b/crates/adapters/src/lib.rs @@ -6,14 +6,11 @@ pub(crate) mod wayland; pub use rendering::femtovg::popup_window::PopupWindow; -pub use wayland::{ - config::WaylandWindowConfig, - shell_adapter::WaylandWindowingSystem, - surfaces::{ - popup_manager::{PopupId, PopupManager}, - surface_state::WindowState, - }, -}; +pub use wayland::config::WaylandWindowConfig; +pub use wayland::facade::{PopupManagerFacade, RuntimeStateFacade, WindowingSystemFacade}; +pub use wayland::shell_adapter::WaylandWindowingSystem; +pub use wayland::surfaces::popup_manager::{PopupId, PopupManager}; +pub use wayland::surfaces::surface_state::WindowState; pub mod platform { pub use slint; diff --git a/crates/adapters/src/wayland/facade.rs b/crates/adapters/src/wayland/facade.rs new file mode 100644 index 0000000..8ac41e0 --- /dev/null +++ b/crates/adapters/src/wayland/facade.rs @@ -0,0 +1,85 @@ +use crate::errors::Result; +use crate::wayland::shell_adapter::WaylandWindowingSystem; +use crate::wayland::surfaces::popup_manager::PopupManager; +use crate::wayland::surfaces::surface_state::WindowState; +use layer_shika_domain::errors::DomainError; +use layer_shika_domain::ports::windowing::RuntimeStatePort; +use slint_interpreter::ComponentInstance; +use std::rc::Rc; +use std::result::Result as StdResult; + +pub struct WindowingSystemFacade { + inner: WaylandWindowingSystem, +} + +impl WindowingSystemFacade { + pub fn new(inner: WaylandWindowingSystem) -> Self { + Self { inner } + } + + pub fn inner_ref(&self) -> &WaylandWindowingSystem { + &self.inner + } + + pub fn inner_mut(&mut self) -> &mut WaylandWindowingSystem { + &mut self.inner + } + + pub fn component_instance(&self) -> &ComponentInstance { + self.inner.component_instance() + } + + pub fn run(&mut self) -> Result<()> { + self.inner.run() + } +} + +pub struct RuntimeStateFacade<'a> { + window_state: &'a mut WindowState, +} + +impl<'a> RuntimeStateFacade<'a> { + pub fn new(window_state: &'a mut WindowState) -> Self { + Self { window_state } + } + + pub fn popup_manager(&self) -> Option> { + self.window_state.popup_manager().cloned() + } + + pub fn component_instance(&self) -> &ComponentInstance { + self.window_state.component_instance() + } + + pub fn window_state(&self) -> &WindowState { + self.window_state + } + + pub fn window_state_mut(&mut self) -> &mut WindowState { + self.window_state + } +} + +impl RuntimeStatePort for RuntimeStateFacade<'_> { + fn render_frame_if_dirty(&mut self) -> StdResult<(), DomainError> { + self.window_state + .render_frame_if_dirty() + .map_err(|e| DomainError::Adapter { + source: Box::new(e), + }) + } +} + +pub struct PopupManagerFacade { + inner: Rc, +} + +impl PopupManagerFacade { + pub fn new(inner: Rc) -> Self { + Self { inner } + } + + pub fn inner(&self) -> &Rc { + &self.inner + } +} diff --git a/crates/adapters/src/wayland/mod.rs b/crates/adapters/src/wayland/mod.rs index 713e5b6..b6f2102 100644 --- a/crates/adapters/src/wayland/mod.rs +++ b/crates/adapters/src/wayland/mod.rs @@ -1,5 +1,6 @@ pub(crate) mod config; pub(crate) mod event_handling; +pub(crate) mod facade; pub(crate) mod globals; pub(crate) mod managed_proxies; pub(crate) mod shell_adapter; diff --git a/crates/adapters/src/wayland/surfaces/surface_state.rs b/crates/adapters/src/wayland/surfaces/surface_state.rs index 0254b63..f50c167 100644 --- a/crates/adapters/src/wayland/surfaces/surface_state.rs +++ b/crates/adapters/src/wayland/surfaces/surface_state.rs @@ -267,7 +267,7 @@ impl WindowState { } impl RuntimeStatePort for WindowState { - fn render_frame_if_dirty(&self) -> CoreResult<(), DomainError> { + fn render_frame_if_dirty(&mut self) -> CoreResult<(), DomainError> { WindowState::render_frame_if_dirty(self).map_err(|e| DomainError::Adapter { source: Box::new(e), }) diff --git a/crates/composition/src/system.rs b/crates/composition/src/system.rs index 97b3426..fcb90a6 100644 --- a/crates/composition/src/system.rs +++ b/crates/composition/src/system.rs @@ -9,7 +9,7 @@ use layer_shika_adapters::platform::slint_interpreter::{ CompilationResult, ComponentDefinition, ComponentInstance, Value, }; use layer_shika_adapters::{ - PopupId, PopupManager, WaylandWindowConfig, WaylandWindowingSystem, WindowState, + PopupId, PopupManager, WaylandWindowConfig, WindowState, WindowingSystemFacade, }; use layer_shika_domain::config::WindowConfig; use layer_shika_domain::errors::DomainError; @@ -18,7 +18,7 @@ use layer_shika_domain::value_objects::popup_request::{ PopupAt, PopupHandle, PopupRequest, PopupSize, }; use std::cell::Cell; -use std::cell::{Ref, RefCell}; +use std::cell::RefCell; use std::os::unix::io::AsFd; use std::rc::{Rc, Weak}; use std::result::Result as StdResult; @@ -31,7 +31,7 @@ pub enum PopupCommand { } pub struct EventLoopHandle { - system: Weak>, + system: Weak>, } impl EventLoopHandle { @@ -45,7 +45,7 @@ impl EventLoopHandle { F: FnMut(S::Event, &mut S::Metadata, RuntimeState<'_>) -> R + 'static, { let system = self.system.upgrade().ok_or(Error::SystemDropped)?; - let loop_handle = system.borrow().event_loop_handle(); + let loop_handle = system.borrow().inner_ref().event_loop_handle(); loop_handle .insert_source(source, move |event, metadata, window_state| { @@ -395,7 +395,7 @@ impl RuntimeState<'_> { } pub struct WindowingSystem { - inner: Rc>, + inner: Rc>, popup_positioning_mode: Rc>, popup_command_sender: channel::Sender, } @@ -411,8 +411,9 @@ impl WindowingSystem { compilation_result, config, ); - let inner = WaylandWindowingSystem::new(wayland_config)?; - let inner_rc = Rc::new(RefCell::new(inner)); + let inner = layer_shika_adapters::WaylandWindowingSystem::new(wayland_config)?; + let facade = WindowingSystemFacade::new(inner); + let inner_rc = Rc::new(RefCell::new(facade)); let (sender, receiver) = channel::channel(); @@ -429,7 +430,7 @@ impl WindowingSystem { } fn setup_popup_command_handler(&self, receiver: channel::Channel) -> Result<()> { - let loop_handle = self.inner.borrow().event_loop_handle(); + let loop_handle = self.inner.borrow().inner_ref().event_loop_handle(); let sender_for_handler = self.popup_command_sender.clone(); loop_handle @@ -476,81 +477,83 @@ impl WindowingSystem { } fn register_popup_callbacks(&self) -> Result<()> { - let component_instance = self.component_instance(); + self.with_component_instance(|component_instance| { + let popup_mode_clone = Rc::clone(&self.popup_positioning_mode); + component_instance + .set_callback("set_popup_positioning_mode", move |args| { + let center_x: bool = args + .first() + .and_then(|v| v.clone().try_into().ok()) + .unwrap_or(false); + let center_y: bool = args + .get(1) + .and_then(|v| v.clone().try_into().ok()) + .unwrap_or(false); - let popup_mode_clone = Rc::clone(&self.popup_positioning_mode); - component_instance - .set_callback("set_popup_positioning_mode", move |args| { - let center_x: bool = args - .first() - .and_then(|v| v.clone().try_into().ok()) - .unwrap_or(false); - let center_y: bool = args - .get(1) - .and_then(|v| v.clone().try_into().ok()) - .unwrap_or(false); - - let mode = PopupPositioningMode::from_flags(center_x, center_y); - *popup_mode_clone.borrow_mut() = mode; - log::info!( - "Popup positioning mode set to: {:?} (center_x: {}, center_y: {})", - mode, - center_x, - center_y - ); - Value::Void - }) - .map_err(|e| { - Error::Domain(DomainError::Configuration { - message: format!( - "Failed to register set_popup_positioning_mode callback: {}", - e - ), + let mode = PopupPositioningMode::from_flags(center_x, center_y); + *popup_mode_clone.borrow_mut() = mode; + log::info!( + "Popup positioning mode set to: {:?} (center_x: {}, center_y: {})", + mode, + center_x, + center_y + ); + Value::Void }) - })?; - - let sender = self.popup_command_sender.clone(); - let popup_mode_for_callback = Rc::clone(&self.popup_positioning_mode); - - component_instance - .set_callback("show_popup", move |args| { - let component_name: SharedString = args - .first() - .and_then(|v| v.clone().try_into().ok()) - .unwrap_or_else(|| SharedString::from("")); - - if component_name.is_empty() { - log::error!("show_popup called without component name"); - return Value::Void; - } - - let x: f32 = args - .get(1) - .and_then(|v| v.clone().try_into().ok()) - .unwrap_or(0.0); - let y: f32 = args - .get(2) - .and_then(|v| v.clone().try_into().ok()) - .unwrap_or(0.0); - - let mode = *popup_mode_for_callback.borrow(); - - let request = PopupRequest::builder(component_name.to_string()) - .at(PopupAt::absolute(x, y)) - .size(PopupSize::content()) - .mode(mode) - .build(); - - if sender.send(PopupCommand::Show(request)).is_err() { - log::error!("Failed to send popup show command through channel"); - } - Value::Void - }) - .map_err(|e| { - Error::Domain(DomainError::Configuration { - message: format!("Failed to register show_popup callback: {}", e), + .map_err(|e| { + Error::Domain(DomainError::Configuration { + message: format!( + "Failed to register set_popup_positioning_mode callback: {}", + e + ), + }) }) - })?; + })?; + + self.with_component_instance(|component_instance| { + let sender = self.popup_command_sender.clone(); + let popup_mode_for_callback = Rc::clone(&self.popup_positioning_mode); + + component_instance + .set_callback("show_popup", move |args| { + let component_name: SharedString = args + .first() + .and_then(|v| v.clone().try_into().ok()) + .unwrap_or_else(|| SharedString::from("")); + + if component_name.is_empty() { + log::error!("show_popup called without component name"); + return Value::Void; + } + + let x: f32 = args + .get(1) + .and_then(|v| v.clone().try_into().ok()) + .unwrap_or(0.0); + let y: f32 = args + .get(2) + .and_then(|v| v.clone().try_into().ok()) + .unwrap_or(0.0); + + let mode = *popup_mode_for_callback.borrow(); + + let request = PopupRequest::builder(component_name.to_string()) + .at(PopupAt::absolute(x, y)) + .size(PopupSize::content()) + .mode(mode) + .build(); + + if sender.send(PopupCommand::Show(request)).is_err() { + log::error!("Failed to send popup show command through channel"); + } + Value::Void + }) + .map_err(|e| { + Error::Domain(DomainError::Configuration { + message: format!("Failed to register show_popup callback: {}", e), + }) + }) + })?; Ok(()) } @@ -587,8 +590,10 @@ impl WindowingSystem { Ok(()) } - #[must_use] - pub fn component_instance(&self) -> Ref<'_, ComponentInstance> { - Ref::map(self.inner.borrow(), |system| system.component_instance()) + pub fn with_component_instance(&self, f: F) -> R + where + F: FnOnce(&ComponentInstance) -> R, + { + f(self.inner.borrow().component_instance()) } } diff --git a/crates/domain/src/ports/windowing.rs b/crates/domain/src/ports/windowing.rs index 31ade23..82e1541 100644 --- a/crates/domain/src/ports/windowing.rs +++ b/crates/domain/src/ports/windowing.rs @@ -5,5 +5,5 @@ pub trait WindowingSystemPort { } pub trait RuntimeStatePort { - fn render_frame_if_dirty(&self) -> Result<(), DomainError>; + fn render_frame_if_dirty(&mut self) -> Result<(), DomainError>; }