diff --git a/.changes/is-always-on-top.md b/.changes/is-always-on-top.md new file mode 100644 index 000000000..0c69ca131 --- /dev/null +++ b/.changes/is-always-on-top.md @@ -0,0 +1,5 @@ +--- +"tao": patch +--- + +Add `Window::is_always_on_top` method to check if a window is always on top on macOS, Linux and Windows. diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index 896f064d5..069272311 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -569,6 +569,11 @@ impl Window { false } + pub fn is_always_on_top(&self) -> bool { + log::warn!("`Window::is_always_on_top` is ignored on Android"); + false + } + pub fn set_resizable(&self, _resizeable: bool) { warn!("`Window::set_resizable` is ignored on Android") } diff --git a/src/platform_impl/ios/window.rs b/src/platform_impl/ios/window.rs index 62164ae4b..d24f63d22 100644 --- a/src/platform_impl/ios/window.rs +++ b/src/platform_impl/ios/window.rs @@ -77,6 +77,11 @@ impl Inner { false } + pub fn is_always_on_top(&self) -> bool { + log::warn!("`Window::is_always_on_top` is ignored on iOS"); + false + } + pub fn request_redraw(&self) { unsafe { if self.gl_or_metal_backed { diff --git a/src/platform_impl/linux/window.rs b/src/platform_impl/linux/window.rs index 07a1ca9bc..a458f420e 100644 --- a/src/platform_impl/linux/window.rs +++ b/src/platform_impl/linux/window.rs @@ -60,6 +60,7 @@ pub struct Window { position: Rc<(AtomicI32, AtomicI32)>, size: Rc<(AtomicI32, AtomicI32)>, maximized: Rc, + is_always_on_top: Rc, minimized: Rc, fullscreen: RefCell>, inner_size_constraints: RefCell, @@ -258,11 +259,14 @@ impl Window { let max_clone = maximized.clone(); let minimized = Rc::new(AtomicBool::new(false)); let minimized_clone = minimized.clone(); + let is_always_on_top = Rc::new(AtomicBool::new(attributes.always_on_top)); + let is_always_on_top_clone = is_always_on_top.clone(); window.connect_window_state_event(move |_, event| { let state = event.new_window_state(); max_clone.store(state.contains(WindowState::MAXIMIZED), Ordering::Release); minimized_clone.store(state.contains(WindowState::ICONIFIED), Ordering::Release); + is_always_on_top_clone.store(state.contains(WindowState::ABOVE), Ordering::Release); glib::Propagation::Proceed }); @@ -304,6 +308,7 @@ impl Window { size, maximized, minimized, + is_always_on_top, fullscreen: RefCell::new(attributes.fullscreen), inner_size_constraints: RefCell::new(attributes.inner_size_constraints), preferred_theme: RefCell::new(preferred_theme), @@ -354,11 +359,14 @@ impl Window { let max_clone = maximized.clone(); let minimized = Rc::new(AtomicBool::new(false)); let minimized_clone = minimized.clone(); + let is_always_on_top = Rc::new(AtomicBool::new(false)); + let is_always_on_top_clone = is_always_on_top.clone(); window.connect_window_state_event(move |_, event| { let state = event.new_window_state(); max_clone.store(state.contains(WindowState::MAXIMIZED), Ordering::Release); minimized_clone.store(state.contains(WindowState::ICONIFIED), Ordering::Release); + is_always_on_top_clone.store(state.contains(WindowState::ABOVE), Ordering::Release); glib::Propagation::Proceed }); @@ -383,6 +391,7 @@ impl Window { size, maximized, minimized, + is_always_on_top, fullscreen: RefCell::new(None), inner_size_constraints: RefCell::new(WindowSizeConstraints::default()), preferred_theme: RefCell::new(None), @@ -577,6 +586,10 @@ impl Window { } } + pub fn is_always_on_top(&self) -> bool { + self.is_always_on_top.load(Ordering::Acquire) + } + pub fn is_maximized(&self) -> bool { self.maximized.load(Ordering::Acquire) } diff --git a/src/platform_impl/macos/window.rs b/src/platform_impl/macos/window.rs index 49d420ea5..0564a8f3f 100644 --- a/src/platform_impl/macos/window.rs +++ b/src/platform_impl/macos/window.rs @@ -990,6 +990,11 @@ impl UnownedWindow { is_visible == YES } + #[inline] + pub fn is_always_on_top(&self) -> bool { + unsafe { self.ns_window.level() == ffi::kCGFloatingWindowLevelKey } + } + #[inline] pub fn is_maximized(&self) -> bool { self.is_zoomed() diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index a3a1978c6..ea4f2a0dc 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -583,6 +583,14 @@ impl Window { window_state.window_flags.contains(WindowFlags::MAXIMIZED) } + #[inline] + pub fn is_always_on_top(&self) -> bool { + let window_state = self.window_state.lock(); + window_state + .window_flags + .contains(WindowFlags::ALWAYS_ON_TOP) + } + #[inline] pub fn is_minimized(&self) -> bool { unsafe { IsIconic(self.hwnd()) }.as_bool() diff --git a/src/window.rs b/src/window.rs index 3b9d57c60..abe11c25b 100644 --- a/src/window.rs +++ b/src/window.rs @@ -809,6 +809,16 @@ impl Window { self.window.is_focused() } + /// Indicates whether the window is always on top of other windows. + /// + /// ## Platform-specific + /// + /// - **iOS / Android:** Unsupported. + #[inline] + pub fn is_always_on_top(&self) -> bool { + self.window.is_always_on_top() + } + /// Sets whether the window is resizable or not. /// /// Note that making the window unresizable doesn't exempt you from handling `Resized`, as that event can still be