window_ondemand: wait for Destroyed event before exiting app

Considering the strict requirement that applications can't keep windows
across run_ondemand calls, this tries to make the window_ondemand example
explicitly wait for its Window to be destroyed before exiting each
run_ondemand iteration.

This updates the example to only `.set_exit()` after it gets a
`Destroyed` event after the Window has been dropped.

On Windows this works to ensure the Window is destroyed before the
example waits for 5 seconds.

Unfortunately though:
1. The Wayland backend doesn't emit `Destroyed` events for windows
2. The macOS backend emits `Destroyed` events before the window is
   really destroyed.

and so the example isn't currently portable.
This commit is contained in:
Robert Bragg 2023-07-04 23:28:43 +01:00 committed by Kirill Chibisov
parent ec11b4877f
commit e5eb253698

View file

@ -3,13 +3,16 @@
// Limit this example to only compatible platforms. // Limit this example to only compatible platforms.
#[cfg(any(windows_platform, macos_platform, x11_platform, wayland_platform,))] #[cfg(any(windows_platform, macos_platform, x11_platform, wayland_platform,))]
fn main() -> Result<(), impl std::error::Error> { fn main() -> Result<(), impl std::error::Error> {
use std::time::Duration;
use simple_logger::SimpleLogger; use simple_logger::SimpleLogger;
use winit::{ use winit::{
error::RunLoopError,
event::{Event, WindowEvent}, event::{Event, WindowEvent},
event_loop::EventLoop, event_loop::EventLoop,
platform::run_ondemand::EventLoopExtRunOnDemand, platform::run_ondemand::EventLoopExtRunOnDemand,
window::{Window, WindowBuilder}, window::{Window, WindowBuilder, WindowId},
}; };
#[path = "util/fill.rs"] #[path = "util/fill.rs"]
@ -17,18 +20,19 @@ fn main() -> Result<(), impl std::error::Error> {
#[derive(Default)] #[derive(Default)]
struct App { struct App {
window_id: Option<WindowId>,
window: Option<Window>, window: Option<Window>,
} }
SimpleLogger::new().init().unwrap(); SimpleLogger::new().init().unwrap();
let mut event_loop = EventLoop::new(); let mut event_loop = EventLoop::new();
{ fn run_app(event_loop: &mut EventLoop<()>, idx: usize) -> Result<(), RunLoopError> {
let mut app = App::default(); let mut app = App::default();
event_loop.run_ondemand(move |event, event_loop, control_flow| { event_loop.run_ondemand(move |event, event_loop, control_flow| {
control_flow.set_wait(); control_flow.set_wait();
println!("Run 1: {:?}", event); println!("Run {idx}: {:?}", event);
if let Some(window) = &app.window { if let Some(window) = &app.window {
match event { match event {
@ -36,8 +40,8 @@ fn main() -> Result<(), impl std::error::Error> {
event: WindowEvent::CloseRequested, event: WindowEvent::CloseRequested,
window_id, window_id,
} if window.id() == window_id => { } if window.id() == window_id => {
println!("--------------------------------------------------------- Window {idx} CloseRequested");
app.window = None; app.window = None;
control_flow.set_exit();
} }
Event::MainEventsCleared => window.request_redraw(), Event::MainEventsCleared => window.request_redraw(),
Event::RedrawRequested(_) => { Event::RedrawRequested(_) => {
@ -45,56 +49,37 @@ fn main() -> Result<(), impl std::error::Error> {
} }
_ => (), _ => (),
} }
} else if let Some(id) = app.window_id {
match event {
Event::WindowEvent {
event: WindowEvent::Destroyed,
window_id,
} if id == window_id => {
println!("--------------------------------------------------------- Window {idx} Destroyed");
app.window_id = None;
control_flow.set_exit();
}
_ => (),
}
} else if let Event::Resumed = event { } else if let Event::Resumed = event {
app.window = Some( let window = WindowBuilder::new()
WindowBuilder::new()
.with_title("Fantastic window number one!") .with_title("Fantastic window number one!")
.with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0)) .with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0))
.build(event_loop) .build(event_loop)
.unwrap(), .unwrap();
); app.window_id = Some(window.id());
app.window = Some(window);
} }
})?; })
} }
run_app(&mut event_loop, 1)?;
println!("--------------------------------------------------------- Finished first loop"); println!("--------------------------------------------------------- Finished first loop");
println!("--------------------------------------------------------- Waiting 5 seconds"); println!("--------------------------------------------------------- Waiting 5 seconds");
std::thread::sleep_ms(5000); std::thread::sleep(Duration::from_secs(5));
let ret = {
let mut app = App::default();
event_loop.run_ondemand(move |event, event_loop, control_flow| {
control_flow.set_wait();
println!("Run 2: {:?}", event);
if let Some(window) = &app.window {
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window.id() == window_id => {
app.window = None;
control_flow.set_exit();
}
Event::MainEventsCleared => window.request_redraw(),
Event::RedrawRequested(_) => {
fill::fill_window(window);
}
_ => (),
}
} else if let Event::Resumed = event {
app.window = Some(
WindowBuilder::new()
.with_title("Fantastic window number two!")
.with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0))
.build(event_loop)
.unwrap(),
);
}
})
};
let ret = run_app(&mut event_loop, 2);
println!("--------------------------------------------------------- Finished second loop"); println!("--------------------------------------------------------- Finished second loop");
ret ret
} }