diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e9f8ef9..b5d3a52d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ Unreleased` header. - **Breaking:** On Web, macOS and iOS, return `HandleError::Unavailable` when a window handle is not available. - **Breaking:** Bump MSRV from `1.65` to `1.70`. - On Wayland, fix `WindowEvent::Destroyed` not being delivered after destroying window. +- Fix `EventLoopExtRunOnDemand::run_on_demand` not working for consequent invocation # 0.29.5 diff --git a/examples/util/fill.rs b/examples/util/fill.rs index 6ff4ed69..1136e7ae 100644 --- a/examples/util/fill.rs +++ b/examples/util/fill.rs @@ -7,17 +7,30 @@ //! The `softbuffer` crate is used, largely because of its ease of use. `glutin` or `wgpu` could //! also be used to fill the window buffer, but they are more complicated to use. -use winit::window::Window; +#[allow(unused_imports)] +pub use platform::cleanup_window; +pub use platform::fill_window; #[cfg(all(feature = "rwh_05", not(any(target_os = "android", target_os = "ios"))))] -pub(super) fn fill_window(window: &Window) { - use softbuffer::{Context, Surface}; +mod platform { use std::cell::RefCell; use std::collections::HashMap; use std::mem::ManuallyDrop; use std::num::NonZeroU32; + + use softbuffer::{Context, Surface}; + use winit::window::Window; use winit::window::WindowId; + thread_local! { + // NOTE: You should never do things like that, create context and drop it before + // you drop the event loop. We do this for brevity to not blow up examples. We use + // ManuallyDrop to prevent destructors from running. + // + // A static, thread-local map of graphics contexts to open windows. + static GC: ManuallyDrop>> = ManuallyDrop::new(RefCell::new(None)); + } + /// The graphics context used to draw to a window. struct GraphicsContext { /// The global softbuffer context. @@ -35,55 +48,69 @@ pub(super) fn fill_window(window: &Window) { } } - fn surface(&mut self, w: &Window) -> &mut Surface { - self.surfaces.entry(w.id()).or_insert_with(|| { - unsafe { Surface::new(&self.context, w) } + fn create_surface(&mut self, window: &Window) -> &mut Surface { + self.surfaces.entry(window.id()).or_insert_with(|| { + unsafe { Surface::new(&self.context, window) } .expect("Failed to create a softbuffer surface") }) } + + fn destroy_surface(&mut self, window: &Window) { + self.surfaces.remove(&window.id()); + } } - thread_local! { - // NOTE: You should never do things like that, create context and drop it before - // you drop the event loop. We do this for brevity to not blow up examples. We use - // ManuallyDrop to prevent destructors from running. - // - // A static, thread-local map of graphics contexts to open windows. - static GC: ManuallyDrop>> = ManuallyDrop::new(RefCell::new(None)); + pub fn fill_window(window: &Window) { + GC.with(|gc| { + let size = window.inner_size(); + let (Some(width), Some(height)) = + (NonZeroU32::new(size.width), NonZeroU32::new(size.height)) + else { + return; + }; + + // Either get the last context used or create a new one. + let mut gc = gc.borrow_mut(); + let surface = gc + .get_or_insert_with(|| GraphicsContext::new(window)) + .create_surface(window); + + // Fill a buffer with a solid color. + const DARK_GRAY: u32 = 0xFF181818; + + surface + .resize(width, height) + .expect("Failed to resize the softbuffer surface"); + + let mut buffer = surface + .buffer_mut() + .expect("Failed to get the softbuffer buffer"); + buffer.fill(DARK_GRAY); + buffer + .present() + .expect("Failed to present the softbuffer buffer"); + }) } - GC.with(|gc| { - let size = window.inner_size(); - let (Some(width), Some(height)) = - (NonZeroU32::new(size.width), NonZeroU32::new(size.height)) - else { - return; - }; - - // Either get the last context used or create a new one. - let mut gc = gc.borrow_mut(); - let surface = gc - .get_or_insert_with(|| GraphicsContext::new(window)) - .surface(window); - - // Fill a buffer with a solid color. - const DARK_GRAY: u32 = 0xFF181818; - - surface - .resize(width, height) - .expect("Failed to resize the softbuffer surface"); - - let mut buffer = surface - .buffer_mut() - .expect("Failed to get the softbuffer buffer"); - buffer.fill(DARK_GRAY); - buffer - .present() - .expect("Failed to present the softbuffer buffer"); - }) + #[allow(dead_code)] + pub fn cleanup_window(window: &Window) { + GC.with(|gc| { + let mut gc = gc.borrow_mut(); + if let Some(context) = gc.as_mut() { + context.destroy_surface(window); + } + }); + } } #[cfg(not(all(feature = "rwh_05", not(any(target_os = "android", target_os = "ios")))))] -pub(super) fn fill_window(_window: &Window) { - // No-op on mobile platforms. +mod platform { + pub fn fill_window(_window: &winit::window::Window) { + // No-op on mobile platforms. + } + + #[allow(dead_code)] + pub fn cleanup_window(_window: &winit::window::Window) { + // No-op on mobile platforms. + } } diff --git a/examples/window_on_demand.rs b/examples/window_on_demand.rs index ca9a448a..bb00416d 100644 --- a/examples/window_on_demand.rs +++ b/examples/window_on_demand.rs @@ -40,6 +40,7 @@ fn main() -> Result<(), impl std::error::Error> { window_id, } if window.id() == window_id => { println!("--------------------------------------------------------- Window {idx} CloseRequested"); + fill::cleanup_window(window); app.window = None; } Event::AboutToWait => window.request_redraw(), diff --git a/src/platform/run_on_demand.rs b/src/platform/run_on_demand.rs index 5326e92c..f7d1d525 100644 --- a/src/platform/run_on_demand.rs +++ b/src/platform/run_on_demand.rs @@ -76,6 +76,14 @@ impl EventLoopExtRunOnDemand for EventLoop { where F: FnMut(Event, &EventLoopWindowTarget), { + self.event_loop.window_target().clear_exit(); self.event_loop.run_on_demand(event_handler) } } + +impl EventLoopWindowTarget { + /// Clear exit status. + pub(crate) fn clear_exit(&self) { + self.p.clear_exit() + } +} diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index cf28c21b..22b05717 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -713,6 +713,10 @@ impl EventLoopWindowTarget { self.exit.set(true) } + pub(crate) fn clear_exit(&self) { + self.exit.set(false) + } + pub(crate) fn exiting(&self) -> bool { self.exit.get() } diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 0cfd3cb8..92eeb0d4 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -925,6 +925,10 @@ impl EventLoopWindowTarget { x11_or_wayland!(match self; Self(evlp) => evlp.control_flow()) } + pub(crate) fn clear_exit(&self) { + x11_or_wayland!(match self; Self(evlp) => evlp.clear_exit()) + } + pub(crate) fn exit(&self) { x11_or_wayland!(match self; Self(evlp) => evlp.exit()) } diff --git a/src/platform_impl/linux/wayland/event_loop/mod.rs b/src/platform_impl/linux/wayland/event_loop/mod.rs index 4b33cfa4..2ba3bb07 100644 --- a/src/platform_impl/linux/wayland/event_loop/mod.rs +++ b/src/platform_impl/linux/wayland/event_loop/mod.rs @@ -629,6 +629,34 @@ pub struct EventLoopWindowTarget { } impl EventLoopWindowTarget { + pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) { + self.control_flow.set(control_flow) + } + + pub(crate) fn control_flow(&self) -> ControlFlow { + self.control_flow.get() + } + + pub(crate) fn exit(&self) { + self.exit.set(Some(0)) + } + + pub(crate) fn clear_exit(&self) { + self.exit.set(None) + } + + pub(crate) fn exiting(&self) -> bool { + self.exit.get().is_some() + } + + pub(crate) fn set_exit_code(&self, code: i32) { + self.exit.set(Some(code)) + } + + pub(crate) fn exit_code(&self) -> Option { + self.exit.get() + } + #[inline] pub fn listen_device_events(&self, _allowed: DeviceEvents) {} diff --git a/src/platform_impl/linux/wayland/output.rs b/src/platform_impl/linux/wayland/output.rs index 4e288cdc..d6fe61bc 100644 --- a/src/platform_impl/linux/wayland/output.rs +++ b/src/platform_impl/linux/wayland/output.rs @@ -4,7 +4,6 @@ use sctk::reexports::client::Proxy; use sctk::output::OutputData; use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize}; -use crate::event_loop::ControlFlow; use crate::platform_impl::platform::VideoMode as PlatformVideoMode; use super::event_loop::EventLoopWindowTarget; @@ -24,30 +23,6 @@ impl EventLoopWindowTarget { // There's no primary monitor on Wayland. None } - - pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) { - self.control_flow.set(control_flow) - } - - pub(crate) fn control_flow(&self) -> ControlFlow { - self.control_flow.get() - } - - pub(crate) fn exit(&self) { - self.exit.set(Some(0)) - } - - pub(crate) fn exiting(&self) -> bool { - self.exit.get().is_some() - } - - pub(crate) fn set_exit_code(&self, code: i32) { - self.exit.set(Some(code)) - } - - pub(crate) fn exit_code(&self) -> Option { - self.exit.get() - } } #[derive(Clone, Debug)] diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index 6d8d9fd3..fc3a6456 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -752,6 +752,10 @@ impl EventLoopWindowTarget { self.exit.set(Some(0)) } + pub(crate) fn clear_exit(&self) { + self.exit.set(None) + } + pub(crate) fn exiting(&self) -> bool { self.exit.get().is_some() } diff --git a/src/platform_impl/macos/app_state.rs b/src/platform_impl/macos/app_state.rs index 3630b06b..023ab505 100644 --- a/src/platform_impl/macos/app_state.rs +++ b/src/platform_impl/macos/app_state.rs @@ -210,6 +210,10 @@ impl Handler { self.exit.store(true, Ordering::Relaxed) } + pub fn clear_exit(&self) { + self.exit.store(false, Ordering::Relaxed) + } + pub fn exiting(&self) -> bool { self.exit.load(Ordering::Relaxed) } @@ -435,6 +439,10 @@ impl AppState { HANDLER.exit() } + pub fn clear_exit() { + HANDLER.clear_exit() + } + pub fn exiting() -> bool { HANDLER.exiting() } diff --git a/src/platform_impl/macos/event_loop.rs b/src/platform_impl/macos/event_loop.rs index 7bce3aba..9a36783d 100644 --- a/src/platform_impl/macos/event_loop.rs +++ b/src/platform_impl/macos/event_loop.rs @@ -122,6 +122,10 @@ impl EventLoopWindowTarget { AppState::exit() } + pub(crate) fn clear_exit(&self) { + AppState::clear_exit() + } + pub(crate) fn exiting(&self) -> bool { AppState::exiting() } diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index b8b2e8eb..e9b35bcc 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -530,6 +530,10 @@ impl EventLoopWindowTarget { self.runner_shared.exit_code().is_some() } + pub(crate) fn clear_exit(&self) { + self.runner_shared.clear_exit(); + } + fn exit_code(&self) -> Option { self.runner_shared.exit_code() } diff --git a/src/platform_impl/windows/event_loop/runner.rs b/src/platform_impl/windows/event_loop/runner.rs index bb5eb56a..7486528d 100644 --- a/src/platform_impl/windows/event_loop/runner.rs +++ b/src/platform_impl/windows/event_loop/runner.rs @@ -163,6 +163,10 @@ impl EventLoopRunner { self.exit.get() } + pub fn clear_exit(&self) { + self.exit.set(None); + } + pub fn should_buffer(&self) -> bool { let handler = self.event_handler.take(); let should_buffer = handler.is_none();