From a450b1c9895a98a41d03f9995386610f6c5ec941 Mon Sep 17 00:00:00 2001 From: Tye <131195812+tye-exe@users.noreply.github.com> Date: Tue, 30 Sep 2025 14:48:54 +0100 Subject: [PATCH] Properly end winit event loop (#7565) --- crates/eframe/src/native/glow_integration.rs | 21 ++++--------------- crates/eframe/src/native/run.rs | 5 +++++ crates/eframe/src/native/wgpu_integration.rs | 9 ++++---- crates/eframe/src/native/winit_integration.rs | 19 +++++++++++++++++ 4 files changed, 33 insertions(+), 21 deletions(-) diff --git a/crates/eframe/src/native/glow_integration.rs b/crates/eframe/src/native/glow_integration.rs index 4a1df9e1..9dc8bdfe 100644 --- a/crates/eframe/src/native/glow_integration.rs +++ b/crates/eframe/src/native/glow_integration.rs @@ -470,7 +470,7 @@ impl WinitApp for GlowWinitApp<'_> { if let Some(running) = &mut self.running { Ok(running.on_window_event(window_id, &event)) } else { - Ok(EventResult::Wait) + Ok(EventResult::Exit) } } @@ -747,7 +747,7 @@ impl GlowWinitRunning<'_> { } if integration.should_close() { - Ok(EventResult::Exit) + Ok(EventResult::CloseRequested) } else { Ok(EventResult::Wait) } @@ -798,7 +798,7 @@ impl GlowWinitRunning<'_> { log::debug!( "Received WindowEvent::CloseRequested for main viewport - shutting down." ); - return EventResult::Exit; + return EventResult::CloseRequested; } log::debug!("Received WindowEvent::CloseRequested for viewport {viewport_id:?}"); @@ -818,24 +818,11 @@ impl GlowWinitRunning<'_> { } } } - - winit::event::WindowEvent::Destroyed => { - log::debug!( - "Received WindowEvent::Destroyed for viewport {:?}", - viewport_id - ); - if viewport_id == Some(ViewportId::ROOT) { - return EventResult::Exit; - } else { - return EventResult::Wait; - } - } - _ => {} } if self.integration.should_close() { - return EventResult::Exit; + return EventResult::CloseRequested; } let mut event_response = egui_winit::EventResponse { diff --git a/crates/eframe/src/native/run.rs b/crates/eframe/src/native/run.rs index d21731bd..03fa7de7 100644 --- a/crates/eframe/src/native/run.rs +++ b/crates/eframe/src/native/run.rs @@ -139,6 +139,11 @@ impl WinitAppWrapper { exit = true; event_result } + EventResult::CloseRequested => { + // The windows need to be dropped whilst the event loop is running to allow for proper cleanup. + self.winit_app.save_and_destroy(); + event_result + } }); if let Err(err) = combined_result { diff --git a/crates/eframe/src/native/wgpu_integration.rs b/crates/eframe/src/native/wgpu_integration.rs index 1d06e672..550512b7 100644 --- a/crates/eframe/src/native/wgpu_integration.rs +++ b/crates/eframe/src/native/wgpu_integration.rs @@ -461,7 +461,8 @@ impl WinitApp for WgpuWinitApp<'_> { if let Some(running) = &mut self.running { Ok(running.on_window_event(window_id, &event)) } else { - Ok(EventResult::Wait) + // running is removed to get ready for exiting + Ok(EventResult::Exit) } } @@ -739,7 +740,7 @@ impl WgpuWinitRunning<'_> { } if integration.should_close() { - Ok(EventResult::Exit) + Ok(EventResult::CloseRequested) } else { Ok(EventResult::Wait) } @@ -799,7 +800,7 @@ impl WgpuWinitRunning<'_> { log::debug!( "Received WindowEvent::CloseRequested for main viewport - shutting down." ); - return EventResult::Exit; + return EventResult::CloseRequested; } log::debug!("Received WindowEvent::CloseRequested for viewport {viewport_id:?}"); @@ -833,7 +834,7 @@ impl WgpuWinitRunning<'_> { .unwrap_or_default(); if integration.should_close() { - EventResult::Exit + EventResult::CloseRequested } else if event_response.repaint { if repaint_asap { EventResult::RepaintNow(window_id) diff --git a/crates/eframe/src/native/winit_integration.rs b/crates/eframe/src/native/winit_integration.rs index d85443f3..2cf2e901 100644 --- a/crates/eframe/src/native/winit_integration.rs +++ b/crates/eframe/src/native/winit_integration.rs @@ -124,6 +124,25 @@ pub enum EventResult { /// Causes a save of the client state when the persistence feature is enabled. Save, + /// Starts the process of ending eframe execution whilst allowing for proper + /// clean up of resources. + /// + /// # Warning + /// This event **must** occur before [`Exit`] to correctly exit eframe code. + /// If in doubt, return this event. + /// + /// [`Exit`]: [EventResult::Exit] + CloseRequested, + + /// The event loop will exit, now. + /// The correct circumstance to return this event is in response to a winit "Destroyed" event. + /// + /// # Warning + /// The [`CloseRequested`] **must** occur before this event to ensure that winit + /// is able to remove any open windows. Otherwise the window(s) will remain open + /// until the program terminates. + /// + /// [`CloseRequested`]: EventResult::CloseRequested Exit, }