diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index 82219b134c..0635e17235 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -12,6 +12,7 @@ //! The app's [runner](bevy_app::App::runner) is set by `WinitPlugin` and handles the `winit` [`EventLoop`]. //! See `winit_runner` for details. +use bevy_derive::Deref; use bevy_window::RawHandleWrapperHolder; use std::marker::PhantomData; use winit::event_loop::EventLoop; @@ -25,6 +26,7 @@ use bevy_ecs::prelude::*; use bevy_window::{exit_on_all_closed, Window, WindowCreated}; pub use system::create_windows; use system::{changed_windows, despawn_windows}; +pub use winit::event_loop::EventLoopProxy; pub use winit_config::*; pub use winit_event::*; pub use winit_windows::*; @@ -142,12 +144,14 @@ impl Plugin for WinitPlugin { #[derive(Debug, Default, Clone, Copy, Event)] pub struct WakeUp; -/// A re-export of [`winit::event_loop::EventLoopProxy`]. +/// A wrapper type around [`winit::event_loop::EventLoopProxy`] with the specific +/// [`winit::event::Event::UserEvent`] used in the [`WinitPlugin`]. /// /// The `EventLoopProxy` can be used to request a redraw from outside bevy. /// -/// Use `NonSend` to receive this resource. -pub type EventLoopProxy = winit::event_loop::EventLoopProxy; +/// Use `Res` to receive this resource. +#[derive(Resource, Deref)] +pub struct EventLoopProxyWrapper(winit::event_loop::EventLoopProxy); trait AppSendEvent { fn send(&mut self, event: impl Into); diff --git a/crates/bevy_winit/src/state.rs b/crates/bevy_winit/src/state.rs index 406aaa937d..6133eee6cf 100644 --- a/crates/bevy_winit/src/state.rs +++ b/crates/bevy_winit/src/state.rs @@ -37,8 +37,8 @@ use bevy_window::{PrimaryWindow, RawHandleWrapper}; use crate::accessibility::AccessKitAdapters; use crate::system::CachedWindow; use crate::{ - converters, create_windows, AppSendEvent, CreateWindowParams, UpdateMode, WinitEvent, - WinitSettings, WinitWindows, + converters, create_windows, AppSendEvent, CreateWindowParams, EventLoopProxyWrapper, + UpdateMode, WinitEvent, WinitSettings, WinitWindows, }; /// Persistent state that is used to run the [`App`] according to the current @@ -763,7 +763,7 @@ pub fn winit_runner(mut app: App) -> AppExit { .unwrap(); app.world_mut() - .insert_non_send_resource(event_loop.create_proxy()); + .insert_resource(EventLoopProxyWrapper(event_loop.create_proxy())); let mut runner_state = WinitAppRunnerState::new(app); diff --git a/examples/window/custom_user_event.rs b/examples/window/custom_user_event.rs index 6fe3c57d7a..a088697c25 100644 --- a/examples/window/custom_user_event.rs +++ b/examples/window/custom_user_event.rs @@ -1,9 +1,8 @@ //! Shows how to create a custom event that can be handled by `winit`'s event loop. use bevy::prelude::*; -use bevy::winit::{EventLoopProxy, WakeUp, WinitPlugin}; +use bevy::winit::{EventLoopProxyWrapper, WakeUp, WinitPlugin}; use std::fmt::Formatter; -use std::sync::OnceLock; #[derive(Default, Debug, Event)] enum CustomEvent { @@ -21,8 +20,6 @@ impl std::fmt::Display for CustomEvent { } } -static EVENT_LOOP_PROXY: OnceLock> = OnceLock::new(); - fn main() { let winit_plugin = WinitPlugin::::default(); @@ -39,7 +36,6 @@ fn main() { Startup, ( setup, - expose_event_loop_proxy, #[cfg(target_arch = "wasm32")] wasm::setup_js_closure, ), @@ -52,11 +48,10 @@ fn setup(mut commands: Commands) { commands.spawn(Camera2dBundle::default()); } -fn send_event(input: Res>) { - let Some(event_loop_proxy) = EVENT_LOOP_PROXY.get() else { - return; - }; - +fn send_event( + input: Res>, + event_loop_proxy: Res>, +) { if input.just_pressed(KeyCode::Space) { let _ = event_loop_proxy.send_event(CustomEvent::WakeUp); } @@ -64,18 +59,15 @@ fn send_event(input: Res>) { // This simulates sending a custom event through an external thread. #[cfg(not(target_arch = "wasm32"))] if input.just_pressed(KeyCode::KeyE) { - let handler = std::thread::spawn(|| { - let _ = event_loop_proxy.send_event(CustomEvent::Key('e')); + let event_loop_proxy = event_loop_proxy.clone(); + let handler = std::thread::spawn(move || { + let _ = event_loop_proxy.clone().send_event(CustomEvent::Key('e')); }); handler.join().unwrap(); } } -fn expose_event_loop_proxy(event_loop_proxy: NonSend>) { - EVENT_LOOP_PROXY.set((*event_loop_proxy).clone()).unwrap(); -} - fn handle_event(mut events: EventReader) { for evt in events.read() { info!("Received event: {evt:?}"); @@ -87,19 +79,21 @@ fn handle_event(mut events: EventReader) { /// the loop if that's currently waiting for a timeout or a user event. #[cfg(target_arch = "wasm32")] pub(crate) mod wasm { - use crate::{CustomEvent, EVENT_LOOP_PROXY}; + use super::*; + use bevy::winit::EventLoopProxy; use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; use web_sys::KeyboardEvent; - pub(crate) fn setup_js_closure() { + pub(crate) fn setup_js_closure(event_loop: Res>) { let window = web_sys::window().unwrap(); let document = window.document().unwrap(); + let event_loop = event_loop.clone(); let closure = Closure::wrap(Box::new(move |event: KeyboardEvent| { let key = event.key(); if key == "e" { - send_custom_event('e').unwrap(); + send_custom_event('e', &event_loop).unwrap(); } }) as Box); @@ -110,13 +104,9 @@ pub(crate) mod wasm { closure.forget(); } - fn send_custom_event(ch: char) -> Result<(), String> { - if let Some(proxy) = EVENT_LOOP_PROXY.get() { - proxy - .send_event(CustomEvent::Key(ch)) - .map_err(|_| "Failed to send event".to_string()) - } else { - Err("Event loop proxy not found".to_string()) - } + fn send_custom_event(ch: char, proxy: &EventLoopProxy) -> Result<(), String> { + proxy + .send_event(CustomEvent::Key(ch)) + .map_err(|_| "Failed to send event".to_string()) } } diff --git a/examples/window/low_power.rs b/examples/window/low_power.rs index 32d0da2230..4a612922a1 100644 --- a/examples/window/low_power.rs +++ b/examples/window/low_power.rs @@ -7,7 +7,7 @@ use bevy::{ prelude::*, utils::Duration, window::{PresentMode, RequestRedraw, WindowPlugin}, - winit::{EventLoopProxy, WakeUp, WinitSettings}, + winit::{EventLoopProxyWrapper, WakeUp, WinitSettings}, }; fn main() { @@ -55,7 +55,7 @@ enum ExampleMode { fn update_winit( mode: Res, mut winit_config: ResMut, - event_loop_proxy: NonSend>, + event_loop_proxy: Res>, mut redraw_request_events: EventWriter, ) { use ExampleMode::*;