From ccea07b751279b95e489aa1d4d00c31445a2b598 Mon Sep 17 00:00:00 2001 From: drendog Date: Tue, 4 Nov 2025 01:32:49 +0100 Subject: [PATCH] refactor: centralize popup handling --- composition/src/system.rs | 101 +++++++++++++++++++++++++++++--------- 1 file changed, 79 insertions(+), 22 deletions(-) diff --git a/composition/src/system.rs b/composition/src/system.rs index fb12020..f44c61f 100644 --- a/composition/src/system.rs +++ b/composition/src/system.rs @@ -25,6 +25,11 @@ use std::rc::{Rc, Weak}; use std::result::Result as StdResult; use std::time::{Duration, Instant}; +enum PopupCommand { + Show(PopupRequest), + Close(PopupHandle), +} + pub struct EventLoopHandle { system: Weak>, } @@ -181,7 +186,7 @@ impl RuntimeState<'_> { req.mode ); - popup_manager.set_pending_popup(req.clone(), width, height); + popup_manager.set_pending_popup(req, width, height); Self::create_popup_instance(&definition, &popup_manager)?; @@ -285,6 +290,7 @@ impl RuntimeState<'_> { pub struct WindowingSystem { inner: Rc>, popup_positioning_mode: Rc>, + popup_command_sender: channel::Sender, } impl WindowingSystem { @@ -299,17 +305,56 @@ impl WindowingSystem { config, ); let inner = WaylandWindowingSystem::new(wayland_config)?; + let inner_rc = Rc::new(RefCell::new(inner)); + + let (sender, receiver) = channel::channel(); let system = Self { - inner: Rc::new(RefCell::new(inner)), + inner: Rc::clone(&inner_rc), popup_positioning_mode: Rc::new(RefCell::new(PopupPositioningMode::Center)), + popup_command_sender: sender, }; + system.setup_popup_command_handler(receiver)?; system.register_popup_callbacks()?; Ok(system) } + fn setup_popup_command_handler(&self, receiver: channel::Channel) -> Result<()> { + let loop_handle = self.inner.borrow().event_loop_handle(); + + loop_handle + .insert_source(receiver, |event, (), window_state| { + if let channel::Event::Msg(command) = event { + let mut runtime_state = RuntimeState { window_state }; + + match command { + PopupCommand::Show(request) => { + if let Err(e) = runtime_state.show_popup(request) { + log::error!("Failed to show popup: {}", e); + } + } + PopupCommand::Close(handle) => { + if let Err(e) = runtime_state.close_popup(handle) { + log::error!("Failed to close popup: {}", e); + } + } + } + } + }) + .map_err(|e| { + Error::Adapter( + EventLoopError::InsertSource { + message: format!("Failed to setup popup command handler: {e:?}"), + } + .into(), + ) + })?; + + Ok(()) + } + fn register_popup_callbacks(&self) -> Result<()> { let component_instance = self.component_instance(); @@ -338,24 +383,8 @@ impl WindowingSystem { }) })?; - let event_loop_handle = self.event_loop_handle(); - let popup_mode_for_channel = Rc::clone(&self.popup_positioning_mode); - - let (_token, sender) = event_loop_handle.add_channel( - move |(component_name, x, y): (String, f32, f32), mut state| { - let mode = *popup_mode_for_channel.borrow(); - - let request = PopupRequest::builder(component_name) - .at(PopupAt::absolute(x, y)) - .size(PopupSize::content()) - .mode(mode) - .build(); - - if let Err(e) = state.show_popup(request) { - log::error!("Failed to show popup: {}", e); - } - }, - )?; + 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| { @@ -380,8 +409,16 @@ impl WindowingSystem { .and_then(|v| v.clone().try_into().ok()) .unwrap_or(0.0); - if sender.send((component_name.to_string(), x, y)).is_err() { - log::error!("Failed to send popup request through channel"); + 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 }) @@ -401,6 +438,26 @@ impl WindowingSystem { } } + pub fn request_show_popup(&self, request: PopupRequest) -> Result<()> { + self.popup_command_sender + .send(PopupCommand::Show(request)) + .map_err(|_| { + Error::Domain(DomainError::Configuration { + message: "Failed to send popup show command: channel closed".to_string(), + }) + }) + } + + pub fn request_close_popup(&self, handle: PopupHandle) -> Result<()> { + self.popup_command_sender + .send(PopupCommand::Close(handle)) + .map_err(|_| { + Error::Domain(DomainError::Configuration { + message: "Failed to send popup close command: channel closed".to_string(), + }) + }) + } + pub fn run(&mut self) -> Result<()> { self.inner.borrow_mut().run()?; Ok(())