Moved exit_on_close_request to window settings. This now controls whether each INDIVIDUAL window should close on CloseRequested events.
This commit is contained in:
parent
d53ccc857d
commit
83c7870c56
8 changed files with 130 additions and 85 deletions
|
|
@ -28,9 +28,6 @@ pub enum Event {
|
|||
RedrawRequested(Instant),
|
||||
|
||||
/// 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 destroyed by the runtime.
|
||||
|
|
|
|||
|
|
@ -57,6 +57,16 @@ pub struct Settings {
|
|||
|
||||
/// Platform specific settings.
|
||||
pub platform_specific: PlatformSpecific,
|
||||
|
||||
/// Whether the window will close when the user requests it, e.g. when a user presses the
|
||||
/// close button.
|
||||
///
|
||||
/// This can be useful if you want to have some behavior that executes before the window is
|
||||
/// actually destroyed. If you disable this, you must manually close the window with the
|
||||
/// `window::close` command.
|
||||
///
|
||||
/// By default this is enabled.
|
||||
pub exit_on_close_request: bool,
|
||||
}
|
||||
|
||||
impl Default for Settings {
|
||||
|
|
@ -73,6 +83,7 @@ impl Default for Settings {
|
|||
level: Level::default(),
|
||||
icon: None,
|
||||
platform_specific: Default::default(),
|
||||
exit_on_close_request: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,7 @@ use iced::{
|
|||
use std::collections::HashMap;
|
||||
|
||||
fn main() -> iced::Result {
|
||||
Example::run(Settings {
|
||||
exit_on_close_request: false,
|
||||
..Default::default()
|
||||
})
|
||||
Example::run(Settings::default())
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
@ -111,6 +108,7 @@ impl multi_window::Application for Example {
|
|||
id,
|
||||
window::Settings {
|
||||
position: self.next_window_pos,
|
||||
exit_on_close_request: count % 2 == 0,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -41,14 +41,6 @@ pub struct Settings<Flags> {
|
|||
///
|
||||
/// [`Canvas`]: crate::widget::Canvas
|
||||
pub antialiasing: bool,
|
||||
|
||||
/// Whether the [`Application`] should exit when the user requests the
|
||||
/// window to close (e.g. the user presses the close button).
|
||||
///
|
||||
/// By default, it is enabled.
|
||||
///
|
||||
/// [`Application`]: crate::Application
|
||||
pub exit_on_close_request: bool,
|
||||
}
|
||||
|
||||
impl<Flags> Settings<Flags> {
|
||||
|
|
@ -65,7 +57,6 @@ impl<Flags> Settings<Flags> {
|
|||
default_font: default_settings.default_font,
|
||||
default_text_size: default_settings.default_text_size,
|
||||
antialiasing: default_settings.antialiasing,
|
||||
exit_on_close_request: default_settings.exit_on_close_request,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -82,7 +73,6 @@ where
|
|||
default_font: Default::default(),
|
||||
default_text_size: 16.0,
|
||||
antialiasing: false,
|
||||
exit_on_close_request: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -93,7 +83,6 @@ impl<Flags> From<Settings<Flags>> for iced_winit::Settings<Flags> {
|
|||
id: settings.id,
|
||||
window: settings.window,
|
||||
flags: settings.flags,
|
||||
exit_on_close_request: settings.exit_on_close_request,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,6 +136,8 @@ where
|
|||
let target = settings.window.platform_specific.target.clone();
|
||||
|
||||
let should_be_visible = settings.window.visible;
|
||||
let exit_on_close_request = settings.window.exit_on_close_request;
|
||||
|
||||
let builder = settings::window_builder(
|
||||
settings.window,
|
||||
&application.title(),
|
||||
|
|
@ -197,7 +199,7 @@ where
|
|||
init_command,
|
||||
window,
|
||||
should_be_visible,
|
||||
settings.exit_on_close_request,
|
||||
exit_on_close_request,
|
||||
));
|
||||
|
||||
let mut context = task::Context::from_waker(task::noop_waker_ref());
|
||||
|
|
|
|||
|
|
@ -46,7 +46,14 @@ pub enum Event<Message> {
|
|||
/// An internal event for closing a window.
|
||||
CloseWindow(window::Id),
|
||||
/// An internal event for when the window has finished being created.
|
||||
WindowCreated(window::Id, winit::window::Window),
|
||||
WindowCreated {
|
||||
/// The internal ID of the window.
|
||||
id: window::Id,
|
||||
/// The raw window.
|
||||
window: winit::window::Window,
|
||||
/// Whether or not the window should close when a user requests it does.
|
||||
exit_on_close_request: bool,
|
||||
},
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
|
|
@ -161,6 +168,8 @@ where
|
|||
};
|
||||
|
||||
let should_main_be_visible = settings.window.visible;
|
||||
let exit_on_close_request = settings.window.exit_on_close_request;
|
||||
|
||||
let builder = window_builder(
|
||||
settings.window,
|
||||
&application.title(window::Id::MAIN),
|
||||
|
|
@ -208,8 +217,13 @@ where
|
|||
let (mut compositor, renderer) =
|
||||
C::new(compositor_settings, Some(&main_window))?;
|
||||
|
||||
let windows =
|
||||
Windows::new(&application, &mut compositor, renderer, main_window);
|
||||
let windows = Windows::new(
|
||||
&application,
|
||||
&mut compositor,
|
||||
renderer,
|
||||
main_window,
|
||||
exit_on_close_request,
|
||||
);
|
||||
|
||||
let (mut event_sender, event_receiver) = mpsc::unbounded();
|
||||
let (control_sender, mut control_receiver) = mpsc::unbounded();
|
||||
|
|
@ -225,7 +239,6 @@ where
|
|||
init_command,
|
||||
windows,
|
||||
should_main_be_visible,
|
||||
settings.exit_on_close_request,
|
||||
));
|
||||
|
||||
let mut context = task::Context::from_waker(task::noop_waker_ref());
|
||||
|
|
@ -255,14 +268,18 @@ where
|
|||
title,
|
||||
monitor,
|
||||
}) => {
|
||||
let exit_on_close_request = settings.exit_on_close_request;
|
||||
|
||||
let window =
|
||||
settings::window_builder(settings, &title, monitor, None)
|
||||
.build(window_target)
|
||||
.expect("Failed to build window");
|
||||
|
||||
Some(winit::event::Event::UserEvent(Event::WindowCreated(
|
||||
id, window,
|
||||
)))
|
||||
Some(winit::event::Event::UserEvent(Event::WindowCreated {
|
||||
id,
|
||||
window,
|
||||
exit_on_close_request,
|
||||
}))
|
||||
}
|
||||
_ => event.to_static(),
|
||||
};
|
||||
|
|
@ -299,7 +316,6 @@ async fn run_instance<A, E, C>(
|
|||
init_command: Command<A::Message>,
|
||||
mut windows: Windows<A, C>,
|
||||
should_main_window_be_visible: bool,
|
||||
exit_on_main_closed: bool,
|
||||
) where
|
||||
A: Application + 'static,
|
||||
E: Executor + 'static,
|
||||
|
|
@ -548,11 +564,20 @@ async fn run_instance<A, E, C>(
|
|||
Event::Application(message) => {
|
||||
messages.push(message);
|
||||
}
|
||||
Event::WindowCreated(id, window) => {
|
||||
Event::WindowCreated {
|
||||
id,
|
||||
window,
|
||||
exit_on_close_request,
|
||||
} => {
|
||||
let bounds = logical_bounds_of(&window);
|
||||
|
||||
let (inner_size, i) =
|
||||
windows.add(&application, &mut compositor, id, window);
|
||||
let (inner_size, i) = windows.add(
|
||||
&application,
|
||||
&mut compositor,
|
||||
id,
|
||||
window,
|
||||
exit_on_close_request,
|
||||
);
|
||||
|
||||
user_interfaces.push(build_user_interface(
|
||||
&application,
|
||||
|
|
@ -680,50 +705,61 @@ async fn run_instance<A, E, C>(
|
|||
event: window_event,
|
||||
window_id,
|
||||
} => {
|
||||
let window_deleted = windows
|
||||
.pending_destroy
|
||||
.iter()
|
||||
.any(|(_, w_id)| window_id == *w_id);
|
||||
let window_index =
|
||||
windows.raw.iter().position(|w| w.id() == window_id);
|
||||
|
||||
if matches!(window_event, winit::event::WindowEvent::Destroyed)
|
||||
{
|
||||
// This is the only special case, since in order trigger the Destroyed event the
|
||||
// window reference from winit must be dropped, but we still want to inform the
|
||||
// user that the window was destroyed so they can clean up any specific window
|
||||
// code for this window
|
||||
let id = windows.get_pending_destroy(window_id);
|
||||
match window_index {
|
||||
Some(i) => {
|
||||
let id = windows.ids[i];
|
||||
let raw = &windows.raw[i];
|
||||
let exit_on_close_request =
|
||||
windows.exit_on_close_requested[i];
|
||||
|
||||
events.push((
|
||||
None,
|
||||
core::Event::Window(id, window::Event::Destroyed),
|
||||
));
|
||||
} else if !window_deleted {
|
||||
let i = windows.index_from_raw(window_id);
|
||||
let id = windows.ids[i];
|
||||
let raw = &windows.raw[i];
|
||||
let state = &mut windows.states[i];
|
||||
if matches!(
|
||||
window_event,
|
||||
winit::event::WindowEvent::CloseRequested
|
||||
) && exit_on_close_request
|
||||
{
|
||||
let i = windows.delete(id);
|
||||
let _ = user_interfaces.remove(i);
|
||||
let _ = ui_caches.remove(i);
|
||||
|
||||
// first check if we need to just break the entire application
|
||||
// e.g. a user does a force quit on MacOS, or if a user has set "exit on main closed"
|
||||
// as an option in window settings and wants to close the main window
|
||||
if requests_exit(
|
||||
i,
|
||||
exit_on_main_closed,
|
||||
&window_event,
|
||||
state.modifiers(),
|
||||
) {
|
||||
break 'main;
|
||||
if windows.is_empty() {
|
||||
break 'main;
|
||||
}
|
||||
} else {
|
||||
let state = &mut windows.states[i];
|
||||
state.update(raw, &window_event, &mut debug);
|
||||
|
||||
if let Some(event) = conversion::window_event(
|
||||
id,
|
||||
&window_event,
|
||||
state.scale_factor(),
|
||||
state.modifiers(),
|
||||
) {
|
||||
events.push((Some(id), event));
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// This is the only special case, since in order to trigger the Destroyed event the
|
||||
// window reference from winit must be dropped, but we still want to inform the
|
||||
// user that the window was destroyed so they can clean up any specific window
|
||||
// code for this window
|
||||
if matches!(
|
||||
window_event,
|
||||
winit::event::WindowEvent::Destroyed
|
||||
) {
|
||||
let id = windows.get_pending_destroy(window_id);
|
||||
|
||||
state.update(raw, &window_event, &mut debug);
|
||||
|
||||
if let Some(event) = conversion::window_event(
|
||||
id,
|
||||
&window_event,
|
||||
state.scale_factor(),
|
||||
state.modifiers(),
|
||||
) {
|
||||
events.push((Some(id), event));
|
||||
events.push((
|
||||
None,
|
||||
core::Event::Window(
|
||||
id,
|
||||
window::Event::Destroyed,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1068,17 +1104,13 @@ where
|
|||
|
||||
/// Returns true if the provided event should cause an [`Application`] to
|
||||
/// exit.
|
||||
pub fn requests_exit(
|
||||
window: usize,
|
||||
exit_on_main_closed: bool,
|
||||
pub fn user_force_quit(
|
||||
event: &winit::event::WindowEvent<'_>,
|
||||
_modifiers: winit::event::ModifiersState,
|
||||
) -> bool {
|
||||
use winit::event::WindowEvent;
|
||||
|
||||
//TODO alt f4..?
|
||||
match event {
|
||||
WindowEvent::CloseRequested => exit_on_main_closed && window == 0,
|
||||
#[cfg(target_os = "macos")]
|
||||
WindowEvent::KeyboardInput {
|
||||
input:
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ where
|
|||
pub raw: Vec<winit::window::Window>,
|
||||
pub states: Vec<State<A>>,
|
||||
pub viewport_versions: Vec<usize>,
|
||||
pub exit_on_close_requested: Vec<bool>,
|
||||
pub surfaces: Vec<C::Surface>,
|
||||
pub renderers: Vec<A::Renderer>,
|
||||
pub pending_destroy: Vec<(window::Id, winit::window::WindowId)>,
|
||||
|
|
@ -52,6 +53,7 @@ where
|
|||
compositor: &mut C,
|
||||
renderer: A::Renderer,
|
||||
main: winit::window::Window,
|
||||
exit_on_close_requested: bool,
|
||||
) -> Self {
|
||||
let state = State::new(application, window::Id::MAIN, &main);
|
||||
let viewport_version = state.viewport_version();
|
||||
|
|
@ -67,6 +69,7 @@ where
|
|||
raw: vec![main],
|
||||
states: vec![state],
|
||||
viewport_versions: vec![viewport_version],
|
||||
exit_on_close_requested: vec![exit_on_close_requested],
|
||||
surfaces: vec![surface],
|
||||
renderers: vec![renderer],
|
||||
pending_destroy: vec![],
|
||||
|
|
@ -81,6 +84,7 @@ where
|
|||
compositor: &mut C,
|
||||
id: window::Id,
|
||||
window: winit::window::Window,
|
||||
exit_on_close_requested: bool,
|
||||
) -> (Size, usize) {
|
||||
let state = State::new(application, id, &window);
|
||||
let window_size = state.logical_size();
|
||||
|
|
@ -96,6 +100,7 @@ where
|
|||
self.ids.push(id);
|
||||
self.raw.push(window);
|
||||
self.states.push(state);
|
||||
self.exit_on_close_requested.push(exit_on_close_requested);
|
||||
self.viewport_versions.push(viewport_version);
|
||||
self.surfaces.push(surface);
|
||||
self.renderers.push(renderer);
|
||||
|
|
@ -145,6 +150,7 @@ where
|
|||
let id = self.ids.remove(i);
|
||||
let window = self.raw.remove(i);
|
||||
let _ = self.states.remove(i);
|
||||
let _ = self.exit_on_close_requested.remove(i);
|
||||
let _ = self.viewport_versions.remove(i);
|
||||
let _ = self.surfaces.remove(i);
|
||||
|
||||
|
|
@ -167,4 +173,24 @@ where
|
|||
let (id, _) = self.pending_destroy.remove(i);
|
||||
id
|
||||
}
|
||||
|
||||
/// Returns the windows that need to be requested to closed, and also the windows that can be
|
||||
/// closed immediately.
|
||||
pub fn partition_close_requests(&self) -> (Vec<window::Id>, Vec<window::Id>) {
|
||||
self.exit_on_close_requested.iter().enumerate().fold(
|
||||
(vec![], vec![]),
|
||||
|(mut close_immediately, mut needs_request_closed),
|
||||
(i, close)| {
|
||||
let id = self.ids[i];
|
||||
|
||||
if *close {
|
||||
close_immediately.push(id);
|
||||
} else {
|
||||
needs_request_closed.push(id);
|
||||
}
|
||||
|
||||
(close_immediately, needs_request_closed)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Configure your application.
|
||||
use crate::conversion;
|
||||
use crate::core::window;
|
||||
use crate::conversion;
|
||||
|
||||
use winit::monitor::MonitorHandle;
|
||||
use winit::window::WindowBuilder;
|
||||
|
|
@ -21,16 +21,6 @@ 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).
|
||||
///
|
||||
/// With a [`multi_window::Application`] this will instead be used to determine whether the
|
||||
/// application should exit when the "main"" window is closed, i.e. the first window created on
|
||||
/// app launch.
|
||||
///
|
||||
/// [`Application`]: crate::Application
|
||||
pub exit_on_close_request: bool,
|
||||
}
|
||||
|
||||
/// Converts the window settings into a `WindowBuilder` from `winit`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue