refactor: centralize popup handling

This commit is contained in:
drendog 2025-11-04 01:32:49 +01:00
parent 6e5c0259e9
commit ccea07b751
Signed by: dwenya
GPG key ID: 8DD77074645332D0

View file

@ -25,6 +25,11 @@ use std::rc::{Rc, Weak};
use std::result::Result as StdResult; use std::result::Result as StdResult;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
enum PopupCommand {
Show(PopupRequest),
Close(PopupHandle),
}
pub struct EventLoopHandle { pub struct EventLoopHandle {
system: Weak<RefCell<WaylandWindowingSystem>>, system: Weak<RefCell<WaylandWindowingSystem>>,
} }
@ -181,7 +186,7 @@ impl RuntimeState<'_> {
req.mode 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)?; Self::create_popup_instance(&definition, &popup_manager)?;
@ -285,6 +290,7 @@ impl RuntimeState<'_> {
pub struct WindowingSystem { pub struct WindowingSystem {
inner: Rc<RefCell<WaylandWindowingSystem>>, inner: Rc<RefCell<WaylandWindowingSystem>>,
popup_positioning_mode: Rc<RefCell<PopupPositioningMode>>, popup_positioning_mode: Rc<RefCell<PopupPositioningMode>>,
popup_command_sender: channel::Sender<PopupCommand>,
} }
impl WindowingSystem { impl WindowingSystem {
@ -299,17 +305,56 @@ impl WindowingSystem {
config, config,
); );
let inner = WaylandWindowingSystem::new(wayland_config)?; let inner = WaylandWindowingSystem::new(wayland_config)?;
let inner_rc = Rc::new(RefCell::new(inner));
let (sender, receiver) = channel::channel();
let system = Self { let system = Self {
inner: Rc::new(RefCell::new(inner)), inner: Rc::clone(&inner_rc),
popup_positioning_mode: Rc::new(RefCell::new(PopupPositioningMode::Center)), popup_positioning_mode: Rc::new(RefCell::new(PopupPositioningMode::Center)),
popup_command_sender: sender,
}; };
system.setup_popup_command_handler(receiver)?;
system.register_popup_callbacks()?; system.register_popup_callbacks()?;
Ok(system) Ok(system)
} }
fn setup_popup_command_handler(&self, receiver: channel::Channel<PopupCommand>) -> 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<()> { fn register_popup_callbacks(&self) -> Result<()> {
let component_instance = self.component_instance(); let component_instance = self.component_instance();
@ -338,24 +383,8 @@ impl WindowingSystem {
}) })
})?; })?;
let event_loop_handle = self.event_loop_handle(); let sender = self.popup_command_sender.clone();
let popup_mode_for_channel = Rc::clone(&self.popup_positioning_mode); let popup_mode_for_callback = 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);
}
},
)?;
component_instance component_instance
.set_callback("show_popup", move |args| { .set_callback("show_popup", move |args| {
@ -380,8 +409,16 @@ impl WindowingSystem {
.and_then(|v| v.clone().try_into().ok()) .and_then(|v| v.clone().try_into().ok())
.unwrap_or(0.0); .unwrap_or(0.0);
if sender.send((component_name.to_string(), x, y)).is_err() { let mode = *popup_mode_for_callback.borrow();
log::error!("Failed to send popup request through channel");
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 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<()> { pub fn run(&mut self) -> Result<()> {
self.inner.borrow_mut().run()?; self.inner.borrow_mut().run()?;
Ok(()) Ok(())