diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index ccc764210eb31..868ec8a98a92e 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -294,6 +294,7 @@ pub struct Window { fit_canvas_to_parent: bool, command_queue: Vec, alpha_mode: CompositeAlphaMode, + always_on_top: bool, } /// A command to be sent to a window. /// @@ -369,6 +370,10 @@ pub enum WindowCommand { SetResizeConstraints { resize_constraints: WindowResizeConstraints, }, + /// Set whether the window is always on top. + SetAlwaysOnTop { + always_on_top: bool, + }, Close, } @@ -438,6 +443,7 @@ impl Window { fit_canvas_to_parent: window_descriptor.fit_canvas_to_parent, command_queue: Vec::new(), alpha_mode: window_descriptor.alpha_mode, + always_on_top: window_descriptor.always_on_top, } } /// Get the window's [`WindowId`]. @@ -796,6 +802,18 @@ impl Window { resolution: UVec2::new(self.physical_width, self.physical_height), }); } + /// Get whether or not the window is always on top. + #[inline] + pub fn always_on_top(&self) -> bool { + self.always_on_top + } + + /// Set whether of not the window is always on top. + pub fn set_always_on_top(&mut self, always_on_top: bool) { + self.always_on_top = always_on_top; + self.command_queue + .push(WindowCommand::SetAlwaysOnTop { always_on_top }); + } /// Close the operating system window corresponding to this [`Window`]. /// /// This will also lead to this [`Window`] being removed from the @@ -972,6 +990,12 @@ pub struct WindowDescriptor { pub fit_canvas_to_parent: bool, /// Specifies how the alpha channel of the textures should be handled during compositing. pub alpha_mode: CompositeAlphaMode, + /// Sets the window to always be on top of other windows. + /// + /// ## Platform-specific + /// - iOS / Android / Web: Unsupported. + /// - Linux (Wayland): Unsupported. + pub always_on_top: bool, } impl Default for WindowDescriptor { @@ -994,6 +1018,7 @@ impl Default for WindowDescriptor { canvas: None, fit_canvas_to_parent: false, alpha_mode: CompositeAlphaMode::Auto, + always_on_top: false, } } } diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index c8df1552bc2b1..0ef1cb6e5c330 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -226,6 +226,10 @@ fn change_window( window.set_max_inner_size(Some(max_inner_size)); } } + bevy_window::WindowCommand::SetAlwaysOnTop { always_on_top } => { + let window = winit_windows.get_window(id).unwrap(); + window.set_always_on_top(always_on_top); + } bevy_window::WindowCommand::Close => { // Since we have borrowed `windows` to iterate through them, we can't remove the window from it. // Add the removal requests to a queue to solve this diff --git a/crates/bevy_winit/src/winit_windows.rs b/crates/bevy_winit/src/winit_windows.rs index 5d803c944b2bc..3364c850b3c28 100644 --- a/crates/bevy_winit/src/winit_windows.rs +++ b/crates/bevy_winit/src/winit_windows.rs @@ -72,7 +72,8 @@ impl WinitWindows { } .with_resizable(window_descriptor.resizable) .with_decorations(window_descriptor.decorations) - .with_transparent(window_descriptor.transparent), + .with_transparent(window_descriptor.transparent) + .with_always_on_top(window_descriptor.always_on_top), }; let constraints = window_descriptor.resize_constraints.check_constraints(); diff --git a/examples/window/window_settings.rs b/examples/window/window_settings.rs index 06e1b5686f62d..a8996c6e85901 100644 --- a/examples/window/window_settings.rs +++ b/examples/window/window_settings.rs @@ -15,6 +15,7 @@ fn main() { width: 500., height: 300., present_mode: PresentMode::AutoVsync, + always_on_top: true, ..default() }, ..default() @@ -25,6 +26,7 @@ fn main() { .add_system(toggle_cursor) .add_system(toggle_vsync) .add_system(cycle_cursor_icon) + .add_system(toggle_always_on_top) .run(); } @@ -43,6 +45,28 @@ fn toggle_vsync(input: Res>, mut windows: ResMut) { } } +/// This system toggles whether the window is always on top when pressing the T button +/// You'll notice it won't be covered by other windows. +/// +/// This feature only works on some platforms. Please check the +/// [documentation](https://docs.rs/bevy/latest/bevy/prelude/struct.WindowDescriptor.html#structfield.always_on_top) +/// for more details. +fn toggle_always_on_top(input: Res>, mut windows: ResMut) { + if input.just_pressed(KeyCode::T) { + let window = windows.primary_mut(); + + let on_top: bool = window.always_on_top(); + + if on_top { + info!("UNLOCKING WINDOW"); + } else { + info!("LOCKING WINDOW ON TOP"); + } + + window.set_always_on_top(!on_top); + } +} + /// This system will then change the title during execution fn change_title(time: Res