diff --git a/gui/src/rt/mod.rs b/gui/src/rt/mod.rs index 11d144e7e..13941169f 100644 --- a/gui/src/rt/mod.rs +++ b/gui/src/rt/mod.rs @@ -56,9 +56,15 @@ where main, windows: HashMap::default(), on_close: WindowEvent::default(), + error: None, }; - el.run_app(&mut rt).map_err(RuntimeError::RunEventLoop) + el.run_app(&mut rt).map_err(RuntimeError::RunEventLoop)?; + + match rt.error { + Some(e) => Err(e), + None => Ok(()), + } } /// # Panics @@ -109,6 +115,7 @@ struct Runtime { main: u64, windows: HashMap>, on_close: WindowEvent<()>, + error: Option, } impl Runtime { @@ -148,16 +155,16 @@ impl Runtime { true } - fn dispatch_window( + fn dispatch_window( &mut self, el: &ActiveEventLoop, win: WindowId, - f: impl FnOnce(&dyn RuntimeWindow) -> Result<(), Box>, - ) { + f: impl FnOnce(&dyn RuntimeWindow) -> R, + ) -> Option { // Get target window. let win = match self.windows.get(&win).unwrap().upgrade() { Some(v) => v, - None => return, + None => return None, }; // Setup context. @@ -170,12 +177,7 @@ impl Runtime { }; // Dispatch the event. - let e = match cx.run(move || f(win.as_ref())) { - Ok(_) => return, - Err(e) => e, - }; - - todo!() + Some(cx.run(move || f(win.as_ref()))) } } @@ -200,17 +202,40 @@ impl ApplicationHandler for Runtime { ) { use winit::event::WindowEvent; - match event { - WindowEvent::Resized(v) => self.dispatch_window(el, id, move |w| w.update_size(v)), - WindowEvent::CloseRequested => self.on_close.raise(id, ()), - WindowEvent::Destroyed => drop(self.windows.remove(&id)), + // Process the event. + let e = match event { + WindowEvent::Resized(v) => match self.dispatch_window(el, id, |w| w.update_size(v)) { + Some(Err(e)) => RuntimeError::UpdateWindowSize(e), + _ => return, + }, + WindowEvent::CloseRequested => { + self.on_close.raise(id, ()); + return; + } + WindowEvent::Destroyed => { + // It is possible for the window to not in the list if the function passed to + // create_window() fails. + self.windows.remove(&id); + return; + } WindowEvent::ScaleFactorChanged { scale_factor, inner_size_writer: _, - } => self.dispatch_window(el, id, move |w| w.update_scale_factor(scale_factor)), - WindowEvent::RedrawRequested => self.dispatch_window(el, id, |w| w.redraw()), - _ => {} - } + } => match self.dispatch_window(el, id, move |w| w.update_scale_factor(scale_factor)) { + Some(Err(e)) => RuntimeError::UpdateWindowScaleFactor(e), + _ => return, + }, + WindowEvent::RedrawRequested => match self.dispatch_window(el, id, |w| w.redraw()) { + Some(Err(e)) => RuntimeError::RedrawWindow(e), + _ => return, + }, + _ => return, + }; + + // Store error then exit. + self.error = Some(e); + + el.exit(); } } @@ -233,4 +258,13 @@ pub enum RuntimeError { #[error("couldn't create runtime window")] CreateRuntimeWindow(#[source] Box), + + #[error("couldn't update window size")] + UpdateWindowSize(#[source] Box), + + #[error("couldn't update window scale factor")] + UpdateWindowScaleFactor(#[source] Box), + + #[error("couldn't redraw the window")] + RedrawWindow(#[source] Box), } diff --git a/gui/src/rt/window.rs b/gui/src/rt/window.rs index 43fb52b01..03ca97f4c 100644 --- a/gui/src/rt/window.rs +++ b/gui/src/rt/window.rs @@ -1,9 +1,11 @@ use std::error::Error; use winit::dpi::PhysicalSize; -/// Encapsulates winit window with application-specific logic. +/// Encapsulates winit window with window-specific logic. +/// +/// The event loop will exit immediately if any method return an error. pub trait RuntimeWindow { - fn update_size(&self, v: PhysicalSize) -> Result<(), Box>; - fn update_scale_factor(&self, v: f64) -> Result<(), Box>; - fn redraw(&self) -> Result<(), Box>; + fn update_size(&self, v: PhysicalSize) -> Result<(), Box>; + fn update_scale_factor(&self, v: f64) -> Result<(), Box>; + fn redraw(&self) -> Result<(), Box>; } diff --git a/gui/src/ui/backend/window.rs b/gui/src/ui/backend/window.rs index 5d171e233..ff4acfa6a 100644 --- a/gui/src/ui/backend/window.rs +++ b/gui/src/ui/backend/window.rs @@ -38,7 +38,10 @@ impl Window { } impl RuntimeWindow for Window { - fn update_size(&self, v: winit::dpi::PhysicalSize) -> Result<(), Box> { + fn update_size( + &self, + v: winit::dpi::PhysicalSize, + ) -> Result<(), Box> { let size = PhysicalSize::new(v.width, v.height); let size = LogicalSize::from_physical(size, self.winit.scale_factor() as f32); @@ -47,7 +50,7 @@ impl RuntimeWindow for Window { Ok(()) } - fn update_scale_factor(&self, v: f64) -> Result<(), Box> { + fn update_scale_factor(&self, v: f64) -> Result<(), Box> { let scale_factor = v as f32; self.slint @@ -56,7 +59,7 @@ impl RuntimeWindow for Window { Ok(()) } - fn redraw(&self) -> Result<(), Box> { + fn redraw(&self) -> Result<(), Box> { // Wayland will show the window on the first render so we need to check visibility flag // here. if self.visible.get().is_some_and(|v| v) {