mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
Remove need for EventLoopProxy to be NonSend (#14198)
# Objective - Continue to pare down the uses on NonSend resources in the engine. In this case, EventLoopProxy used to be `!Sync`, but is now `Sync` in the latest version of winit. ## Solution - New type `EventLoopProxy` as `EventLoopProxyWrapper` to make it into a normal resource. - Update the `custom_user_event` example as it no longer needs to indirectly access the `EventLoopProxy` through a static variable anymore. ## Testing - Ran the example. The resource exists just for users to use, so there aren't any in engine uses for it currently. --- ## Changelog - make EventLoopProxy into a regular resource. ## Migration Guide `EventLoopProxy` has been renamed to `EventLoopProxyWrapper` and is now `Send`, making it an ordinary resource. Before: ```rust event_loop_system(event_loop: NonSend<EventLoopProxy<MyEvent>>) { event_loop.send_event(MyEvent); } ``` After: ```rust event_loop_system(event_loop: Res<EventLoopProxy<MyEvent>>) { event_loop.send_event(MyEvent); } ```
This commit is contained in:
parent
1042f09c2e
commit
cfcb56f5b9
4 changed files with 29 additions and 35 deletions
|
@ -12,6 +12,7 @@
|
||||||
//! The app's [runner](bevy_app::App::runner) is set by `WinitPlugin` and handles the `winit` [`EventLoop`].
|
//! The app's [runner](bevy_app::App::runner) is set by `WinitPlugin` and handles the `winit` [`EventLoop`].
|
||||||
//! See `winit_runner` for details.
|
//! See `winit_runner` for details.
|
||||||
|
|
||||||
|
use bevy_derive::Deref;
|
||||||
use bevy_window::RawHandleWrapperHolder;
|
use bevy_window::RawHandleWrapperHolder;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use winit::event_loop::EventLoop;
|
use winit::event_loop::EventLoop;
|
||||||
|
@ -25,6 +26,7 @@ use bevy_ecs::prelude::*;
|
||||||
use bevy_window::{exit_on_all_closed, Window, WindowCreated};
|
use bevy_window::{exit_on_all_closed, Window, WindowCreated};
|
||||||
pub use system::create_windows;
|
pub use system::create_windows;
|
||||||
use system::{changed_windows, despawn_windows};
|
use system::{changed_windows, despawn_windows};
|
||||||
|
pub use winit::event_loop::EventLoopProxy;
|
||||||
pub use winit_config::*;
|
pub use winit_config::*;
|
||||||
pub use winit_event::*;
|
pub use winit_event::*;
|
||||||
pub use winit_windows::*;
|
pub use winit_windows::*;
|
||||||
|
@ -142,12 +144,14 @@ impl<T: Event> Plugin for WinitPlugin<T> {
|
||||||
#[derive(Debug, Default, Clone, Copy, Event)]
|
#[derive(Debug, Default, Clone, Copy, Event)]
|
||||||
pub struct WakeUp;
|
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.
|
/// The `EventLoopProxy` can be used to request a redraw from outside bevy.
|
||||||
///
|
///
|
||||||
/// Use `NonSend<EventLoopProxy>` to receive this resource.
|
/// Use `Res<EventLoopProxy>` to receive this resource.
|
||||||
pub type EventLoopProxy<T> = winit::event_loop::EventLoopProxy<T>;
|
#[derive(Resource, Deref)]
|
||||||
|
pub struct EventLoopProxyWrapper<T: 'static>(winit::event_loop::EventLoopProxy<T>);
|
||||||
|
|
||||||
trait AppSendEvent {
|
trait AppSendEvent {
|
||||||
fn send(&mut self, event: impl Into<WinitEvent>);
|
fn send(&mut self, event: impl Into<WinitEvent>);
|
||||||
|
|
|
@ -37,8 +37,8 @@ use bevy_window::{PrimaryWindow, RawHandleWrapper};
|
||||||
use crate::accessibility::AccessKitAdapters;
|
use crate::accessibility::AccessKitAdapters;
|
||||||
use crate::system::CachedWindow;
|
use crate::system::CachedWindow;
|
||||||
use crate::{
|
use crate::{
|
||||||
converters, create_windows, AppSendEvent, CreateWindowParams, UpdateMode, WinitEvent,
|
converters, create_windows, AppSendEvent, CreateWindowParams, EventLoopProxyWrapper,
|
||||||
WinitSettings, WinitWindows,
|
UpdateMode, WinitEvent, WinitSettings, WinitWindows,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Persistent state that is used to run the [`App`] according to the current
|
/// Persistent state that is used to run the [`App`] according to the current
|
||||||
|
@ -763,7 +763,7 @@ pub fn winit_runner<T: Event>(mut app: App) -> AppExit {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
app.world_mut()
|
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);
|
let mut runner_state = WinitAppRunnerState::new(app);
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
//! Shows how to create a custom event that can be handled by `winit`'s event loop.
|
//! Shows how to create a custom event that can be handled by `winit`'s event loop.
|
||||||
|
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy::winit::{EventLoopProxy, WakeUp, WinitPlugin};
|
use bevy::winit::{EventLoopProxyWrapper, WakeUp, WinitPlugin};
|
||||||
use std::fmt::Formatter;
|
use std::fmt::Formatter;
|
||||||
use std::sync::OnceLock;
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Event)]
|
#[derive(Default, Debug, Event)]
|
||||||
enum CustomEvent {
|
enum CustomEvent {
|
||||||
|
@ -21,8 +20,6 @@ impl std::fmt::Display for CustomEvent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static EVENT_LOOP_PROXY: OnceLock<EventLoopProxy<CustomEvent>> = OnceLock::new();
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let winit_plugin = WinitPlugin::<CustomEvent>::default();
|
let winit_plugin = WinitPlugin::<CustomEvent>::default();
|
||||||
|
|
||||||
|
@ -39,7 +36,6 @@ fn main() {
|
||||||
Startup,
|
Startup,
|
||||||
(
|
(
|
||||||
setup,
|
setup,
|
||||||
expose_event_loop_proxy,
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
wasm::setup_js_closure,
|
wasm::setup_js_closure,
|
||||||
),
|
),
|
||||||
|
@ -52,11 +48,10 @@ fn setup(mut commands: Commands) {
|
||||||
commands.spawn(Camera2dBundle::default());
|
commands.spawn(Camera2dBundle::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_event(input: Res<ButtonInput<KeyCode>>) {
|
fn send_event(
|
||||||
let Some(event_loop_proxy) = EVENT_LOOP_PROXY.get() else {
|
input: Res<ButtonInput<KeyCode>>,
|
||||||
return;
|
event_loop_proxy: Res<EventLoopProxyWrapper<CustomEvent>>,
|
||||||
};
|
) {
|
||||||
|
|
||||||
if input.just_pressed(KeyCode::Space) {
|
if input.just_pressed(KeyCode::Space) {
|
||||||
let _ = event_loop_proxy.send_event(CustomEvent::WakeUp);
|
let _ = event_loop_proxy.send_event(CustomEvent::WakeUp);
|
||||||
}
|
}
|
||||||
|
@ -64,18 +59,15 @@ fn send_event(input: Res<ButtonInput<KeyCode>>) {
|
||||||
// This simulates sending a custom event through an external thread.
|
// This simulates sending a custom event through an external thread.
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
if input.just_pressed(KeyCode::KeyE) {
|
if input.just_pressed(KeyCode::KeyE) {
|
||||||
let handler = std::thread::spawn(|| {
|
let event_loop_proxy = event_loop_proxy.clone();
|
||||||
let _ = event_loop_proxy.send_event(CustomEvent::Key('e'));
|
let handler = std::thread::spawn(move || {
|
||||||
|
let _ = event_loop_proxy.clone().send_event(CustomEvent::Key('e'));
|
||||||
});
|
});
|
||||||
|
|
||||||
handler.join().unwrap();
|
handler.join().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expose_event_loop_proxy(event_loop_proxy: NonSend<EventLoopProxy<CustomEvent>>) {
|
|
||||||
EVENT_LOOP_PROXY.set((*event_loop_proxy).clone()).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_event(mut events: EventReader<CustomEvent>) {
|
fn handle_event(mut events: EventReader<CustomEvent>) {
|
||||||
for evt in events.read() {
|
for evt in events.read() {
|
||||||
info!("Received event: {evt:?}");
|
info!("Received event: {evt:?}");
|
||||||
|
@ -87,19 +79,21 @@ fn handle_event(mut events: EventReader<CustomEvent>) {
|
||||||
/// the loop if that's currently waiting for a timeout or a user event.
|
/// the loop if that's currently waiting for a timeout or a user event.
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
pub(crate) mod wasm {
|
pub(crate) mod wasm {
|
||||||
use crate::{CustomEvent, EVENT_LOOP_PROXY};
|
use super::*;
|
||||||
|
use bevy::winit::EventLoopProxy;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
use web_sys::KeyboardEvent;
|
use web_sys::KeyboardEvent;
|
||||||
|
|
||||||
pub(crate) fn setup_js_closure() {
|
pub(crate) fn setup_js_closure(event_loop: Res<EventLoopProxyWrapper<CustomEvent>>) {
|
||||||
let window = web_sys::window().unwrap();
|
let window = web_sys::window().unwrap();
|
||||||
let document = window.document().unwrap();
|
let document = window.document().unwrap();
|
||||||
|
|
||||||
|
let event_loop = event_loop.clone();
|
||||||
let closure = Closure::wrap(Box::new(move |event: KeyboardEvent| {
|
let closure = Closure::wrap(Box::new(move |event: KeyboardEvent| {
|
||||||
let key = event.key();
|
let key = event.key();
|
||||||
if key == "e" {
|
if key == "e" {
|
||||||
send_custom_event('e').unwrap();
|
send_custom_event('e', &event_loop).unwrap();
|
||||||
}
|
}
|
||||||
}) as Box<dyn FnMut(KeyboardEvent)>);
|
}) as Box<dyn FnMut(KeyboardEvent)>);
|
||||||
|
|
||||||
|
@ -110,13 +104,9 @@ pub(crate) mod wasm {
|
||||||
closure.forget();
|
closure.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_custom_event(ch: char) -> Result<(), String> {
|
fn send_custom_event(ch: char, proxy: &EventLoopProxy<CustomEvent>) -> Result<(), String> {
|
||||||
if let Some(proxy) = EVENT_LOOP_PROXY.get() {
|
proxy
|
||||||
proxy
|
.send_event(CustomEvent::Key(ch))
|
||||||
.send_event(CustomEvent::Key(ch))
|
.map_err(|_| "Failed to send event".to_string())
|
||||||
.map_err(|_| "Failed to send event".to_string())
|
|
||||||
} else {
|
|
||||||
Err("Event loop proxy not found".to_string())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use bevy::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
utils::Duration,
|
utils::Duration,
|
||||||
window::{PresentMode, RequestRedraw, WindowPlugin},
|
window::{PresentMode, RequestRedraw, WindowPlugin},
|
||||||
winit::{EventLoopProxy, WakeUp, WinitSettings},
|
winit::{EventLoopProxyWrapper, WakeUp, WinitSettings},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -55,7 +55,7 @@ enum ExampleMode {
|
||||||
fn update_winit(
|
fn update_winit(
|
||||||
mode: Res<ExampleMode>,
|
mode: Res<ExampleMode>,
|
||||||
mut winit_config: ResMut<WinitSettings>,
|
mut winit_config: ResMut<WinitSettings>,
|
||||||
event_loop_proxy: NonSend<EventLoopProxy<WakeUp>>,
|
event_loop_proxy: Res<EventLoopProxyWrapper<WakeUp>>,
|
||||||
mut redraw_request_events: EventWriter<RequestRedraw>,
|
mut redraw_request_events: EventWriter<RequestRedraw>,
|
||||||
) {
|
) {
|
||||||
use ExampleMode::*;
|
use ExampleMode::*;
|
||||||
|
|
Loading…
Reference in a new issue