Add support for graceful exits in `Application`

- `Settings` now contains an `exit_on_close_request` field
- `Application` has a new `should_exit` method
This commit is contained in:
Héctor Ramón Jiménez 2021-03-30 21:44:19 +02:00
parent 00de9d0c9b
commit 67db13ff7c
5 changed files with 57 additions and 9 deletions

View File

@ -92,10 +92,11 @@ where
application, application,
compositor, compositor,
renderer, renderer,
context,
runtime, runtime,
debug, debug,
receiver, receiver,
context,
settings.exit_on_close_request,
)); ));
let mut context = task::Context::from_waker(task::noop_waker_ref()); let mut context = task::Context::from_waker(task::noop_waker_ref());
@ -139,10 +140,11 @@ async fn run_instance<A, E, C>(
mut application: A, mut application: A,
mut compositor: C, mut compositor: C,
mut renderer: A::Renderer, mut renderer: A::Renderer,
context: glutin::ContextWrapper<glutin::PossiblyCurrent, Window>,
mut runtime: Runtime<E, Proxy<A::Message>, A::Message>, mut runtime: Runtime<E, Proxy<A::Message>, A::Message>,
mut debug: Debug, mut debug: Debug,
mut receiver: mpsc::UnboundedReceiver<glutin::event::Event<'_, A::Message>>, mut receiver: mpsc::UnboundedReceiver<glutin::event::Event<'_, A::Message>>,
context: glutin::ContextWrapper<glutin::PossiblyCurrent, Window>,
exit_on_close_request: bool,
) where ) where
A: Application + 'static, A: Application + 'static,
E: Executor + 'static, E: Executor + 'static,
@ -212,6 +214,8 @@ async fn run_instance<A, E, C>(
// Update window // Update window
state.synchronize(&application, context.window()); state.synchronize(&application, context.window());
let should_exit = application.should_exit();
user_interface = user_interface =
ManuallyDrop::new(application::build_user_interface( ManuallyDrop::new(application::build_user_interface(
&mut application, &mut application,
@ -220,6 +224,10 @@ async fn run_instance<A, E, C>(
state.logical_size(), state.logical_size(),
&mut debug, &mut debug,
)); ));
if should_exit {
break;
}
} }
debug.draw_started(); debug.draw_started();
@ -290,6 +298,7 @@ async fn run_instance<A, E, C>(
.. ..
} => { } => {
if application::requests_exit(&window_event, state.modifiers()) if application::requests_exit(&window_event, state.modifiers())
&& exit_on_close_request
{ {
break; break;
} }

View File

@ -184,6 +184,13 @@ pub trait Application: Sized {
1.0 1.0
} }
/// Returns whether the [`Application`] should be terminated.
///
/// By default, it returns `false`.
fn should_exit(&self) -> bool {
false
}
/// Runs the [`Application`]. /// Runs the [`Application`].
/// ///
/// On native platforms, this method will take control of the current thread /// On native platforms, this method will take control of the current thread
@ -284,6 +291,10 @@ where
fn scale_factor(&self) -> f64 { fn scale_factor(&self) -> f64 {
self.0.scale_factor() self.0.scale_factor()
} }
fn should_exit(&self) -> bool {
self.0.should_exit()
}
} }
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]

View File

