Cleanup bevy winit (#11489)
# Objective Get #11257 changes merged. I rewrote them one by one checking each to ensure correctness. In particular, the window rescale logic changes to accomodate mut app access are double checked. Not all changes have been included as some of bevy_winit has since changed, and i am not confident including them. Namely, the `run_app_update_if_should` change. ### Notes to reviewers Review commits individually, use the "Hide whitespaces" diff display mode. ## Changelog * `bevy:🪟:WindowMoved`'s `entity` field has been renamed to `window` ## Migration Guide `bevy:🪟:WindowMoved`'s `entity` field has been renamed to `window`. This is to be more consistent with other windowing events. Consider changing usage: ```diff -window_moved.entity +window_moved.window ``` --------- Co-authored-by: François <mockersf@gmail.com>
This commit is contained in:
parent
dad379cdca
commit
eb8de36922
@ -332,7 +332,7 @@ pub enum FileDragAndDrop {
|
|||||||
)]
|
)]
|
||||||
pub struct WindowMoved {
|
pub struct WindowMoved {
|
||||||
/// Window that moved.
|
/// Window that moved.
|
||||||
pub entity: Entity,
|
pub window: Entity,
|
||||||
/// Where the window moved to in physical pixels.
|
/// Where the window moved to in physical pixels.
|
||||||
pub position: IVec2,
|
pub position: IVec2,
|
||||||
}
|
}
|
||||||
|
@ -12,20 +12,20 @@ mod system;
|
|||||||
mod winit_config;
|
mod winit_config;
|
||||||
mod winit_windows;
|
mod winit_windows;
|
||||||
|
|
||||||
|
use approx::relative_eq;
|
||||||
use bevy_a11y::AccessibilityRequested;
|
use bevy_a11y::AccessibilityRequested;
|
||||||
use bevy_utils::{Duration, Instant};
|
use bevy_utils::{Duration, Instant};
|
||||||
use system::{changed_windows, create_windows, despawn_windows, CachedWindow};
|
use system::{changed_windows, create_windows, despawn_windows, CachedWindow};
|
||||||
|
use winit::dpi::{LogicalSize, PhysicalSize};
|
||||||
pub use winit_config::*;
|
pub use winit_config::*;
|
||||||
pub use winit_windows::*;
|
pub use winit_windows::*;
|
||||||
|
|
||||||
use bevy_app::{App, AppExit, Last, Plugin, PluginsState};
|
use bevy_app::{App, AppExit, Last, Plugin, PluginsState};
|
||||||
use bevy_ecs::event::{Events, ManualEventReader};
|
use bevy_ecs::event::{Events, ManualEventReader};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_ecs::system::{SystemParam, SystemState};
|
use bevy_ecs::system::SystemState;
|
||||||
use bevy_input::{
|
use bevy_input::{
|
||||||
keyboard::KeyboardInput,
|
|
||||||
mouse::{MouseButtonInput, MouseMotion, MouseScrollUnit, MouseWheel},
|
mouse::{MouseButtonInput, MouseMotion, MouseScrollUnit, MouseWheel},
|
||||||
touch::TouchInput,
|
|
||||||
touchpad::{TouchpadMagnify, TouchpadRotate},
|
touchpad::{TouchpadMagnify, TouchpadRotate},
|
||||||
};
|
};
|
||||||
use bevy_math::{ivec2, DVec2, Vec2};
|
use bevy_math::{ivec2, DVec2, Vec2};
|
||||||
@ -84,11 +84,8 @@ impl Plugin for WinitPlugin {
|
|||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
let mut event_loop_builder = EventLoopBuilder::<()>::with_user_event();
|
let mut event_loop_builder = EventLoopBuilder::<()>::with_user_event();
|
||||||
|
|
||||||
// This is needed because the features checked in the inner
|
// linux check is needed because x11 might be enabled on other platforms.
|
||||||
// block might be enabled on other platforms than linux.
|
#[cfg(all(target_os = "linux", feature = "x11"))]
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
{
|
|
||||||
#[cfg(feature = "x11")]
|
|
||||||
{
|
{
|
||||||
use winit::platform::x11::EventLoopBuilderExtX11;
|
use winit::platform::x11::EventLoopBuilderExtX11;
|
||||||
|
|
||||||
@ -99,12 +96,12 @@ impl Plugin for WinitPlugin {
|
|||||||
event_loop_builder.with_any_thread(self.run_on_any_thread);
|
event_loop_builder.with_any_thread(self.run_on_any_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "wayland")]
|
// linux check is needed because wayland might be enabled on other platforms.
|
||||||
|
#[cfg(all(target_os = "linux", feature = "wayland"))]
|
||||||
{
|
{
|
||||||
use winit::platform::wayland::EventLoopBuilderExtWayland;
|
use winit::platform::wayland::EventLoopBuilderExtWayland;
|
||||||
event_loop_builder.with_any_thread(self.run_on_any_thread);
|
event_loop_builder.with_any_thread(self.run_on_any_thread);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
{
|
{
|
||||||
@ -115,12 +112,8 @@ impl Plugin for WinitPlugin {
|
|||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
{
|
{
|
||||||
use winit::platform::android::EventLoopBuilderExtAndroid;
|
use winit::platform::android::EventLoopBuilderExtAndroid;
|
||||||
event_loop_builder.with_android_app(
|
let msg = "Bevy must be setup with the #[bevy_main] macro on Android";
|
||||||
ANDROID_APP
|
event_loop_builder.with_android_app(ANDROID_APP.get().expect(msg).clone());
|
||||||
.get()
|
|
||||||
.expect("Bevy must be setup with the #[bevy_main] macro on Android")
|
|
||||||
.clone(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app.init_non_send_resource::<WinitWindows>()
|
app.init_non_send_resource::<WinitWindows>()
|
||||||
@ -154,62 +147,9 @@ impl Plugin for WinitPlugin {
|
|||||||
// Otherwise, we want to create a window before `bevy_render` initializes the renderer
|
// Otherwise, we want to create a window before `bevy_render` initializes the renderer
|
||||||
// so that we have a surface to use as a hint. This improves compatibility with `wgpu`
|
// so that we have a surface to use as a hint. This improves compatibility with `wgpu`
|
||||||
// backends, especially WASM/WebGL2.
|
// backends, especially WASM/WebGL2.
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
let mut create_window = SystemState::<CreateWindowParams>::from_world(&mut app.world);
|
||||||
let mut create_window_system_state: SystemState<(
|
create_windows(&event_loop, create_window.get_mut(&mut app.world));
|
||||||
Commands,
|
create_window.apply(&mut app.world);
|
||||||
Query<(Entity, &mut Window)>,
|
|
||||||
EventWriter<WindowCreated>,
|
|
||||||
NonSendMut<WinitWindows>,
|
|
||||||
NonSendMut<AccessKitAdapters>,
|
|
||||||
ResMut<WinitActionHandlers>,
|
|
||||||
ResMut<AccessibilityRequested>,
|
|
||||||
)> = SystemState::from_world(&mut app.world);
|
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
let mut create_window_system_state: SystemState<(
|
|
||||||
Commands,
|
|
||||||
Query<(Entity, &mut Window)>,
|
|
||||||
EventWriter<WindowCreated>,
|
|
||||||
NonSendMut<WinitWindows>,
|
|
||||||
NonSendMut<AccessKitAdapters>,
|
|
||||||
ResMut<WinitActionHandlers>,
|
|
||||||
ResMut<AccessibilityRequested>,
|
|
||||||
)> = SystemState::from_world(&mut app.world);
|
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
let (
|
|
||||||
commands,
|
|
||||||
mut windows,
|
|
||||||
event_writer,
|
|
||||||
winit_windows,
|
|
||||||
adapters,
|
|
||||||
handlers,
|
|
||||||
accessibility_requested,
|
|
||||||
) = create_window_system_state.get_mut(&mut app.world);
|
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
let (
|
|
||||||
commands,
|
|
||||||
mut windows,
|
|
||||||
event_writer,
|
|
||||||
winit_windows,
|
|
||||||
adapters,
|
|
||||||
handlers,
|
|
||||||
accessibility_requested,
|
|
||||||
) = create_window_system_state.get_mut(&mut app.world);
|
|
||||||
|
|
||||||
create_windows(
|
|
||||||
&event_loop,
|
|
||||||
commands,
|
|
||||||
windows.iter_mut(),
|
|
||||||
event_writer,
|
|
||||||
winit_windows,
|
|
||||||
adapters,
|
|
||||||
handlers,
|
|
||||||
accessibility_requested,
|
|
||||||
);
|
|
||||||
|
|
||||||
create_window_system_state.apply(&mut app.world);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// `winit`'s windows are bound to the event loop that created them, so the event loop must
|
// `winit`'s windows are bound to the event loop that created them, so the event loop must
|
||||||
@ -218,33 +158,13 @@ impl Plugin for WinitPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(SystemParam)]
|
trait AppSendEvent {
|
||||||
struct WindowAndInputEventWriters<'w> {
|
fn send_event<E: bevy_ecs::event::Event>(&mut self, event: E);
|
||||||
// `winit` `WindowEvent`s
|
}
|
||||||
window_resized: EventWriter<'w, WindowResized>,
|
impl AppSendEvent for App {
|
||||||
window_close_requested: EventWriter<'w, WindowCloseRequested>,
|
fn send_event<E: bevy_ecs::event::Event>(&mut self, event: E) {
|
||||||
window_scale_factor_changed: EventWriter<'w, WindowScaleFactorChanged>,
|
self.world.send_event(event);
|
||||||
window_backend_scale_factor_changed: EventWriter<'w, WindowBackendScaleFactorChanged>,
|
}
|
||||||
window_focused: EventWriter<'w, WindowFocused>,
|
|
||||||
window_occluded: EventWriter<'w, WindowOccluded>,
|
|
||||||
window_moved: EventWriter<'w, WindowMoved>,
|
|
||||||
window_theme_changed: EventWriter<'w, WindowThemeChanged>,
|
|
||||||
window_destroyed: EventWriter<'w, WindowDestroyed>,
|
|
||||||
lifetime: EventWriter<'w, ApplicationLifetime>,
|
|
||||||
keyboard_input: EventWriter<'w, KeyboardInput>,
|
|
||||||
character_input: EventWriter<'w, ReceivedCharacter>,
|
|
||||||
mouse_button_input: EventWriter<'w, MouseButtonInput>,
|
|
||||||
touchpad_magnify_input: EventWriter<'w, TouchpadMagnify>,
|
|
||||||
touchpad_rotate_input: EventWriter<'w, TouchpadRotate>,
|
|
||||||
mouse_wheel_input: EventWriter<'w, MouseWheel>,
|
|
||||||
touch_input: EventWriter<'w, TouchInput>,
|
|
||||||
ime_input: EventWriter<'w, Ime>,
|
|
||||||
file_drag_and_drop: EventWriter<'w, FileDragAndDrop>,
|
|
||||||
cursor_moved: EventWriter<'w, CursorMoved>,
|
|
||||||
cursor_entered: EventWriter<'w, CursorEntered>,
|
|
||||||
cursor_left: EventWriter<'w, CursorLeft>,
|
|
||||||
// `winit` `DeviceEvent`s
|
|
||||||
mouse_motion: EventWriter<'w, MouseMotion>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
||||||
@ -311,6 +231,16 @@ impl Default for WinitAppRunnerState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CreateWindowParams<'w, 's, F = ()> = (
|
||||||
|
Commands<'w, 's>,
|
||||||
|
Query<'w, 's, (Entity, &'static mut Window), F>,
|
||||||
|
EventWriter<'w, WindowCreated>,
|
||||||
|
NonSendMut<'w, WinitWindows>,
|
||||||
|
NonSendMut<'w, AccessKitAdapters>,
|
||||||
|
ResMut<'w, WinitActionHandlers>,
|
||||||
|
Res<'w, AccessibilityRequested>,
|
||||||
|
);
|
||||||
|
|
||||||
/// The default [`App::runner`] for the [`WinitPlugin`] plugin.
|
/// The default [`App::runner`] for the [`WinitPlugin`] plugin.
|
||||||
///
|
///
|
||||||
/// Overriding the app's [runner](bevy_app::App::runner) while using `WinitPlugin` will bypass the
|
/// Overriding the app's [runner](bevy_app::App::runner) while using `WinitPlugin` will bypass the
|
||||||
@ -339,24 +269,53 @@ pub fn winit_runner(mut app: App) {
|
|||||||
SystemState::new(&mut app.world);
|
SystemState::new(&mut app.world);
|
||||||
|
|
||||||
let mut event_writer_system_state: SystemState<(
|
let mut event_writer_system_state: SystemState<(
|
||||||
WindowAndInputEventWriters,
|
EventWriter<WindowResized>,
|
||||||
NonSend<WinitWindows>,
|
NonSend<WinitWindows>,
|
||||||
Query<(&mut Window, &mut CachedWindow)>,
|
Query<(&mut Window, &mut CachedWindow)>,
|
||||||
NonSend<AccessKitAdapters>,
|
NonSend<AccessKitAdapters>,
|
||||||
)> = SystemState::new(&mut app.world);
|
)> = SystemState::new(&mut app.world);
|
||||||
|
|
||||||
let mut create_window_system_state: SystemState<(
|
let mut create_window =
|
||||||
Commands,
|
SystemState::<CreateWindowParams<Added<Window>>>::from_world(&mut app.world);
|
||||||
Query<(Entity, &mut Window), Added<Window>>,
|
// set up the event loop
|
||||||
EventWriter<WindowCreated>,
|
let event_handler = move |event, event_loop: &EventLoopWindowTarget<()>| {
|
||||||
NonSendMut<WinitWindows>,
|
handle_winit_event(
|
||||||
NonSendMut<AccessKitAdapters>,
|
&mut app,
|
||||||
ResMut<WinitActionHandlers>,
|
&mut app_exit_event_reader,
|
||||||
ResMut<AccessibilityRequested>,
|
&mut runner_state,
|
||||||
)> = SystemState::from_world(&mut app.world);
|
&mut create_window,
|
||||||
|
&mut event_writer_system_state,
|
||||||
|
&mut focused_windows_state,
|
||||||
|
&mut redraw_event_reader,
|
||||||
|
event,
|
||||||
|
event_loop,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
// setup up the event loop
|
trace!("starting winit event loop");
|
||||||
let event_handler = move |event: Event<()>, event_loop: &EventLoopWindowTarget<()>| {
|
// TODO(clean): the winit docs mention using `spawn` instead of `run` on WASM.
|
||||||
|
if let Err(err) = event_loop.run(event_handler) {
|
||||||
|
error!("winit event loop returned an error: {err}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments /* TODO: probs can reduce # of args */)]
|
||||||
|
fn handle_winit_event(
|
||||||
|
app: &mut App,
|
||||||
|
app_exit_event_reader: &mut ManualEventReader<AppExit>,
|
||||||
|
runner_state: &mut WinitAppRunnerState,
|
||||||
|
create_window: &mut SystemState<CreateWindowParams<Added<Window>>>,
|
||||||
|
event_writer_system_state: &mut SystemState<(
|
||||||
|
EventWriter<WindowResized>,
|
||||||
|
NonSend<WinitWindows>,
|
||||||
|
Query<(&mut Window, &mut CachedWindow)>,
|
||||||
|
NonSend<AccessKitAdapters>,
|
||||||
|
)>,
|
||||||
|
focused_windows_state: &mut SystemState<(Res<WinitSettings>, Query<&Window>)>,
|
||||||
|
redraw_event_reader: &mut ManualEventReader<RequestRedraw>,
|
||||||
|
event: Event<()>,
|
||||||
|
event_loop: &EventLoopWindowTarget<()>,
|
||||||
|
) {
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
let _span = bevy_utils::tracing::info_span!("winit event_handler").entered();
|
let _span = bevy_utils::tracing::info_span!("winit event_handler").entered();
|
||||||
|
|
||||||
@ -414,8 +373,7 @@ pub fn winit_runner(mut app: App) {
|
|||||||
|
|
||||||
if should_update {
|
if should_update {
|
||||||
let visible = windows.iter().any(|window| window.visible);
|
let visible = windows.iter().any(|window| window.visible);
|
||||||
let (_, winit_windows, _, _) =
|
let (_, winit_windows, _, _) = event_writer_system_state.get_mut(&mut app.world);
|
||||||
event_writer_system_state.get_mut(&mut app.world);
|
|
||||||
if visible && runner_state.active != ActiveState::WillSuspend {
|
if visible && runner_state.active != ActiveState::WillSuspend {
|
||||||
for window in winit_windows.windows.values() {
|
for window in winit_windows.windows.values() {
|
||||||
window.request_redraw();
|
window.request_redraw();
|
||||||
@ -424,13 +382,13 @@ pub fn winit_runner(mut app: App) {
|
|||||||
// there are no windows, or they are not visible.
|
// there are no windows, or they are not visible.
|
||||||
// Winit won't send events on some platforms, so trigger an update manually.
|
// Winit won't send events on some platforms, so trigger an update manually.
|
||||||
run_app_update_if_should(
|
run_app_update_if_should(
|
||||||
&mut runner_state,
|
runner_state,
|
||||||
&mut app,
|
app,
|
||||||
&mut focused_windows_state,
|
focused_windows_state,
|
||||||
event_loop,
|
event_loop,
|
||||||
&mut create_window_system_state,
|
create_window,
|
||||||
&mut app_exit_event_reader,
|
app_exit_event_reader,
|
||||||
&mut redraw_event_reader,
|
redraw_event_reader,
|
||||||
);
|
);
|
||||||
if runner_state.active != ActiveState::Suspended {
|
if runner_state.active != ActiveState::Suspended {
|
||||||
event_loop.set_control_flow(ControlFlow::Poll);
|
event_loop.set_control_flow(ControlFlow::Poll);
|
||||||
@ -448,30 +406,24 @@ pub fn winit_runner(mut app: App) {
|
|||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event, window_id, ..
|
event, window_id, ..
|
||||||
} => {
|
} => {
|
||||||
let (mut event_writers, winit_windows, mut windows, access_kit_adapters) =
|
let (mut window_resized, winit_windows, mut windows, access_kit_adapters) =
|
||||||
event_writer_system_state.get_mut(&mut app.world);
|
event_writer_system_state.get_mut(&mut app.world);
|
||||||
|
|
||||||
let Some(window_entity) = winit_windows.get_window_entity(window_id) else {
|
let Some(window) = winit_windows.get_window_entity(window_id) else {
|
||||||
warn!(
|
warn!("Skipped event {event:?} for unknown winit Window Id {window_id:?}");
|
||||||
"Skipped event {:?} for unknown winit Window Id {:?}",
|
|
||||||
event, window_id
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Ok((mut window, _)) = windows.get_mut(window_entity) else {
|
let Ok((mut win, _)) = windows.get_mut(window) else {
|
||||||
warn!(
|
warn!("Window {window:?} is missing `Window` component, skipping event {event:?}");
|
||||||
"Window {:?} is missing `Window` component, skipping event {:?}",
|
|
||||||
window_entity, event
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Allow AccessKit to respond to `WindowEvent`s before they reach
|
// Allow AccessKit to respond to `WindowEvent`s before they reach
|
||||||
// the engine.
|
// the engine.
|
||||||
if let Some(adapter) = access_kit_adapters.get(&window_entity) {
|
if let Some(adapter) = access_kit_adapters.get(&window) {
|
||||||
if let Some(window) = winit_windows.get_window(window_entity) {
|
if let Some(winit_window) = winit_windows.get_window(window) {
|
||||||
adapter.process_event(window, &event);
|
adapter.process_event(winit_window, &event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,262 +431,199 @@ pub fn winit_runner(mut app: App) {
|
|||||||
|
|
||||||
match event {
|
match event {
|
||||||
WindowEvent::Resized(size) => {
|
WindowEvent::Resized(size) => {
|
||||||
react_to_resize(&mut window, size, &mut event_writers, window_entity);
|
react_to_resize(&mut win, size, &mut window_resized, window);
|
||||||
}
|
|
||||||
WindowEvent::CloseRequested => {
|
|
||||||
event_writers
|
|
||||||
.window_close_requested
|
|
||||||
.send(WindowCloseRequested {
|
|
||||||
window: window_entity,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
WindowEvent::CloseRequested => app.send_event(WindowCloseRequested { window }),
|
||||||
WindowEvent::KeyboardInput { ref event, .. } => {
|
WindowEvent::KeyboardInput { ref event, .. } => {
|
||||||
if event.state.is_pressed() {
|
if event.state.is_pressed() {
|
||||||
if let Some(char) = &event.text {
|
if let Some(char) = &event.text {
|
||||||
event_writers.character_input.send(ReceivedCharacter {
|
let char = char.clone();
|
||||||
window: window_entity,
|
app.send_event(ReceivedCharacter { window, char });
|
||||||
char: char.clone(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let keyboard_event =
|
app.send_event(converters::convert_keyboard_input(event, window));
|
||||||
converters::convert_keyboard_input(event, window_entity);
|
|
||||||
event_writers.keyboard_input.send(keyboard_event);
|
|
||||||
}
|
}
|
||||||
WindowEvent::CursorMoved { position, .. } => {
|
WindowEvent::CursorMoved { position, .. } => {
|
||||||
let physical_position = DVec2::new(position.x, position.y);
|
let physical_position = DVec2::new(position.x, position.y);
|
||||||
window.set_physical_cursor_position(Some(physical_position));
|
win.set_physical_cursor_position(Some(physical_position));
|
||||||
event_writers.cursor_moved.send(CursorMoved {
|
let position =
|
||||||
window: window_entity,
|
(physical_position / win.resolution.scale_factor() as f64).as_vec2();
|
||||||
position: (physical_position / window.resolution.scale_factor() as f64)
|
app.send_event(CursorMoved { window, position });
|
||||||
.as_vec2(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
WindowEvent::CursorEntered { .. } => {
|
WindowEvent::CursorEntered { .. } => {
|
||||||
event_writers.cursor_entered.send(CursorEntered {
|
app.send_event(CursorEntered { window });
|
||||||
window: window_entity,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
WindowEvent::CursorLeft { .. } => {
|
WindowEvent::CursorLeft { .. } => {
|
||||||
window.set_physical_cursor_position(None);
|
win.set_physical_cursor_position(None);
|
||||||
event_writers.cursor_left.send(CursorLeft {
|
app.send_event(CursorLeft { window });
|
||||||
window: window_entity,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
WindowEvent::MouseInput { state, button, .. } => {
|
WindowEvent::MouseInput { state, button, .. } => {
|
||||||
event_writers.mouse_button_input.send(MouseButtonInput {
|
app.send_event(MouseButtonInput {
|
||||||
button: converters::convert_mouse_button(button),
|
button: converters::convert_mouse_button(button),
|
||||||
state: converters::convert_element_state(state),
|
state: converters::convert_element_state(state),
|
||||||
window: window_entity,
|
window,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
WindowEvent::TouchpadMagnify { delta, .. } => {
|
WindowEvent::TouchpadMagnify { delta, .. } => {
|
||||||
event_writers
|
app.send_event(TouchpadMagnify(delta as f32));
|
||||||
.touchpad_magnify_input
|
|
||||||
.send(TouchpadMagnify(delta as f32));
|
|
||||||
}
|
}
|
||||||
WindowEvent::TouchpadRotate { delta, .. } => {
|
WindowEvent::TouchpadRotate { delta, .. } => {
|
||||||
event_writers
|
app.send_event(TouchpadRotate(delta));
|
||||||
.touchpad_rotate_input
|
|
||||||
.send(TouchpadRotate(delta));
|
|
||||||
}
|
}
|
||||||
WindowEvent::MouseWheel { delta, .. } => match delta {
|
WindowEvent::MouseWheel { delta, .. } => match delta {
|
||||||
event::MouseScrollDelta::LineDelta(x, y) => {
|
event::MouseScrollDelta::LineDelta(x, y) => {
|
||||||
event_writers.mouse_wheel_input.send(MouseWheel {
|
app.send_event(MouseWheel {
|
||||||
unit: MouseScrollUnit::Line,
|
unit: MouseScrollUnit::Line,
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
window: window_entity,
|
window,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
event::MouseScrollDelta::PixelDelta(p) => {
|
event::MouseScrollDelta::PixelDelta(p) => {
|
||||||
event_writers.mouse_wheel_input.send(MouseWheel {
|
app.send_event(MouseWheel {
|
||||||
unit: MouseScrollUnit::Pixel,
|
unit: MouseScrollUnit::Pixel,
|
||||||
x: p.x as f32,
|
x: p.x as f32,
|
||||||
y: p.y as f32,
|
y: p.y as f32,
|
||||||
window: window_entity,
|
window,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
WindowEvent::Touch(touch) => {
|
WindowEvent::Touch(touch) => {
|
||||||
let location = touch
|
let location = touch
|
||||||
.location
|
.location
|
||||||
.to_logical(window.resolution.scale_factor() as f64);
|
.to_logical(win.resolution.scale_factor() as f64);
|
||||||
event_writers
|
app.send_event(converters::convert_touch_input(touch, location, window));
|
||||||
.touch_input
|
|
||||||
.send(converters::convert_touch_input(
|
|
||||||
touch,
|
|
||||||
location,
|
|
||||||
window_entity,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
WindowEvent::ScaleFactorChanged {
|
WindowEvent::ScaleFactorChanged {
|
||||||
scale_factor,
|
scale_factor,
|
||||||
mut inner_size_writer,
|
mut inner_size_writer,
|
||||||
} => {
|
} => {
|
||||||
event_writers.window_backend_scale_factor_changed.send(
|
let prior_factor = win.resolution.scale_factor();
|
||||||
WindowBackendScaleFactorChanged {
|
win.resolution.set_scale_factor(scale_factor as f32);
|
||||||
window: window_entity,
|
// Note: this may be different from new_scale_factor if
|
||||||
scale_factor,
|
// `scale_factor_override` is set to Some(thing)
|
||||||
},
|
let new_factor = win.resolution.scale_factor();
|
||||||
);
|
|
||||||
|
|
||||||
let prior_factor = window.resolution.scale_factor();
|
let mut new_inner_size =
|
||||||
window.resolution.set_scale_factor(scale_factor as f32);
|
PhysicalSize::new(win.physical_width(), win.physical_height());
|
||||||
let new_factor = window.resolution.scale_factor();
|
let scale_factor_override = win.resolution.scale_factor_override();
|
||||||
|
if let Some(forced_factor) = scale_factor_override {
|
||||||
let mut new_inner_size = winit::dpi::PhysicalSize::new(
|
|
||||||
window.physical_width(),
|
|
||||||
window.physical_height(),
|
|
||||||
);
|
|
||||||
if let Some(forced_factor) = window.resolution.scale_factor_override() {
|
|
||||||
// This window is overriding the OS-suggested DPI, so its physical size
|
// This window is overriding the OS-suggested DPI, so its physical size
|
||||||
// should be set based on the overriding value. Its logical size already
|
// should be set based on the overriding value. Its logical size already
|
||||||
// incorporates any resize constraints.
|
// incorporates any resize constraints.
|
||||||
let maybe_new_inner_size =
|
let maybe_new_inner_size = LogicalSize::new(win.width(), win.height())
|
||||||
winit::dpi::LogicalSize::new(window.width(), window.height())
|
|
||||||
.to_physical::<u32>(forced_factor as f64);
|
.to_physical::<u32>(forced_factor as f64);
|
||||||
if let Err(err) = inner_size_writer.request_inner_size(new_inner_size) {
|
if let Err(err) = inner_size_writer.request_inner_size(new_inner_size) {
|
||||||
warn!("Winit Failed to resize the window: {err}");
|
warn!("Winit Failed to resize the window: {err}");
|
||||||
} else {
|
} else {
|
||||||
new_inner_size = maybe_new_inner_size;
|
new_inner_size = maybe_new_inner_size;
|
||||||
}
|
}
|
||||||
} else if approx::relative_ne!(new_factor, prior_factor) {
|
|
||||||
event_writers.window_scale_factor_changed.send(
|
|
||||||
WindowScaleFactorChanged {
|
|
||||||
window: window_entity,
|
|
||||||
scale_factor,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
let new_logical_width = new_inner_size.width as f32 / new_factor;
|
let new_logical_width = new_inner_size.width as f32 / new_factor;
|
||||||
let new_logical_height = new_inner_size.height as f32 / new_factor;
|
let new_logical_height = new_inner_size.height as f32 / new_factor;
|
||||||
if approx::relative_ne!(window.width(), new_logical_width)
|
|
||||||
|| approx::relative_ne!(window.height(), new_logical_height)
|
let width_equal = relative_eq!(win.width(), new_logical_width);
|
||||||
{
|
let height_equal = relative_eq!(win.height(), new_logical_height);
|
||||||
event_writers.window_resized.send(WindowResized {
|
win.resolution
|
||||||
window: window_entity,
|
.set_physical_resolution(new_inner_size.width, new_inner_size.height);
|
||||||
|
|
||||||
|
app.send_event(WindowBackendScaleFactorChanged {
|
||||||
|
window,
|
||||||
|
scale_factor,
|
||||||
|
});
|
||||||
|
if scale_factor_override.is_none() && !relative_eq!(new_factor, prior_factor) {
|
||||||
|
app.send_event(WindowScaleFactorChanged {
|
||||||
|
window,
|
||||||
|
scale_factor,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if !width_equal || !height_equal {
|
||||||
|
app.send_event(WindowResized {
|
||||||
|
window,
|
||||||
width: new_logical_width,
|
width: new_logical_width,
|
||||||
height: new_logical_height,
|
height: new_logical_height,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
window
|
|
||||||
.resolution
|
|
||||||
.set_physical_resolution(new_inner_size.width, new_inner_size.height);
|
|
||||||
}
|
}
|
||||||
WindowEvent::Focused(focused) => {
|
WindowEvent::Focused(focused) => {
|
||||||
window.focused = focused;
|
win.focused = focused;
|
||||||
event_writers.window_focused.send(WindowFocused {
|
app.send_event(WindowFocused { window, focused });
|
||||||
window: window_entity,
|
|
||||||
focused,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
WindowEvent::Occluded(occluded) => {
|
WindowEvent::Occluded(occluded) => {
|
||||||
event_writers.window_occluded.send(WindowOccluded {
|
app.send_event(WindowOccluded { window, occluded });
|
||||||
window: window_entity,
|
|
||||||
occluded,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
WindowEvent::DroppedFile(path_buf) => {
|
WindowEvent::DroppedFile(path_buf) => {
|
||||||
event_writers
|
app.send_event(FileDragAndDrop::DroppedFile { window, path_buf });
|
||||||
.file_drag_and_drop
|
|
||||||
.send(FileDragAndDrop::DroppedFile {
|
|
||||||
window: window_entity,
|
|
||||||
path_buf,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
WindowEvent::HoveredFile(path_buf) => {
|
WindowEvent::HoveredFile(path_buf) => {
|
||||||
event_writers
|
app.send_event(FileDragAndDrop::HoveredFile { window, path_buf });
|
||||||
.file_drag_and_drop
|
|
||||||
.send(FileDragAndDrop::HoveredFile {
|
|
||||||
window: window_entity,
|
|
||||||
path_buf,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
WindowEvent::HoveredFileCancelled => {
|
WindowEvent::HoveredFileCancelled => {
|
||||||
event_writers.file_drag_and_drop.send(
|
app.send_event(FileDragAndDrop::HoveredFileCanceled { window });
|
||||||
FileDragAndDrop::HoveredFileCanceled {
|
|
||||||
window: window_entity,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
WindowEvent::Moved(position) => {
|
WindowEvent::Moved(position) => {
|
||||||
let position = ivec2(position.x, position.y);
|
let position = ivec2(position.x, position.y);
|
||||||
window.position.set(position);
|
win.position.set(position);
|
||||||
event_writers.window_moved.send(WindowMoved {
|
app.send_event(WindowMoved { window, position });
|
||||||
entity: window_entity,
|
|
||||||
position,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
WindowEvent::Ime(event) => match event {
|
WindowEvent::Ime(event) => match event {
|
||||||
event::Ime::Preedit(value, cursor) => {
|
event::Ime::Preedit(value, cursor) => {
|
||||||
event_writers.ime_input.send(Ime::Preedit {
|
app.send_event(Ime::Preedit {
|
||||||
window: window_entity,
|
window,
|
||||||
value,
|
value,
|
||||||
cursor,
|
cursor,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
event::Ime::Commit(value) => {
|
event::Ime::Commit(value) => {
|
||||||
event_writers.ime_input.send(Ime::Commit {
|
app.send_event(Ime::Commit { window, value });
|
||||||
window: window_entity,
|
|
||||||
value,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
event::Ime::Enabled => {
|
event::Ime::Enabled => {
|
||||||
event_writers.ime_input.send(Ime::Enabled {
|
app.send_event(Ime::Enabled { window });
|
||||||
window: window_entity,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
event::Ime::Disabled => {
|
event::Ime::Disabled => {
|
||||||
event_writers.ime_input.send(Ime::Disabled {
|
app.send_event(Ime::Disabled { window });
|
||||||
window: window_entity,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
WindowEvent::ThemeChanged(theme) => {
|
WindowEvent::ThemeChanged(theme) => {
|
||||||
event_writers.window_theme_changed.send(WindowThemeChanged {
|
app.send_event(WindowThemeChanged {
|
||||||
window: window_entity,
|
window,
|
||||||
theme: convert_winit_theme(theme),
|
theme: convert_winit_theme(theme),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
WindowEvent::Destroyed => {
|
WindowEvent::Destroyed => {
|
||||||
event_writers.window_destroyed.send(WindowDestroyed {
|
app.send_event(WindowDestroyed { window });
|
||||||
window: window_entity,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
WindowEvent::RedrawRequested => {
|
WindowEvent::RedrawRequested => {
|
||||||
run_app_update_if_should(
|
run_app_update_if_should(
|
||||||
&mut runner_state,
|
runner_state,
|
||||||
&mut app,
|
app,
|
||||||
&mut focused_windows_state,
|
focused_windows_state,
|
||||||
event_loop,
|
event_loop,
|
||||||
&mut create_window_system_state,
|
create_window,
|
||||||
&mut app_exit_event_reader,
|
app_exit_event_reader,
|
||||||
&mut redraw_event_reader,
|
redraw_event_reader,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut windows = app.world.query::<(&mut Window, &mut CachedWindow)>();
|
let mut windows = app.world.query::<(&mut Window, &mut CachedWindow)>();
|
||||||
if let Ok((window, mut cache)) = windows.get_mut(&mut app.world, window_entity) {
|
if let Ok((window_component, mut cache)) = windows.get_mut(&mut app.world, window) {
|
||||||
if window.is_changed() {
|
if window_component.is_changed() {
|
||||||
cache.window = window.clone();
|
cache.window = window_component.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::DeviceEvent { event, .. } => {
|
Event::DeviceEvent { event, .. } => {
|
||||||
runner_state.device_event_received = true;
|
runner_state.device_event_received = true;
|
||||||
if let DeviceEvent::MouseMotion { delta: (x, y) } = event {
|
if let DeviceEvent::MouseMotion { delta: (x, y) } = event {
|
||||||
let (mut event_writers, ..) = event_writer_system_state.get_mut(&mut app.world);
|
let delta = Vec2::new(x as f32, y as f32);
|
||||||
event_writers.mouse_motion.send(MouseMotion {
|
app.send_event(MouseMotion { delta });
|
||||||
delta: Vec2::new(x as f32, y as f32),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::Suspended => {
|
Event::Suspended => {
|
||||||
let (mut event_writers, ..) = event_writer_system_state.get_mut(&mut app.world);
|
app.send_event(ApplicationLifetime::Suspended);
|
||||||
event_writers.lifetime.send(ApplicationLifetime::Suspended);
|
|
||||||
// Mark the state as `WillSuspend`. This will let the schedule run one last time
|
// Mark the state as `WillSuspend`. This will let the schedule run one last time
|
||||||
// before actually suspending to let the application react
|
// before actually suspending to let the application react
|
||||||
runner_state.active = ActiveState::WillSuspend;
|
runner_state.active = ActiveState::WillSuspend;
|
||||||
@ -743,49 +632,14 @@ pub fn winit_runner(mut app: App) {
|
|||||||
#[cfg(any(target_os = "android", target_os = "ios", target_os = "macos"))]
|
#[cfg(any(target_os = "android", target_os = "ios", target_os = "macos"))]
|
||||||
{
|
{
|
||||||
if runner_state.active == ActiveState::NotYetStarted {
|
if runner_state.active == ActiveState::NotYetStarted {
|
||||||
let mut create_window_system_state: SystemState<(
|
create_windows(event_loop, create_window.get_mut(&mut app.world));
|
||||||
Commands,
|
create_window.apply(&mut app.world);
|
||||||
Query<(Entity, &mut Window)>,
|
|
||||||
EventWriter<WindowCreated>,
|
|
||||||
NonSendMut<WinitWindows>,
|
|
||||||
NonSendMut<AccessKitAdapters>,
|
|
||||||
ResMut<WinitActionHandlers>,
|
|
||||||
ResMut<AccessibilityRequested>,
|
|
||||||
)> = SystemState::from_world(&mut app.world);
|
|
||||||
|
|
||||||
let (
|
|
||||||
commands,
|
|
||||||
mut windows,
|
|
||||||
event_writer,
|
|
||||||
winit_windows,
|
|
||||||
adapters,
|
|
||||||
handlers,
|
|
||||||
accessibility_requested,
|
|
||||||
) = create_window_system_state.get_mut(&mut app.world);
|
|
||||||
|
|
||||||
create_windows(
|
|
||||||
event_loop,
|
|
||||||
commands,
|
|
||||||
windows.iter_mut(),
|
|
||||||
event_writer,
|
|
||||||
winit_windows,
|
|
||||||
adapters,
|
|
||||||
handlers,
|
|
||||||
accessibility_requested,
|
|
||||||
);
|
|
||||||
|
|
||||||
create_window_system_state.apply(&mut app.world);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (mut event_writers, ..) = event_writer_system_state.get_mut(&mut app.world);
|
|
||||||
match runner_state.active {
|
match runner_state.active {
|
||||||
ActiveState::NotYetStarted => {
|
ActiveState::NotYetStarted => app.send_event(ApplicationLifetime::Started),
|
||||||
event_writers.lifetime.send(ApplicationLifetime::Started);
|
_ => app.send_event(ApplicationLifetime::Resumed),
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
event_writers.lifetime.send(ApplicationLifetime::Resumed);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
runner_state.active = ActiveState::Active;
|
runner_state.active = ActiveState::Active;
|
||||||
runner_state.redraw_requested = true;
|
runner_state.redraw_requested = true;
|
||||||
@ -801,14 +655,12 @@ pub fn winit_runner(mut app: App) {
|
|||||||
let window = window.clone();
|
let window = window.clone();
|
||||||
|
|
||||||
let (
|
let (
|
||||||
_,
|
..,
|
||||||
_,
|
|
||||||
_,
|
|
||||||
mut winit_windows,
|
mut winit_windows,
|
||||||
mut adapters,
|
mut adapters,
|
||||||
mut handlers,
|
mut handlers,
|
||||||
accessibility_requested,
|
accessibility_requested,
|
||||||
) = create_window_system_state.get_mut(&mut app.world);
|
) = create_window.get_mut(&mut app.world);
|
||||||
|
|
||||||
let winit_window = winit_windows.create_window(
|
let winit_window = winit_windows.create_window(
|
||||||
event_loop,
|
event_loop,
|
||||||
@ -831,13 +683,6 @@ pub fn winit_runner(mut app: App) {
|
|||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
trace!("starting winit event loop");
|
|
||||||
// TODO(clean): the winit docs mention using `spawn` instead of `run` on WASM.
|
|
||||||
if let Err(err) = event_loop.run(event_handler) {
|
|
||||||
error!("winit event loop returned an error: {err}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_app_update_if_should(
|
fn run_app_update_if_should(
|
||||||
@ -845,15 +690,7 @@ fn run_app_update_if_should(
|
|||||||
app: &mut App,
|
app: &mut App,
|
||||||
focused_windows_state: &mut SystemState<(Res<WinitSettings>, Query<&Window>)>,
|
focused_windows_state: &mut SystemState<(Res<WinitSettings>, Query<&Window>)>,
|
||||||
event_loop: &EventLoopWindowTarget<()>,
|
event_loop: &EventLoopWindowTarget<()>,
|
||||||
create_window_system_state: &mut SystemState<(
|
create_window: &mut SystemState<CreateWindowParams<Added<Window>>>,
|
||||||
Commands,
|
|
||||||
Query<(Entity, &mut Window), Added<Window>>,
|
|
||||||
EventWriter<WindowCreated>,
|
|
||||||
NonSendMut<WinitWindows>,
|
|
||||||
NonSendMut<AccessKitAdapters>,
|
|
||||||
ResMut<WinitActionHandlers>,
|
|
||||||
ResMut<AccessibilityRequested>,
|
|
||||||
)>,
|
|
||||||
app_exit_event_reader: &mut ManualEventReader<AppExit>,
|
app_exit_event_reader: &mut ManualEventReader<AppExit>,
|
||||||
redraw_event_reader: &mut ManualEventReader<RequestRedraw>,
|
redraw_event_reader: &mut ManualEventReader<RequestRedraw>,
|
||||||
) {
|
) {
|
||||||
@ -918,43 +755,22 @@ fn run_app_update_if_should(
|
|||||||
|
|
||||||
// create any new windows
|
// create any new windows
|
||||||
// (even if app did not update, some may have been created by plugin setup)
|
// (even if app did not update, some may have been created by plugin setup)
|
||||||
let (
|
create_windows(event_loop, create_window.get_mut(&mut app.world));
|
||||||
commands,
|
create_window.apply(&mut app.world);
|
||||||
mut windows,
|
|
||||||
event_writer,
|
|
||||||
winit_windows,
|
|
||||||
adapters,
|
|
||||||
handlers,
|
|
||||||
accessibility_requested,
|
|
||||||
) = create_window_system_state.get_mut(&mut app.world);
|
|
||||||
|
|
||||||
create_windows(
|
|
||||||
event_loop,
|
|
||||||
commands,
|
|
||||||
windows.iter_mut(),
|
|
||||||
event_writer,
|
|
||||||
winit_windows,
|
|
||||||
adapters,
|
|
||||||
handlers,
|
|
||||||
accessibility_requested,
|
|
||||||
);
|
|
||||||
|
|
||||||
create_window_system_state.apply(&mut app.world);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn react_to_resize(
|
fn react_to_resize(
|
||||||
window: &mut Mut<'_, Window>,
|
win: &mut Mut<'_, Window>,
|
||||||
size: winit::dpi::PhysicalSize<u32>,
|
size: winit::dpi::PhysicalSize<u32>,
|
||||||
event_writers: &mut WindowAndInputEventWriters<'_>,
|
window_resized: &mut EventWriter<WindowResized>,
|
||||||
window_entity: Entity,
|
window: Entity,
|
||||||
) {
|
) {
|
||||||
window
|
win.resolution
|
||||||
.resolution
|
|
||||||
.set_physical_resolution(size.width, size.height);
|
.set_physical_resolution(size.width, size.height);
|
||||||
|
|
||||||
event_writers.window_resized.send(WindowResized {
|
window_resized.send(WindowResized {
|
||||||
window: window_entity,
|
window,
|
||||||
width: window.width(),
|
width: win.width(),
|
||||||
height: window.height(),
|
height: win.height(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,13 @@
|
|||||||
use bevy_a11y::AccessibilityRequested;
|
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
event::EventWriter,
|
event::EventWriter,
|
||||||
prelude::{Changed, Component, Resource},
|
prelude::{Changed, Component},
|
||||||
|
query::QueryFilter,
|
||||||
removal_detection::RemovedComponents,
|
removal_detection::RemovedComponents,
|
||||||
system::{Commands, NonSendMut, Query, ResMut},
|
system::{NonSendMut, Query, SystemParamItem},
|
||||||
world::Mut,
|
|
||||||
};
|
};
|
||||||
use bevy_utils::{
|
use bevy_utils::tracing::{error, info, warn};
|
||||||
tracing::{error, info, warn},
|
use bevy_window::{RawHandleWrapper, Window, WindowClosed, WindowCreated, WindowResized};
|
||||||
EntityHashMap,
|
|
||||||
};
|
|
||||||
use bevy_window::{RawHandleWrapper, Window, WindowClosed, WindowCreated};
|
|
||||||
|
|
||||||
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
|
use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
|
||||||
use winit::{
|
use winit::{
|
||||||
@ -20,12 +16,11 @@ use winit::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
accessibility::{AccessKitAdapters, WinitActionHandlers},
|
|
||||||
converters::{
|
converters::{
|
||||||
self, convert_enabled_buttons, convert_window_level, convert_window_theme,
|
self, convert_enabled_buttons, convert_window_level, convert_window_theme,
|
||||||
convert_winit_theme,
|
convert_winit_theme,
|
||||||
},
|
},
|
||||||
get_best_videomode, get_fitting_videomode, WindowAndInputEventWriters, WinitWindows,
|
get_best_videomode, get_fitting_videomode, CreateWindowParams, WinitWindows,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// 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
|
||||||
@ -34,17 +29,19 @@ use crate::{
|
|||||||
/// If any of these entities are missing required components, those will be added with their
|
/// If any of these entities are missing required components, those will be added with their
|
||||||
/// default values.
|
/// default values.
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(crate) fn create_windows<'a>(
|
pub(crate) fn create_windows<F: QueryFilter + 'static>(
|
||||||
event_loop: &EventLoopWindowTarget<()>,
|
event_loop: &EventLoopWindowTarget<()>,
|
||||||
mut commands: Commands,
|
(
|
||||||
created_windows: impl Iterator<Item = (Entity, Mut<'a, Window>)>,
|
mut commands,
|
||||||
mut event_writer: EventWriter<WindowCreated>,
|
mut created_windows,
|
||||||
mut winit_windows: NonSendMut<WinitWindows>,
|
mut window_created_events,
|
||||||
mut adapters: NonSendMut<AccessKitAdapters>,
|
mut winit_windows,
|
||||||
mut handlers: ResMut<WinitActionHandlers>,
|
mut adapters,
|
||||||
accessibility_requested: ResMut<AccessibilityRequested>,
|
mut handlers,
|
||||||
|
accessibility_requested,
|
||||||
|
): SystemParamItem<CreateWindowParams<F>>,
|
||||||
) {
|
) {
|
||||||
for (entity, mut window) in created_windows {
|
for (entity, mut window) in &mut created_windows {
|
||||||
if winit_windows.get_window(entity).is_some() {
|
if winit_windows.get_window(entity).is_some() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -81,14 +78,10 @@ pub(crate) fn create_windows<'a>(
|
|||||||
window: window.clone(),
|
window: window.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
event_writer.send(WindowCreated { window: entity });
|
window_created_events.send(WindowCreated { window: entity });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cache for closing windows so we can get better debug information.
|
|
||||||
#[derive(Debug, Clone, Resource)]
|
|
||||||
pub struct WindowTitleCache(EntityHashMap<Entity, String>);
|
|
||||||
|
|
||||||
pub(crate) fn despawn_windows(
|
pub(crate) fn despawn_windows(
|
||||||
mut closed: RemovedComponents<Window>,
|
mut closed: RemovedComponents<Window>,
|
||||||
window_entities: Query<&Window>,
|
window_entities: Query<&Window>,
|
||||||
@ -123,7 +116,7 @@ pub struct CachedWindow {
|
|||||||
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>,
|
winit_windows: NonSendMut<WinitWindows>,
|
||||||
mut event_writers: WindowAndInputEventWriters<'_>,
|
mut window_resized: EventWriter<WindowResized>,
|
||||||
) {
|
) {
|
||||||
for (entity, mut window, mut cache) in &mut changed_windows {
|
for (entity, mut window, mut cache) in &mut changed_windows {
|
||||||
if let Some(winit_window) = winit_windows.get_window(entity) {
|
if let Some(winit_window) = winit_windows.get_window(entity) {
|
||||||
@ -161,7 +154,7 @@ pub(crate) fn changed_windows(
|
|||||||
window.resolution.physical_height(),
|
window.resolution.physical_height(),
|
||||||
);
|
);
|
||||||
if let Some(size_now) = winit_window.request_inner_size(physical_size) {
|
if let Some(size_now) = winit_window.request_inner_size(physical_size) {
|
||||||
crate::react_to_resize(&mut window, size_now, &mut event_writers, entity);
|
crate::react_to_resize(&mut window, size_now, &mut window_resized, entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user