diff options
author | 2021-03-31 10:20:22 +0200 | |
---|---|---|
committer | 2021-03-31 10:20:22 +0200 | |
commit | b9ec44446ed4d99b9b17aceafdcb353dd1595877 (patch) | |
tree | 86b3e4d9a7257a6d5b0d82988111f2a3a5ca7117 | |
parent | bbb4e4678f14b4b187f9537a32063440e727e919 (diff) | |
parent | 8f952452ce3d61203856bcebae7016372556be31 (diff) | |
download | iced-b9ec44446ed4d99b9b17aceafdcb353dd1595877.tar.gz iced-b9ec44446ed4d99b9b17aceafdcb353dd1595877.tar.bz2 iced-b9ec44446ed4d99b9b17aceafdcb353dd1595877.zip |
Merge pull request #804 from hecrj/feature/graceful-exit
Graceful exiting for `Application`
-rw-r--r-- | examples/events/src/main.rs | 47 | ||||
-rw-r--r-- | glutin/src/application.rs | 13 | ||||
-rw-r--r-- | native/src/window/event.rs | 6 | ||||
-rw-r--r-- | src/application.rs | 11 | ||||
-rw-r--r-- | src/settings.rs | 15 | ||||
-rw-r--r-- | winit/src/application.rs | 23 | ||||
-rw-r--r-- | winit/src/conversion.rs | 3 | ||||
-rw-r--r-- | winit/src/settings.rs | 4 |
8 files changed, 103 insertions, 19 deletions
diff --git a/examples/events/src/main.rs b/examples/events/src/main.rs index 18e6364b..446c190b 100644 --- a/examples/events/src/main.rs +++ b/examples/events/src/main.rs @@ -1,22 +1,30 @@ use iced::{ - executor, Align, Application, Checkbox, Clipboard, Column, Command, - Container, Element, Length, Settings, Subscription, Text, + button, executor, Align, Application, Button, Checkbox, Clipboard, Column, + Command, Container, Element, HorizontalAlignment, Length, Settings, + Subscription, Text, }; +use iced_native::{window, Event}; pub fn main() -> iced::Result { - Events::run(Settings::default()) + Events::run(Settings { + exit_on_close_request: false, + ..Settings::default() + }) } #[derive(Debug, Default)] struct Events { last: Vec<iced_native::Event>, enabled: bool, + exit: button::State, + should_exit: bool, } #[derive(Debug, Clone)] enum Message { EventOccurred(iced_native::Event), Toggled(bool), + Exit, } impl Application for Events { @@ -38,27 +46,35 @@ impl Application for Events { _clipboard: &mut Clipboard, ) -> Command<Message> { match message { - Message::EventOccurred(event) => { + Message::EventOccurred(event) if self.enabled => { self.last.push(event); if self.last.len() > 5 { let _ = self.last.remove(0); } } + Message::EventOccurred(event) => { + if let Event::Window(window::Event::CloseRequested) = event { + self.should_exit = true; + } + } Message::Toggled(enabled) => { self.enabled = enabled; } + Message::Exit => { + self.should_exit = true; + } }; Command::none() } fn subscription(&self) -> Subscription<Message> { - if self.enabled { - iced_native::subscription::events().map(Message::EventOccurred) - } else { - Subscription::none() - } + iced_native::subscription::events().map(Message::EventOccurred) + } + + fn should_exit(&self) -> bool { + self.should_exit } fn view(&mut self) -> Element<Message> { @@ -75,11 +91,22 @@ impl Application for Events { Message::Toggled, ); + let exit = Button::new( + &mut self.exit, + Text::new("Exit") + .width(Length::Fill) + .horizontal_alignment(HorizontalAlignment::Center), + ) + .width(Length::Units(100)) + .padding(10) + .on_press(Message::Exit); + let content = Column::new() .align_items(Align::Center) .spacing(20) .push(events) - .push(toggle); + .push(toggle) + .push(exit); Container::new(content) .width(Length::Fill) diff --git a/glutin/src/application.rs b/glutin/src/application.rs index 163bc9f9..79fcf745 100644 --- a/glutin/src/application.rs +++ b/glutin/src/application.rs @@ -92,10 +92,11 @@ where application, compositor, renderer, - context, runtime, debug, receiver, + context, + settings.exit_on_close_request, )); 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 compositor: C, mut renderer: A::Renderer, - context: glutin::ContextWrapper<glutin::PossiblyCurrent, Window>, mut runtime: Runtime<E, Proxy<A::Message>, A::Message>, mut debug: Debug, mut receiver: mpsc::UnboundedReceiver<glutin::event::Event<'_, A::Message>>, + context: glutin::ContextWrapper<glutin::PossiblyCurrent, Window>, + exit_on_close_request: bool, ) where A: Application + 'static, E: Executor + 'static, @@ -212,6 +214,8 @@ async fn run_instance<A, E, C>( // Update window state.synchronize(&application, context.window()); + let should_exit = application.should_exit(); + user_interface = ManuallyDrop::new(application::build_user_interface( &mut application, @@ -220,6 +224,10 @@ async fn run_instance<A, E, C>( state.logical_size(), &mut debug, )); + + if should_exit { + break; + } } debug.draw_started(); @@ -290,6 +298,7 @@ async fn run_instance<A, E, C>( .. } => { if application::requests_exit(&window_event, state.modifiers()) + && exit_on_close_request { break; } diff --git a/native/src/window/event.rs b/native/src/window/event.rs index fc746781..3aa1ab0b 100644 --- a/native/src/window/event.rs +++ b/native/src/window/event.rs @@ -12,6 +12,12 @@ pub enum Event { height: u32, }, + /// The user has requested for the window to close. + /// + /// Usually, you will want to terminate the execution whenever this event + /// occurs. + CloseRequested, + /// A window was focused. Focused, diff --git a/src/application.rs b/src/application.rs index 83ce900a..7b7de6d4 100644 --- a/src/application.rs +++ b/src/application.rs @@ -184,6 +184,13 @@ pub trait Application: Sized { 1.0 } + /// Returns whether the [`Application`] should be terminated. + /// + /// By default, it returns `false`. + fn should_exit(&self) -> bool { + false + } + /// Runs the [`Application`]. /// /// On native platforms, this method will take control of the current thread @@ -284,6 +291,10 @@ where fn scale_factor(&self) -> f64 { self.0.scale_factor() } + + fn should_exit(&self) -> bool { + self.0.should_exit() + } } #[cfg(target_arch = "wasm32")] diff --git a/src/settings.rs b/src/settings.rs index c82a1354..2b32258d 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -25,6 +25,10 @@ pub struct Settings<Flags> { /// The default value is 20. 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 /// primitives. /// @@ -46,10 +50,11 @@ impl<Flags> Settings<Flags> { Self { flags, - antialiasing: default_settings.antialiasing, + window: default_settings.window, default_font: default_settings.default_font, 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 { Self { flags: Default::default(), - antialiasing: Default::default(), + window: Default::default(), default_font: Default::default(), 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 { window: settings.window.into(), flags: settings.flags, + exit_on_close_request: settings.exit_on_close_request, } } } diff --git a/winit/src/application.rs b/winit/src/application.rs index ef6c8463..106d5218 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -91,6 +91,13 @@ pub trait Application: Program<Clipboard = Clipboard> { fn scale_factor(&self) -> f64 { 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 @@ -149,10 +156,11 @@ where application, compositor, renderer, - window, runtime, debug, receiver, + window, + settings.exit_on_close_request, )); 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 compositor: C, mut renderer: A::Renderer, - window: winit::window::Window, mut runtime: Runtime<E, Proxy<A::Message>, A::Message>, mut debug: Debug, mut receiver: mpsc::UnboundedReceiver<winit::event::Event<'_, A::Message>>, + window: winit::window::Window, + exit_on_close_request: bool, ) where A: Application + 'static, E: Executor + 'static, @@ -279,6 +288,8 @@ async fn run_instance<A, E, C>( // Update window state.synchronize(&application, &window); + let should_exit = application.should_exit(); + user_interface = ManuallyDrop::new(build_user_interface( &mut application, cache, @@ -286,6 +297,10 @@ async fn run_instance<A, E, C>( state.logical_size(), &mut debug, )); + + if should_exit { + break; + } } debug.draw_started(); @@ -358,7 +373,9 @@ async fn run_instance<A, E, C>( event: window_event, .. } => { - if requests_exit(&window_event, state.modifiers()) { + if requests_exit(&window_event, state.modifiers()) + && exit_on_close_request + { break; } diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs index 0e04b35d..0fa27413 100644 --- a/winit/src/conversion.rs +++ b/winit/src/conversion.rs @@ -33,6 +33,9 @@ pub fn window_event( height: logical_size.height, })) } + WindowEvent::CloseRequested => { + Some(Event::Window(window::Event::CloseRequested)) + } WindowEvent::CursorMoved { position, .. } => { let position = position.to_logical::<f64>(scale_factor); diff --git a/winit/src/settings.rs b/winit/src/settings.rs index 2e8715cd..9ce5cfc5 100644 --- a/winit/src/settings.rs +++ b/winit/src/settings.rs @@ -23,6 +23,10 @@ pub struct Settings<Flags> { /// /// [`Application`]: crate::Application 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. |