@ -25,6 +25,10 @@ pub struct Settings<Flags> {
/// The default value is 20. /// The default value is 20.
pub default_text_size: u16, pub default_text_size: u16,
/// Whether the [`Application`] should exit when the user requests the
/// window to close (e.g. the user presses the close button).
pub exit_on_close_request: bool,
/// If set to true, the renderer will try to perform antialiasing for some /// If set to true, the renderer will try to perform antialiasing for some
/// primitives. /// primitives.
/// ///
@ -46,10 +50,11 @@ impl<Flags> Settings<Flags> {
Self { Self {
flags, flags,
antialiasing: default_settings.antialiasing, window: default_settings.window,
default_font: default_settings.default_font, default_font: default_settings.default_font,
default_text_size: default_settings.default_text_size, default_text_size: default_settings.default_text_size,
window: default_settings.window, exit_on_close_request: default_settings.exit_on_close_request,
antialiasing: default_settings.antialiasing,
} }
} }
} }
@ -61,10 +66,11 @@ where
fn default() -> Self { fn default() -> Self {
Self { Self {
flags: Default::default(), flags: Default::default(),
antialiasing: Default::default(), window: Default::default(),
default_font: Default::default(), default_font: Default::default(),
default_text_size: 20, default_text_size: 20,
window: Default::default(), exit_on_close_request: true,
antialiasing: false,
} }
} }
} }
@ -75,6 +81,7 @@ impl<Flags> From<Settings<Flags>> for iced_winit::Settings<Flags> {
iced_winit::Settings { iced_winit::Settings {
window: settings.window.into(), window: settings.window.into(),
flags: settings.flags, flags: settings.flags,
exit_on_close_request: settings.exit_on_close_request,
} }
} }
} }

View File

@ -91,6 +91,13 @@ pub trait Application: Program<Clipboard = Clipboard> {
fn scale_factor(&self) -> f64 { fn scale_factor(&self) -> f64 {
1.0 1.0
} }
/// Returns whether the [`Application`] should be terminated.
///
/// By default, it returns `false`.
fn should_exit(&self) -> bool {
false
}
} }
/// Runs an [`Application`] with an executor, compositor, and the provided /// Runs an [`Application`] with an executor, compositor, and the provided
@ -149,10 +156,11 @@ where
application, application,
compositor, compositor,
renderer, renderer,
window,
runtime, runtime,
debug, debug,
receiver, receiver,
window,
settings.exit_on_close_request,
)); ));
let mut context = task::Context::from_waker(task::noop_waker_ref()); let mut context = task::Context::from_waker(task::noop_waker_ref());
@ -196,10 +204,11 @@ async fn run_instance<A, E, C>(
mut application: A, mut application: A,
mut compositor: C, mut compositor: C,
mut renderer: A::Renderer, mut renderer: A::Renderer,
window: winit::window::Window,
mut runtime: Runtime<E, Proxy<A::Message>, A::Message>, mut runtime: Runtime<E, Proxy<A::Message>, A::Message>,
mut debug: Debug, mut debug: Debug,
mut receiver: mpsc::UnboundedReceiver<winit::event::Event<'_, A::Message>>, mut receiver: mpsc::UnboundedReceiver<winit::event::Event<'_, A::Message>>,
window: winit::window::Window,
exit_on_close_request: bool,
) where ) where
A: Application + 'static, A: Application + 'static,
E: Executor + 'static, E: Executor + 'static,
@ -279,6 +288,8 @@ async fn run_instance<A, E, C>(
// Update window // Update window
state.synchronize(&application, &window); state.synchronize(&application, &window);
let should_exit = application.should_exit();
user_interface = ManuallyDrop::new(build_user_interface( user_interface = ManuallyDrop::new(build_user_interface(
&mut application, &mut application,
cache, cache,
@ -286,6 +297,10 @@ async fn run_instance<A, E, C>(
state.logical_size(), state.logical_size(),
&mut debug, &mut debug,
)); ));
if should_exit {
break;
}
} }
debug.draw_started(); debug.draw_started();
@ -358,7 +373,9 @@ async fn run_instance<A, E, C>(
event: window_event, event: window_event,
.. ..
} => { } => {
if requests_exit(&window_event, state.modifiers()) { if requests_exit(&window_event, state.modifiers())
&& exit_on_close_request
{
break; break;
} }

View File

@ -23,6 +23,10 @@ pub struct Settings<Flags> {
/// ///
/// [`Application`]: crate::Application /// [`Application`]: crate::Application
pub flags: Flags, pub flags: Flags,
/// Whether the [`Application`] should exit when the user requests the
/// window to close (e.g. the user presses the close button).
pub exit_on_close_request: bool,
} }
/// The window settings of an application. /// The window settings of an application.