Remove remaining internal use of !Send
resources (#18386)
# Objective Remaining work for and closes #17682. First half of work for that issue was completed in [PR 17730](https://github.com/bevyengine/bevy/pull/17730). However, the rest of the work ended up getting blocked because we needed a way of forcing systems to run on the main thread without the use of `!Send` resources. That was unblocked by [PR 18301](https://github.com/bevyengine/bevy/pull/18301). This work should finish unblocking the resources-as-components effort. # Testing Ran several examples using my Linux machine, just to make sure things are working as expected and no surprises pop up. --------- Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com> Co-authored-by: François Mockers <francois.mockers@vleue.com>
This commit is contained in:
parent
7b1c9f192e
commit
770f10bc19
@ -117,3 +117,22 @@ impl Plugin for GilrsPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
// Regression test for https://github.com/bevyengine/bevy/issues/17697
|
||||||
|
#[test]
|
||||||
|
fn world_is_truly_send() {
|
||||||
|
let mut app = App::new();
|
||||||
|
app.add_plugins(GilrsPlugin);
|
||||||
|
let world = core::mem::take(app.world_mut());
|
||||||
|
|
||||||
|
let handler = std::thread::spawn(move || {
|
||||||
|
drop(world);
|
||||||
|
});
|
||||||
|
|
||||||
|
handler.join().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use alloc::{collections::VecDeque, sync::Arc};
|
use alloc::{collections::VecDeque, sync::Arc};
|
||||||
use bevy_input_focus::InputFocus;
|
use bevy_input_focus::InputFocus;
|
||||||
|
use core::cell::RefCell;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use winit::event_loop::ActiveEventLoop;
|
use winit::event_loop::ActiveEventLoop;
|
||||||
|
|
||||||
@ -16,13 +17,26 @@ use bevy_a11y::{
|
|||||||
};
|
};
|
||||||
use bevy_app::{App, Plugin, PostUpdate};
|
use bevy_app::{App, Plugin, PostUpdate};
|
||||||
use bevy_derive::{Deref, DerefMut};
|
use bevy_derive::{Deref, DerefMut};
|
||||||
use bevy_ecs::{entity::EntityHashMap, prelude::*};
|
use bevy_ecs::{entity::EntityHashMap, prelude::*, system::NonSendMarker};
|
||||||
use bevy_window::{PrimaryWindow, Window, WindowClosed};
|
use bevy_window::{PrimaryWindow, Window, WindowClosed};
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
/// Temporary storage of access kit adapter data to replace usage of `!Send` resources. This will be replaced with proper
|
||||||
|
/// storage of `!Send` data after issue #17667 is complete.
|
||||||
|
pub static ACCESS_KIT_ADAPTERS: RefCell<AccessKitAdapters> = const { RefCell::new(AccessKitAdapters::new()) };
|
||||||
|
}
|
||||||
|
|
||||||
/// Maps window entities to their `AccessKit` [`Adapter`]s.
|
/// Maps window entities to their `AccessKit` [`Adapter`]s.
|
||||||
#[derive(Default, Deref, DerefMut)]
|
#[derive(Default, Deref, DerefMut)]
|
||||||
pub struct AccessKitAdapters(pub EntityHashMap<Adapter>);
|
pub struct AccessKitAdapters(pub EntityHashMap<Adapter>);
|
||||||
|
|
||||||
|
impl AccessKitAdapters {
|
||||||
|
/// Creates a new empty `AccessKitAdapters`.
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self(EntityHashMap::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Maps window entities to their respective [`ActionRequest`]s.
|
/// Maps window entities to their respective [`ActionRequest`]s.
|
||||||
#[derive(Resource, Default, Deref, DerefMut)]
|
#[derive(Resource, Default, Deref, DerefMut)]
|
||||||
pub struct WinitActionRequestHandlers(pub EntityHashMap<Arc<Mutex<WinitActionRequestHandler>>>);
|
pub struct WinitActionRequestHandlers(pub EntityHashMap<Arc<Mutex<WinitActionRequestHandler>>>);
|
||||||
@ -144,14 +158,16 @@ pub(crate) fn prepare_accessibility_for_window(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn window_closed(
|
fn window_closed(
|
||||||
mut adapters: NonSendMut<AccessKitAdapters>,
|
|
||||||
mut handlers: ResMut<WinitActionRequestHandlers>,
|
mut handlers: ResMut<WinitActionRequestHandlers>,
|
||||||
mut events: EventReader<WindowClosed>,
|
mut events: EventReader<WindowClosed>,
|
||||||
|
_non_send_marker: NonSendMarker,
|
||||||
) {
|
) {
|
||||||
|
ACCESS_KIT_ADAPTERS.with_borrow_mut(|adapters| {
|
||||||
for WindowClosed { window, .. } in events.read() {
|
for WindowClosed { window, .. } in events.read() {
|
||||||
adapters.remove(window);
|
adapters.remove(window);
|
||||||
handlers.remove(window);
|
handlers.remove(window);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_receivers(
|
fn poll_receivers(
|
||||||
@ -174,7 +190,6 @@ fn should_update_accessibility_nodes(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update_accessibility_nodes(
|
fn update_accessibility_nodes(
|
||||||
mut adapters: NonSendMut<AccessKitAdapters>,
|
|
||||||
focus: Option<Res<InputFocus>>,
|
focus: Option<Res<InputFocus>>,
|
||||||
primary_window: Query<(Entity, &Window), With<PrimaryWindow>>,
|
primary_window: Query<(Entity, &Window), With<PrimaryWindow>>,
|
||||||
nodes: Query<(
|
nodes: Query<(
|
||||||
@ -184,7 +199,9 @@ fn update_accessibility_nodes(
|
|||||||
Option<&ChildOf>,
|
Option<&ChildOf>,
|
||||||
)>,
|
)>,
|
||||||
node_entities: Query<Entity, With<AccessibilityNode>>,
|
node_entities: Query<Entity, With<AccessibilityNode>>,
|
||||||
|
_non_send_marker: NonSendMarker,
|
||||||
) {
|
) {
|
||||||
|
ACCESS_KIT_ADAPTERS.with_borrow_mut(|adapters| {
|
||||||
let Ok((primary_window_id, primary_window)) = primary_window.single() else {
|
let Ok((primary_window_id, primary_window)) = primary_window.single() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@ -213,6 +230,7 @@ fn update_accessibility_nodes(
|
|||||||
)
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_adapter(
|
fn update_adapter(
|
||||||
@ -290,8 +308,7 @@ pub struct AccessKitPlugin;
|
|||||||
|
|
||||||
impl Plugin for AccessKitPlugin {
|
impl Plugin for AccessKitPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.init_non_send_resource::<AccessKitAdapters>()
|
app.init_resource::<WinitActionRequestHandlers>()
|
||||||
.init_resource::<WinitActionRequestHandlers>()
|
|
||||||
.add_event::<ActionRequestWrapper>()
|
.add_event::<ActionRequestWrapper>()
|
||||||
.add_systems(
|
.add_systems(
|
||||||
PostUpdate,
|
PostUpdate,
|
||||||
|
@ -18,6 +18,7 @@ use bevy_derive::Deref;
|
|||||||
use bevy_reflect::prelude::ReflectDefault;
|
use bevy_reflect::prelude::ReflectDefault;
|
||||||
use bevy_reflect::Reflect;
|
use bevy_reflect::Reflect;
|
||||||
use bevy_window::{RawHandleWrapperHolder, WindowEvent};
|
use bevy_window::{RawHandleWrapperHolder, WindowEvent};
|
||||||
|
use core::cell::RefCell;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use winit::{event_loop::EventLoop, window::WindowId};
|
use winit::{event_loop::EventLoop, window::WindowId};
|
||||||
|
|
||||||
@ -37,7 +38,7 @@ pub use winit_config::*;
|
|||||||
pub use winit_windows::*;
|
pub use winit_windows::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
accessibility::{AccessKitAdapters, AccessKitPlugin, WinitActionRequestHandlers},
|
accessibility::{AccessKitPlugin, WinitActionRequestHandlers},
|
||||||
state::winit_runner,
|
state::winit_runner,
|
||||||
winit_monitors::WinitMonitors,
|
winit_monitors::WinitMonitors,
|
||||||
};
|
};
|
||||||
@ -53,6 +54,10 @@ mod winit_config;
|
|||||||
mod winit_monitors;
|
mod winit_monitors;
|
||||||
mod winit_windows;
|
mod winit_windows;
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
static WINIT_WINDOWS: RefCell<WinitWindows> = const { RefCell::new(WinitWindows::new()) };
|
||||||
|
}
|
||||||
|
|
||||||
/// A [`Plugin`] that uses `winit` to create and manage windows, and receive window and input
|
/// A [`Plugin`] that uses `winit` to create and manage windows, and receive window and input
|
||||||
/// events.
|
/// events.
|
||||||
///
|
///
|
||||||
@ -124,8 +129,7 @@ impl<T: Event> Plugin for WinitPlugin<T> {
|
|||||||
.build()
|
.build()
|
||||||
.expect("Failed to build event loop");
|
.expect("Failed to build event loop");
|
||||||
|
|
||||||
app.init_non_send_resource::<WinitWindows>()
|
app.init_resource::<WinitMonitors>()
|
||||||
.init_resource::<WinitMonitors>()
|
|
||||||
.init_resource::<WinitSettings>()
|
.init_resource::<WinitSettings>()
|
||||||
.insert_resource(DisplayHandleWrapper(event_loop.owned_display_handle()))
|
.insert_resource(DisplayHandleWrapper(event_loop.owned_display_handle()))
|
||||||
.add_event::<RawWinitWindowEvent>()
|
.add_event::<RawWinitWindowEvent>()
|
||||||
@ -210,8 +214,6 @@ pub type CreateWindowParams<'w, 's, F = ()> = (
|
|||||||
F,
|
F,
|
||||||
>,
|
>,
|
||||||
EventWriter<'w, WindowCreated>,
|
EventWriter<'w, WindowCreated>,
|
||||||
NonSendMut<'w, WinitWindows>,
|
|
||||||
NonSendMut<'w, AccessKitAdapters>,
|
|
||||||
ResMut<'w, WinitActionRequestHandlers>,
|
ResMut<'w, WinitActionRequestHandlers>,
|
||||||
Res<'w, AccessibilityRequested>,
|
Res<'w, AccessibilityRequested>,
|
||||||
Res<'w, WinitMonitors>,
|
Res<'w, WinitMonitors>,
|
||||||
|
@ -3,7 +3,7 @@ use bevy_app::{App, AppExit, PluginsState};
|
|||||||
#[cfg(feature = "custom_cursor")]
|
#[cfg(feature = "custom_cursor")]
|
||||||
use bevy_asset::AssetId;
|
use bevy_asset::AssetId;
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
change_detection::{DetectChanges, NonSendMut, Res},
|
change_detection::{DetectChanges, Res},
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
event::{EventCursor, EventWriter},
|
event::{EventCursor, EventWriter},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
@ -49,11 +49,11 @@ use bevy_window::{
|
|||||||
use bevy_window::{PrimaryWindow, RawHandleWrapper};
|
use bevy_window::{PrimaryWindow, RawHandleWrapper};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
accessibility::AccessKitAdapters,
|
accessibility::ACCESS_KIT_ADAPTERS,
|
||||||
converters, create_windows,
|
converters, create_windows,
|
||||||
system::{create_monitors, CachedWindow, WinitWindowPressedKeys},
|
system::{create_monitors, CachedWindow, WinitWindowPressedKeys},
|
||||||
AppSendEvent, CreateMonitorParams, CreateWindowParams, EventLoopProxyWrapper,
|
AppSendEvent, CreateMonitorParams, CreateWindowParams, EventLoopProxyWrapper,
|
||||||
RawWinitWindowEvent, UpdateMode, WinitSettings, WinitWindows,
|
RawWinitWindowEvent, UpdateMode, WinitSettings, WINIT_WINDOWS,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// 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
|
||||||
@ -94,7 +94,6 @@ struct WinitAppRunnerState<T: Event> {
|
|||||||
EventWriter<'static, WindowResized>,
|
EventWriter<'static, WindowResized>,
|
||||||
EventWriter<'static, WindowBackendScaleFactorChanged>,
|
EventWriter<'static, WindowBackendScaleFactorChanged>,
|
||||||
EventWriter<'static, WindowScaleFactorChanged>,
|
EventWriter<'static, WindowScaleFactorChanged>,
|
||||||
NonSend<'static, WinitWindows>,
|
|
||||||
Query<
|
Query<
|
||||||
'static,
|
'static,
|
||||||
'static,
|
'static,
|
||||||
@ -104,7 +103,6 @@ struct WinitAppRunnerState<T: Event> {
|
|||||||
&'static mut WinitWindowPressedKeys,
|
&'static mut WinitWindowPressedKeys,
|
||||||
),
|
),
|
||||||
>,
|
>,
|
||||||
NonSendMut<'static, AccessKitAdapters>,
|
|
||||||
)>,
|
)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,9 +115,7 @@ impl<T: Event> WinitAppRunnerState<T> {
|
|||||||
EventWriter<WindowResized>,
|
EventWriter<WindowResized>,
|
||||||
EventWriter<WindowBackendScaleFactorChanged>,
|
EventWriter<WindowBackendScaleFactorChanged>,
|
||||||
EventWriter<WindowScaleFactorChanged>,
|
EventWriter<WindowScaleFactorChanged>,
|
||||||
NonSend<WinitWindows>,
|
|
||||||
Query<(&mut Window, &mut CachedWindow, &mut WinitWindowPressedKeys)>,
|
Query<(&mut Window, &mut CachedWindow, &mut WinitWindowPressedKeys)>,
|
||||||
NonSendMut<AccessKitAdapters>,
|
|
||||||
)> = SystemState::new(app.world_mut());
|
)> = SystemState::new(app.world_mut());
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@ -255,13 +251,19 @@ impl<T: Event> ApplicationHandler<T> for WinitAppRunnerState<T> {
|
|||||||
) {
|
) {
|
||||||
self.window_event_received = true;
|
self.window_event_received = true;
|
||||||
|
|
||||||
|
#[cfg_attr(
|
||||||
|
not(target_os = "windows"),
|
||||||
|
expect(unused_mut, reason = "only needs to be mut on windows for now")
|
||||||
|
)]
|
||||||
|
let mut manual_run_redraw_requested = false;
|
||||||
|
|
||||||
|
WINIT_WINDOWS.with_borrow(|winit_windows| {
|
||||||
|
ACCESS_KIT_ADAPTERS.with_borrow_mut(|access_kit_adapters| {
|
||||||
let (
|
let (
|
||||||
mut window_resized,
|
mut window_resized,
|
||||||
mut window_backend_scale_factor_changed,
|
mut window_backend_scale_factor_changed,
|
||||||
mut window_scale_factor_changed,
|
mut window_scale_factor_changed,
|
||||||
winit_windows,
|
|
||||||
mut windows,
|
mut windows,
|
||||||
mut access_kit_adapters,
|
|
||||||
) = self.event_writer_system_state.get_mut(self.app.world_mut());
|
) = self.event_writer_system_state.get_mut(self.app.world_mut());
|
||||||
|
|
||||||
let Some(window) = winit_windows.get_window_entity(window_id) else {
|
let Some(window) = winit_windows.get_window_entity(window_id) else {
|
||||||
@ -270,7 +272,9 @@ impl<T: Event> ApplicationHandler<T> for WinitAppRunnerState<T> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let Ok((mut win, _, mut pressed_keys)) = windows.get_mut(window) else {
|
let Ok((mut win, _, mut pressed_keys)) = windows.get_mut(window) else {
|
||||||
warn!("Window {window:?} is missing `Window` component, skipping event {event:?}");
|
warn!(
|
||||||
|
"Window {window:?} is missing `Window` component, skipping event {event:?}"
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -315,9 +319,10 @@ impl<T: Event> ApplicationHandler<T> for WinitAppRunnerState<T> {
|
|||||||
} => {
|
} => {
|
||||||
let keyboard_input = converters::convert_keyboard_input(event, window);
|
let keyboard_input = converters::convert_keyboard_input(event, window);
|
||||||
if event.state.is_pressed() {
|
if event.state.is_pressed() {
|
||||||
pressed_keys
|
pressed_keys.0.insert(
|
||||||
.0
|
keyboard_input.key_code,
|
||||||
.insert(keyboard_input.key_code, keyboard_input.logical_key.clone());
|
keyboard_input.logical_key.clone(),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
pressed_keys.0.remove(&keyboard_input.key_code);
|
pressed_keys.0.remove(&keyboard_input.key_code);
|
||||||
}
|
}
|
||||||
@ -332,7 +337,8 @@ impl<T: Event> ApplicationHandler<T> for WinitAppRunnerState<T> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
win.set_physical_cursor_position(Some(physical_position));
|
win.set_physical_cursor_position(Some(physical_position));
|
||||||
let position = (physical_position / win.resolution.scale_factor() as f64).as_vec2();
|
let position =
|
||||||
|
(physical_position / win.resolution.scale_factor() as f64).as_vec2();
|
||||||
self.bevy_window_events.send(CursorMoved {
|
self.bevy_window_events.send(CursorMoved {
|
||||||
window,
|
window,
|
||||||
position,
|
position,
|
||||||
@ -456,7 +462,7 @@ impl<T: Event> ApplicationHandler<T> for WinitAppRunnerState<T> {
|
|||||||
// Have the startup behavior run in about_to_wait, which prevents issues with
|
// Have the startup behavior run in about_to_wait, which prevents issues with
|
||||||
// invisible window creation. https://github.com/bevyengine/bevy/issues/18027
|
// invisible window creation. https://github.com/bevyengine/bevy/issues/18027
|
||||||
if self.startup_forced_updates == 0 {
|
if self.startup_forced_updates == 0 {
|
||||||
self.redraw_requested(_event_loop);
|
manual_run_redraw_requested = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -464,11 +470,18 @@ impl<T: Event> ApplicationHandler<T> for WinitAppRunnerState<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut windows = self.world_mut().query::<(&mut Window, &mut CachedWindow)>();
|
let mut windows = self.world_mut().query::<(&mut Window, &mut CachedWindow)>();
|
||||||
if let Ok((window_component, mut cache)) = windows.get_mut(self.world_mut(), window) {
|
if let Ok((window_component, mut cache)) = windows.get_mut(self.world_mut(), window)
|
||||||
|
{
|
||||||
if window_component.is_changed() {
|
if window_component.is_changed() {
|
||||||
cache.window = window_component.clone();
|
cache.window = window_component.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if manual_run_redraw_requested {
|
||||||
|
self.redraw_requested(_event_loop);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn device_event(
|
fn device_event(
|
||||||
@ -506,7 +519,7 @@ impl<T: Event> ApplicationHandler<T> for WinitAppRunnerState<T> {
|
|||||||
// invisible window creation. https://github.com/bevyengine/bevy/issues/18027
|
// invisible window creation. https://github.com/bevyengine/bevy/issues/18027
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
{
|
{
|
||||||
let winit_windows = self.world().non_send_resource::<WinitWindows>();
|
WINIT_WINDOWS.with_borrow(|winit_windows| {
|
||||||
let headless = winit_windows.windows.is_empty();
|
let headless = winit_windows.windows.is_empty();
|
||||||
let exiting = self.app_exit.is_some();
|
let exiting = self.app_exit.is_some();
|
||||||
let reactive = matches!(self.update_mode, UpdateMode::Reactive { .. });
|
let reactive = matches!(self.update_mode, UpdateMode::Reactive { .. });
|
||||||
@ -519,6 +532,7 @@ impl<T: Event> ApplicationHandler<T> for WinitAppRunnerState<T> {
|
|||||||
{
|
{
|
||||||
self.redraw_requested(event_loop);
|
self.redraw_requested(event_loop);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -591,27 +605,23 @@ impl<T: Event> WinitAppRunnerState<T> {
|
|||||||
// Get windows that are cached but without raw handles. Those window were already created, but got their
|
// Get windows that are cached but without raw handles. Those window were already created, but got their
|
||||||
// handle wrapper removed when the app was suspended.
|
// handle wrapper removed when the app was suspended.
|
||||||
let mut query = self.world_mut()
|
let mut query = self.world_mut()
|
||||||
.query_filtered::<(Entity, &Window), (With<CachedWindow>, Without<bevy_window::RawHandleWrapper>)>();
|
.query_filtered::<(Entity, &Window), (With<CachedWindow>, Without<RawHandleWrapper>)>();
|
||||||
if let Ok((entity, window)) = query.single(&self.world()) {
|
if let Ok((entity, window)) = query.single(&self.world()) {
|
||||||
let window = window.clone();
|
let window = window.clone();
|
||||||
|
|
||||||
|
WINIT_WINDOWS.with_borrow_mut(|winit_windows| {
|
||||||
|
ACCESS_KIT_ADAPTERS.with_borrow_mut(|adapters| {
|
||||||
let mut create_window =
|
let mut create_window =
|
||||||
SystemState::<CreateWindowParams>::from_world(self.world_mut());
|
SystemState::<CreateWindowParams>::from_world(self.world_mut());
|
||||||
|
|
||||||
let (
|
let (.., mut handlers, accessibility_requested, monitors) =
|
||||||
..,
|
create_window.get_mut(self.world_mut());
|
||||||
mut winit_windows,
|
|
||||||
mut adapters,
|
|
||||||
mut handlers,
|
|
||||||
accessibility_requested,
|
|
||||||
monitors,
|
|
||||||
) = create_window.get_mut(self.world_mut());
|
|
||||||
|
|
||||||
let winit_window = winit_windows.create_window(
|
let winit_window = winit_windows.create_window(
|
||||||
event_loop,
|
event_loop,
|
||||||
entity,
|
entity,
|
||||||
&window,
|
&window,
|
||||||
&mut adapters,
|
adapters,
|
||||||
&mut handlers,
|
&mut handlers,
|
||||||
&accessibility_requested,
|
&accessibility_requested,
|
||||||
&monitors,
|
&monitors,
|
||||||
@ -620,6 +630,8 @@ impl<T: Event> WinitAppRunnerState<T> {
|
|||||||
let wrapper = RawHandleWrapper::new(winit_window).unwrap();
|
let wrapper = RawHandleWrapper::new(winit_window).unwrap();
|
||||||
|
|
||||||
self.world_mut().entity_mut(entity).insert(wrapper);
|
self.world_mut().entity_mut(entity).insert(wrapper);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -684,9 +696,10 @@ impl<T: Event> WinitAppRunnerState<T> {
|
|||||||
all(target_os = "linux", any(feature = "x11", feature = "wayland"))
|
all(target_os = "linux", any(feature = "x11", feature = "wayland"))
|
||||||
)))]
|
)))]
|
||||||
{
|
{
|
||||||
let winit_windows = self.world().non_send_resource::<WinitWindows>();
|
let visible = WINIT_WINDOWS.with_borrow(|winit_windows| {
|
||||||
let visible = winit_windows.windows.iter().any(|(_, w)| {
|
winit_windows.windows.iter().any(|(_, w)| {
|
||||||
w.is_visible().unwrap_or(false)
|
w.is_visible().unwrap_or(false)
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
event_loop.set_control_flow(if visible {
|
event_loop.set_control_flow(if visible {
|
||||||
@ -716,10 +729,11 @@ impl<T: Event> WinitAppRunnerState<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.redraw_requested && self.lifecycle != AppLifecycle::Suspended {
|
if self.redraw_requested && self.lifecycle != AppLifecycle::Suspended {
|
||||||
let winit_windows = self.world().non_send_resource::<WinitWindows>();
|
WINIT_WINDOWS.with_borrow(|winit_windows| {
|
||||||
for window in winit_windows.windows.values() {
|
for window in winit_windows.windows.values() {
|
||||||
window.request_redraw();
|
window.request_redraw();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
self.redraw_requested = false;
|
self.redraw_requested = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -871,21 +885,19 @@ impl<T: Event> WinitAppRunnerState<T> {
|
|||||||
fn update_cursors(&mut self, #[cfg(feature = "custom_cursor")] event_loop: &ActiveEventLoop) {
|
fn update_cursors(&mut self, #[cfg(feature = "custom_cursor")] event_loop: &ActiveEventLoop) {
|
||||||
#[cfg(feature = "custom_cursor")]
|
#[cfg(feature = "custom_cursor")]
|
||||||
let mut windows_state: SystemState<(
|
let mut windows_state: SystemState<(
|
||||||
NonSendMut<WinitWindows>,
|
|
||||||
ResMut<CustomCursorCache>,
|
ResMut<CustomCursorCache>,
|
||||||
Query<(Entity, &mut PendingCursor), Changed<PendingCursor>>,
|
Query<(Entity, &mut PendingCursor), Changed<PendingCursor>>,
|
||||||
)> = SystemState::new(self.world_mut());
|
)> = SystemState::new(self.world_mut());
|
||||||
#[cfg(feature = "custom_cursor")]
|
#[cfg(feature = "custom_cursor")]
|
||||||
let (winit_windows, mut cursor_cache, mut windows) =
|
let (mut cursor_cache, mut windows) = windows_state.get_mut(self.world_mut());
|
||||||
windows_state.get_mut(self.world_mut());
|
|
||||||
#[cfg(not(feature = "custom_cursor"))]
|
#[cfg(not(feature = "custom_cursor"))]
|
||||||
let mut windows_state: SystemState<(
|
let mut windows_state: SystemState<(
|
||||||
NonSendMut<WinitWindows>,
|
|
||||||
Query<(Entity, &mut PendingCursor), Changed<PendingCursor>>,
|
Query<(Entity, &mut PendingCursor), Changed<PendingCursor>>,
|
||||||
)> = SystemState::new(self.world_mut());
|
)> = SystemState::new(self.world_mut());
|
||||||
#[cfg(not(feature = "custom_cursor"))]
|
#[cfg(not(feature = "custom_cursor"))]
|
||||||
let (winit_windows, mut windows) = windows_state.get_mut(self.world_mut());
|
let (mut windows,) = windows_state.get_mut(self.world_mut());
|
||||||
|
|
||||||
|
WINIT_WINDOWS.with_borrow(|winit_windows| {
|
||||||
for (entity, mut pending_cursor) in windows.iter_mut() {
|
for (entity, mut pending_cursor) in windows.iter_mut() {
|
||||||
let Some(winit_window) = winit_windows.get_window(entity) else {
|
let Some(winit_window) = winit_windows.get_window(entity) else {
|
||||||
continue;
|
continue;
|
||||||
@ -913,6 +925,7 @@ impl<T: Event> WinitAppRunnerState<T> {
|
|||||||
};
|
};
|
||||||
winit_window.set_cursor(final_cursor);
|
winit_window.set_cursor(final_cursor);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ use bevy_ecs::{
|
|||||||
prelude::{Changed, Component},
|
prelude::{Changed, Component},
|
||||||
query::QueryFilter,
|
query::QueryFilter,
|
||||||
removal_detection::RemovedComponents,
|
removal_detection::RemovedComponents,
|
||||||
system::{Local, NonSendMut, Query, SystemParamItem},
|
system::{Local, NonSendMarker, Query, SystemParamItem},
|
||||||
};
|
};
|
||||||
use bevy_input::keyboard::{Key, KeyCode, KeyboardFocusLost, KeyboardInput};
|
use bevy_input::keyboard::{Key, KeyCode, KeyboardFocusLost, KeyboardInput};
|
||||||
use bevy_window::{
|
use bevy_window::{
|
||||||
@ -30,6 +30,7 @@ use winit::platform::ios::WindowExtIOS;
|
|||||||
use winit::platform::web::WindowExtWebSys;
|
use winit::platform::web::WindowExtWebSys;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
accessibility::ACCESS_KIT_ADAPTERS,
|
||||||
converters::{
|
converters::{
|
||||||
convert_enabled_buttons, convert_resize_direction, convert_window_level,
|
convert_enabled_buttons, convert_resize_direction, convert_window_level,
|
||||||
convert_window_theme, convert_winit_theme,
|
convert_window_theme, convert_winit_theme,
|
||||||
@ -37,7 +38,7 @@ use crate::{
|
|||||||
get_selected_videomode, select_monitor,
|
get_selected_videomode, select_monitor,
|
||||||
state::react_to_resize,
|
state::react_to_resize,
|
||||||
winit_monitors::WinitMonitors,
|
winit_monitors::WinitMonitors,
|
||||||
CreateMonitorParams, CreateWindowParams, WinitWindows,
|
CreateMonitorParams, CreateWindowParams, WINIT_WINDOWS,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Creates new windows on the [`winit`] backend for each entity with a newly-added
|
/// Creates new windows on the [`winit`] backend for each entity with a newly-added
|
||||||
@ -51,13 +52,13 @@ pub fn create_windows<F: QueryFilter + 'static>(
|
|||||||
mut commands,
|
mut commands,
|
||||||
mut created_windows,
|
mut created_windows,
|
||||||
mut window_created_events,
|
mut window_created_events,
|
||||||
mut winit_windows,
|
|
||||||
mut adapters,
|
|
||||||
mut handlers,
|
mut handlers,
|
||||||
accessibility_requested,
|
accessibility_requested,
|
||||||
monitors,
|
monitors,
|
||||||
): SystemParamItem<CreateWindowParams<F>>,
|
): SystemParamItem<CreateWindowParams<F>>,
|
||||||
) {
|
) {
|
||||||
|
WINIT_WINDOWS.with_borrow_mut(|winit_windows| {
|
||||||
|
ACCESS_KIT_ADAPTERS.with_borrow_mut(|adapters| {
|
||||||
for (entity, mut window, handle_holder) in &mut created_windows {
|
for (entity, mut window, handle_holder) in &mut created_windows {
|
||||||
if winit_windows.get_window(entity).is_some() {
|
if winit_windows.get_window(entity).is_some() {
|
||||||
continue;
|
continue;
|
||||||
@ -69,7 +70,7 @@ pub fn create_windows<F: QueryFilter + 'static>(
|
|||||||
event_loop,
|
event_loop,
|
||||||
entity,
|
entity,
|
||||||
&window,
|
&window,
|
||||||
&mut adapters,
|
adapters,
|
||||||
&mut handlers,
|
&mut handlers,
|
||||||
&accessibility_requested,
|
&accessibility_requested,
|
||||||
&monitors,
|
&monitors,
|
||||||
@ -123,6 +124,8 @@ pub fn create_windows<F: QueryFilter + 'static>(
|
|||||||
|
|
||||||
window_created_events.write(WindowCreated { window: entity });
|
window_created_events.write(WindowCreated { window: entity });
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check whether keyboard focus was lost. This is different from window
|
/// Check whether keyboard focus was lost. This is different from window
|
||||||
@ -239,9 +242,9 @@ pub(crate) fn despawn_windows(
|
|||||||
window_entities: Query<Entity, With<Window>>,
|
window_entities: Query<Entity, With<Window>>,
|
||||||
mut closing_events: EventWriter<WindowClosing>,
|
mut closing_events: EventWriter<WindowClosing>,
|
||||||
mut closed_events: EventWriter<WindowClosed>,
|
mut closed_events: EventWriter<WindowClosed>,
|
||||||
mut winit_windows: NonSendMut<WinitWindows>,
|
|
||||||
mut windows_to_drop: Local<Vec<WindowWrapper<winit::window::Window>>>,
|
mut windows_to_drop: Local<Vec<WindowWrapper<winit::window::Window>>>,
|
||||||
mut exit_events: EventReader<AppExit>,
|
mut exit_events: EventReader<AppExit>,
|
||||||
|
_non_send_marker: NonSendMarker,
|
||||||
) {
|
) {
|
||||||
// Drop all the windows that are waiting to be closed
|
// Drop all the windows that are waiting to be closed
|
||||||
windows_to_drop.clear();
|
windows_to_drop.clear();
|
||||||
@ -254,6 +257,7 @@ pub(crate) fn despawn_windows(
|
|||||||
// rather than having the component added
|
// rather than having the component added
|
||||||
// and removed in the same frame.
|
// and removed in the same frame.
|
||||||
if !window_entities.contains(window) {
|
if !window_entities.contains(window) {
|
||||||
|
WINIT_WINDOWS.with_borrow_mut(|winit_windows| {
|
||||||
if let Some(window) = winit_windows.remove_window(window) {
|
if let Some(window) = winit_windows.remove_window(window) {
|
||||||
// Keeping WindowWrapper that are dropped for one frame
|
// Keeping WindowWrapper that are dropped for one frame
|
||||||
// Otherwise the last `Arc` of the window could be in the rendering thread, and dropped there
|
// Otherwise the last `Arc` of the window could be in the rendering thread, and dropped there
|
||||||
@ -261,6 +265,7 @@ pub(crate) fn despawn_windows(
|
|||||||
// Keeping the wrapper and dropping it next frame in this system ensure its dropped in the main thread
|
// Keeping the wrapper and dropping it next frame in this system ensure its dropped in the main thread
|
||||||
windows_to_drop.push(window);
|
windows_to_drop.push(window);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
closed_events.write(WindowClosed { window });
|
closed_events.write(WindowClosed { window });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -291,10 +296,11 @@ pub struct CachedWindow {
|
|||||||
/// - [`Window::focused`] cannot be manually changed to `false` after the window is created.
|
/// - [`Window::focused`] cannot be manually changed to `false` after the window is created.
|
||||||
pub(crate) fn changed_windows(
|
pub(crate) fn changed_windows(
|
||||||
mut changed_windows: Query<(Entity, &mut Window, &mut CachedWindow), Changed<Window>>,
|
mut changed_windows: Query<(Entity, &mut Window, &mut CachedWindow), Changed<Window>>,
|
||||||
winit_windows: NonSendMut<WinitWindows>,
|
|
||||||
monitors: Res<WinitMonitors>,
|
monitors: Res<WinitMonitors>,
|
||||||
mut window_resized: EventWriter<WindowResized>,
|
mut window_resized: EventWriter<WindowResized>,
|
||||||
|
_non_send_marker: NonSendMarker,
|
||||||
) {
|
) {
|
||||||
|
WINIT_WINDOWS.with_borrow(|winit_windows| {
|
||||||
for (entity, mut window, mut cache) in &mut changed_windows {
|
for (entity, mut window, mut cache) in &mut changed_windows {
|
||||||
let Some(winit_window) = winit_windows.get_window(entity) else {
|
let Some(winit_window) = winit_windows.get_window(entity) else {
|
||||||
continue;
|
continue;
|
||||||
@ -581,6 +587,7 @@ pub(crate) fn changed_windows(
|
|||||||
}
|
}
|
||||||
cache.window = window.clone();
|
cache.window = window.clone();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This keeps track of which keys are pressed on each window.
|
/// This keeps track of which keys are pressed on each window.
|
||||||
|
@ -42,6 +42,16 @@ pub struct WinitWindows {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl WinitWindows {
|
impl WinitWindows {
|
||||||
|
/// Creates a new instance of `WinitWindows`.
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
windows: HashMap::new(),
|
||||||
|
entity_to_winit: EntityHashMap::new(),
|
||||||
|
winit_to_entity: HashMap::new(),
|
||||||
|
_not_send_sync: core::marker::PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a `winit` window and associates it with our entity.
|
/// Creates a `winit` window and associates it with our entity.
|
||||||
pub fn create_window(
|
pub fn create_window(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
Loading…
Reference in New Issue
Block a user