diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 4a06e2fb8e..9b22f96464 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -11,7 +11,6 @@ mod render; pub use alpha::*; use bevy_transform::TransformSystem; -use bevy_window::ModifiesWindows; pub use bundle::*; pub use fog::*; pub use light::*; @@ -199,8 +198,7 @@ impl Plugin for PbrPlugin { .in_set(SimulationLightSystems::AssignLightsToClusters) .after(TransformSystem::TransformPropagate) .after(VisibilitySystems::CheckVisibility) - .after(CameraUpdateSystem) - .after(ModifiesWindows), + .after(CameraUpdateSystem), ) .add_system( update_directional_light_cascades diff --git a/crates/bevy_render/src/camera/projection.rs b/crates/bevy_render/src/camera/projection.rs index 4228db69b8..27cb378511 100644 --- a/crates/bevy_render/src/camera/projection.rs +++ b/crates/bevy_render/src/camera/projection.rs @@ -7,7 +7,6 @@ use bevy_reflect::{ std_traits::ReflectDefault, FromReflect, GetTypeRegistration, Reflect, ReflectDeserialize, ReflectSerialize, }; -use bevy_window::ModifiesWindows; use serde::{Deserialize, Serialize}; /// Adds [`Camera`](crate::camera::Camera) driver systems for a given projection type. @@ -43,7 +42,6 @@ impl Plugin for CameraPro .add_system( crate::camera::camera_system:: .in_set(CameraUpdateSystem) - .after(ModifiesWindows) // We assume that each camera will only have one projection, // so we can ignore ambiguities with all other monomorphizations. // FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481. diff --git a/crates/bevy_text/src/lib.rs b/crates/bevy_text/src/lib.rs index 85757cd7af..86fa55e8f8 100644 --- a/crates/bevy_text/src/lib.rs +++ b/crates/bevy_text/src/lib.rs @@ -28,7 +28,6 @@ use bevy_asset::AddAsset; use bevy_ecs::prelude::*; use bevy_render::{camera::CameraUpdateSystem, ExtractSchedule, RenderApp}; use bevy_sprite::SpriteSystem; -use bevy_window::ModifiesWindows; use std::num::NonZeroUsize; #[derive(Default)] @@ -83,7 +82,6 @@ impl Plugin for TextPlugin { .add_system( update_text2d_layout .in_base_set(CoreSet::PostUpdate) - .after(ModifiesWindows) // Potential conflict: `Assets` // In practice, they run independently since `bevy_render::camera_update_system` // will only ever observe its own render target, and `update_text2d_layout` diff --git a/crates/bevy_ui/src/lib.rs b/crates/bevy_ui/src/lib.rs index fc26a25a21..8ea3b45410 100644 --- a/crates/bevy_ui/src/lib.rs +++ b/crates/bevy_ui/src/lib.rs @@ -34,7 +34,6 @@ use bevy_app::prelude::*; use bevy_ecs::prelude::*; use bevy_input::InputSystem; use bevy_transform::TransformSystem; -use bevy_window::ModifiesWindows; use stack::ui_stack_system; pub use stack::UiStack; use update::update_clipping_system; @@ -110,7 +109,6 @@ impl Plugin for UiPlugin { widget::text_system .in_base_set(CoreSet::PostUpdate) .before(UiSystem::Flex) - .after(ModifiesWindows) // Potential conflict: `Assets` // In practice, they run independently since `bevy_render::camera_update_system` // will only ever observe its own render target, and `widget::text_system` @@ -135,8 +133,7 @@ impl Plugin for UiPlugin { .add_system( flex_node_system .in_set(UiSystem::Flex) - .before(TransformSystem::TransformPropagate) - .after(ModifiesWindows), + .before(TransformSystem::TransformPropagate), ) .add_system(ui_stack_system.in_set(UiSystem::Stack)) .add_system( diff --git a/crates/bevy_window/src/lib.rs b/crates/bevy_window/src/lib.rs index 417a11ddb9..03b270c693 100644 --- a/crates/bevy_window/src/lib.rs +++ b/crates/bevy_window/src/lib.rs @@ -137,9 +137,6 @@ impl Plugin for WindowPlugin { } } -#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)] -pub struct ModifiesWindows; - /// Defines the specific conditions the application should exit on #[derive(Clone)] pub enum ExitCondition { diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index 63b66c1ac3..29a839fec5 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -6,7 +6,7 @@ mod winit_config; mod winit_windows; use bevy_ecs::system::{SystemParam, SystemState}; -use system::{changed_window, create_window, despawn_window}; +use system::{changed_window, create_window, despawn_window, CachedWindow}; pub use winit_config::*; pub use winit_windows::*; @@ -26,7 +26,7 @@ use bevy_utils::{ }; use bevy_window::{ exit_on_all_closed, CursorEntered, CursorLeft, CursorMoved, FileDragAndDrop, Ime, - ModifiesWindows, ReceivedCharacter, RequestRedraw, Window, WindowBackendScaleFactorChanged, + ReceivedCharacter, RequestRedraw, Window, WindowBackendScaleFactorChanged, WindowCloseRequested, WindowCreated, WindowFocused, WindowMoved, WindowResized, WindowScaleFactorChanged, }; @@ -39,7 +39,6 @@ use winit::{ event_loop::{ControlFlow, EventLoop, EventLoopBuilder, EventLoopWindowTarget}, }; -use crate::system::WinitWindowInfo; #[cfg(target_arch = "wasm32")] use crate::web_resize::{CanvasParentResizeEventChannel, CanvasParentResizePlugin}; @@ -70,7 +69,6 @@ impl Plugin for WinitPlugin { app.init_non_send_resource::() .init_resource::() .set_runner(winit_runner) - .configure_set(ModifiesWindows.in_base_set(CoreSet::PostUpdate)) // exit_on_all_closed only uses the query to determine if the query is empty, // and so doesn't care about ordering relative to changed_window .add_systems( @@ -79,7 +77,7 @@ impl Plugin for WinitPlugin { // Update the state of the window before attempting to despawn to ensure consistent event ordering despawn_window.after(changed_window), ) - .in_set(ModifiesWindows), + .in_base_set(CoreSet::Last), ); #[cfg(target_arch = "wasm32")] @@ -349,7 +347,7 @@ pub fn winit_runner(mut app: App) { // Fetch and prepare details from the world let mut system_state: SystemState<( NonSend, - Query<(&mut Window, &mut WinitWindowInfo)>, + Query<(&mut Window, &mut CachedWindow)>, WindowEvents, InputEvents, CursorEvents, @@ -376,7 +374,7 @@ pub fn winit_runner(mut app: App) { return; }; - let (mut window, mut info) = + let (mut window, mut cache) = if let Ok((window, info)) = window_query.get_mut(window_entity) { (window, info) } else { @@ -394,7 +392,6 @@ pub fn winit_runner(mut app: App) { window .resolution .set_physical_resolution(size.width, size.height); - info.last_winit_size = size; window_events.window_resized.send(WindowResized { window: window_entity, @@ -421,11 +418,7 @@ pub fn winit_runner(mut app: App) { window.resolution.physical_height() as f64 - position.y, ); - // bypassing change detection to not trigger feedback loop with system `changed_window` - // this system change the cursor position in winit - window - .bypass_change_detection() - .set_physical_cursor_position(Some(physical_position)); + window.set_physical_cursor_position(Some(physical_position)); cursor_events.cursor_moved.send(CursorMoved { window: window_entity, @@ -439,14 +432,7 @@ pub fn winit_runner(mut app: App) { }); } WindowEvent::CursorLeft { .. } => { - // Component - if let Ok((mut window, _)) = window_query.get_mut(window_entity) { - // bypassing change detection to not trigger feedback loop with system `changed_window` - // this system change the cursor position in winit - window - .bypass_change_detection() - .set_physical_cursor_position(None); - } + window.set_physical_cursor_position(None); cursor_events.cursor_left.send(CursorLeft { window: window_entity, @@ -594,6 +580,10 @@ pub fn winit_runner(mut app: App) { }, _ => {} } + + if window.is_changed() { + cache.window = window.clone(); + } } event::Event::DeviceEvent { event: DeviceEvent::MouseMotion { delta: (x, y) }, diff --git a/crates/bevy_winit/src/system.rs b/crates/bevy_winit/src/system.rs index d3ba832cb2..ecef9a20f3 100644 --- a/crates/bevy_winit/src/system.rs +++ b/crates/bevy_winit/src/system.rs @@ -39,20 +39,19 @@ pub(crate) fn create_window<'a>( mut winit_windows: NonSendMut, #[cfg(target_arch = "wasm32")] event_channel: ResMut, ) { - for (entity, mut component) in created_windows { + for (entity, mut window) in created_windows { if winit_windows.get_window(entity).is_some() { continue; } info!( "Creating new window {:?} ({:?})", - component.title.as_str(), + window.title.as_str(), entity ); - let winit_window = winit_windows.create_window(event_loop, entity, &component); - let current_size = winit_window.inner_size(); - component + let winit_window = winit_windows.create_window(event_loop, entity, &window); + window .resolution .set_scale_factor(winit_window.scale_factor()); commands @@ -61,18 +60,14 @@ pub(crate) fn create_window<'a>( window_handle: winit_window.raw_window_handle(), display_handle: winit_window.raw_display_handle(), }) - .insert(WinitWindowInfo { - previous: component.clone(), - last_winit_size: PhysicalSize { - width: current_size.width, - height: current_size.height, - }, + .insert(CachedWindow { + window: window.clone(), }); #[cfg(target_arch = "wasm32")] { - if component.fit_canvas_to_parent { - let selector = if let Some(selector) = &component.canvas { + if window.fit_canvas_to_parent { + let selector = if let Some(selector) = &window.canvas { selector } else { WINIT_CANVAS_SELECTOR @@ -106,11 +101,10 @@ pub(crate) fn despawn_window( } } -/// Previous state of the window so we can check sub-portions of what actually was changed. +/// The cached state of the window so we can check which properties were changed from within the app. #[derive(Debug, Clone, Component)] -pub struct WinitWindowInfo { - pub previous: Window, - pub last_winit_size: PhysicalSize, +pub struct CachedWindow { + pub window: Window, } // Detect changes to the window and update the winit window accordingly. @@ -121,18 +115,16 @@ pub struct WinitWindowInfo { // - [`Window::canvas`] currently cannot be updated after startup, not entirely sure if it would work well with the // event channel stuff. pub(crate) fn changed_window( - mut changed_windows: Query<(Entity, &mut Window, &mut WinitWindowInfo), Changed>, + mut changed_windows: Query<(Entity, &mut Window, &mut CachedWindow), Changed>, winit_windows: NonSendMut, ) { - for (entity, mut window, mut info) in &mut changed_windows { - let previous = &info.previous; - + for (entity, mut window, mut cache) in &mut changed_windows { if let Some(winit_window) = winit_windows.get_window(entity) { - if window.title != previous.title { + if window.title != cache.window.title { winit_window.set_title(window.title.as_str()); } - if window.mode != previous.mode { + if window.mode != cache.window.mode { let new_mode = match window.mode { bevy_window::WindowMode::BorderlessFullscreen => { Some(winit::window::Fullscreen::Borderless(None)) @@ -156,19 +148,15 @@ pub(crate) fn changed_window( winit_window.set_fullscreen(new_mode); } } - if window.resolution != previous.resolution { + if window.resolution != cache.window.resolution { let physical_size = PhysicalSize::new( window.resolution.physical_width(), window.resolution.physical_height(), ); - // Prevents "window.resolution values set from a winit resize event" from - // being set here, creating feedback loops. - if physical_size != info.last_winit_size { - winit_window.set_inner_size(physical_size); - } + winit_window.set_inner_size(physical_size); } - if window.physical_cursor_position() != previous.physical_cursor_position() { + if window.physical_cursor_position() != cache.window.physical_cursor_position() { if let Some(physical_position) = window.physical_cursor_position() { let inner_size = winit_window.inner_size(); @@ -184,21 +172,21 @@ pub(crate) fn changed_window( } } - if window.cursor.icon != previous.cursor.icon { + if window.cursor.icon != cache.window.cursor.icon { winit_window.set_cursor_icon(converters::convert_cursor_icon(window.cursor.icon)); } - if window.cursor.grab_mode != previous.cursor.grab_mode { + if window.cursor.grab_mode != cache.window.cursor.grab_mode { crate::winit_windows::attempt_grab(winit_window, window.cursor.grab_mode); } - if window.cursor.visible != previous.cursor.visible { + if window.cursor.visible != cache.window.cursor.visible { winit_window.set_cursor_visible(window.cursor.visible); } - if window.cursor.hit_test != previous.cursor.hit_test { + if window.cursor.hit_test != cache.window.cursor.hit_test { if let Err(err) = winit_window.set_cursor_hittest(window.cursor.hit_test) { - window.cursor.hit_test = previous.cursor.hit_test; + window.cursor.hit_test = cache.window.cursor.hit_test; warn!( "Could not set cursor hit test for window {:?}: {:?}", window.title, err @@ -206,19 +194,19 @@ pub(crate) fn changed_window( } } - if window.decorations != previous.decorations + if window.decorations != cache.window.decorations && window.decorations != winit_window.is_decorated() { winit_window.set_decorations(window.decorations); } - if window.resizable != previous.resizable + if window.resizable != cache.window.resizable && window.resizable != winit_window.is_resizable() { winit_window.set_resizable(window.resizable); } - if window.resize_constraints != previous.resize_constraints { + if window.resize_constraints != cache.window.resize_constraints { let constraints = window.resize_constraints.check_constraints(); let min_inner_size = LogicalSize { width: constraints.min_width, @@ -235,7 +223,7 @@ pub(crate) fn changed_window( } } - if window.position != previous.position { + if window.position != cache.window.position { if let Some(position) = crate::winit_window_position( &window.position, &window.resolution, @@ -262,42 +250,42 @@ pub(crate) fn changed_window( winit_window.set_minimized(minimized); } - if window.focused != previous.focused && window.focused { + if window.focused != cache.window.focused && window.focused { winit_window.focus_window(); } - if window.window_level != previous.window_level { + if window.window_level != cache.window.window_level { winit_window.set_window_level(convert_window_level(window.window_level)); } // Currently unsupported changes - if window.transparent != previous.transparent { - window.transparent = previous.transparent; + if window.transparent != cache.window.transparent { + window.transparent = cache.window.transparent; warn!( "Winit does not currently support updating transparency after window creation." ); } #[cfg(target_arch = "wasm32")] - if window.canvas != previous.canvas { - window.canvas = previous.canvas.clone(); + if window.canvas != cache.window.canvas { + window.canvas = cache.window.canvas.clone(); warn!( "Bevy currently doesn't support modifying the window canvas after initialization." ); } - if window.ime_enabled != previous.ime_enabled { + if window.ime_enabled != cache.window.ime_enabled { winit_window.set_ime_allowed(window.ime_enabled); } - if window.ime_position != previous.ime_position { + if window.ime_position != cache.window.ime_position { winit_window.set_ime_position(LogicalPosition::new( window.ime_position.x, window.ime_position.y, )); } - info.previous = window.clone(); + cache.window = window.clone(); } } }