diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index 301c1c4efe82a..d5d191d70d2ca 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -213,6 +213,16 @@ pub struct Window { /// /// - iOS / Android / Web: Unsupported. pub window_theme: Option, + /// Sets the window's visibility. + /// + /// If `false`, this will hide the window the window completely, it won't appear on the screen or in the task bar. + /// If `true`, this will show the window. + /// Note that this doesn't change its focused or minimized state. + /// + /// ## Platform-specific + /// + /// - **Android / Wayland / Web:** Unsupported. + pub visible: bool, } impl Default for Window { @@ -239,6 +249,7 @@ impl Default for Window { prevent_default_event_handling: true, canvas: None, window_theme: None, + visible: true, } } } @@ -1016,7 +1027,7 @@ pub enum WindowTheme { /// /// ## Platform-specific /// -/// **`iOS`**, **`Android`**, and the **`Web`** do not have window control buttons. +/// **`iOS`**, **`Android`**, and the **`Web`** do not have window control buttons. /// /// On some **`Linux`** environments these values have no effect. #[derive(Debug, Copy, Clone, PartialEq, Reflect)] diff --git a/crates/bevy_winit/src/system.rs b/crates/bevy_winit/src/system.rs index af7f41e405ab1..0be99b24cc73e 100644 --- a/crates/bevy_winit/src/system.rs +++ b/crates/bevy_winit/src/system.rs @@ -308,6 +308,10 @@ pub(crate) fn changed_windows( winit_window.set_theme(window.window_theme.map(convert_window_theme)); } + if window.visible != cache.window.visible { + winit_window.set_visible(window.visible); + } + cache.window = window.clone(); } } diff --git a/crates/bevy_winit/src/winit_windows.rs b/crates/bevy_winit/src/winit_windows.rs index e38203b819945..4c7f30df6fa82 100644 --- a/crates/bevy_winit/src/winit_windows.rs +++ b/crates/bevy_winit/src/winit_windows.rs @@ -96,7 +96,8 @@ impl WinitWindows { .with_resizable(window.resizable) .with_enabled_buttons(convert_enabled_buttons(window.enabled_buttons)) .with_decorations(window.decorations) - .with_transparent(window.transparent); + .with_transparent(window.transparent) + .with_visible(window.visible); let constraints = window.resize_constraints.check_constraints(); let min_inner_size = LogicalSize { @@ -167,7 +168,6 @@ impl WinitWindows { ); adapters.insert(entity, adapter); handlers.insert(entity, handler); - winit_window.set_visible(true); // Do not set the grab mode on window creation if it's none. It can fail on mobile. if window.cursor.grab_mode != CursorGrabMode::None { diff --git a/examples/window/window_settings.rs b/examples/window/window_settings.rs index 3a7687ee92155..4623c45308c8a 100644 --- a/examples/window/window_settings.rs +++ b/examples/window/window_settings.rs @@ -6,6 +6,7 @@ use bevy::{ prelude::*, window::{CursorGrabMode, PresentMode, WindowLevel, WindowTheme}, }; +use bevy_internal::window::PrimaryWindow; fn main() { App::new() @@ -24,6 +25,10 @@ fn main() { maximize: false, ..Default::default() }, + // This will spawn an invisible window + // The window will be made visible in the setup() function + // This is useful when you want to avoid the white window that shows up before the GPU is ready to render the app. + visible: false, ..default() }), ..default() @@ -31,6 +36,7 @@ fn main() { LogDiagnosticsPlugin::default(), FrameTimeDiagnosticsPlugin, )) + .add_systems(Startup, setup) .add_systems( Update, ( @@ -46,6 +52,13 @@ fn main() { .run(); } +fn setup(mut primary_window: Query<&mut Window, With>) { + // At this point the gpu is ready to show the app so we can make the window visible + // There might still be a white frame when doing it in startup. + // Alternatively, you could have a system that waits a few seconds before making the window visible. + primary_window.single_mut().visible = true; +} + /// This system toggles the vsync mode when pressing the button V. /// You'll see fps increase displayed in the console. fn toggle_vsync(input: Res>, mut windows: Query<&mut Window>) {