diff --git a/CHANGELOG.md b/CHANGELOG.md index 79ad4d31..08338e90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ And please only add new entries to the top of this list, right below the `# Unre # Unreleased +- Add `Window::is_minimized`. - On X11, fix errors handled during `register_xlib_error_hook` invocation bleeding into winit. - Add `Window::has_focus`. - On Windows, fix `Window::set_minimized(false)` not working for windows minimized by `Win + D` hotkey. diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index 9c2c7606..d71e9521 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -974,6 +974,10 @@ impl Window { pub fn set_minimized(&self, _minimized: bool) {} + pub fn is_minimized(&self) -> Option { + None + } + pub fn set_maximized(&self, _maximized: bool) {} pub fn is_maximized(&self) -> bool { diff --git a/src/platform_impl/ios/window.rs b/src/platform_impl/ios/window.rs index 1f0061b2..28e2473c 100644 --- a/src/platform_impl/ios/window.rs +++ b/src/platform_impl/ios/window.rs @@ -216,6 +216,11 @@ impl Inner { warn!("`Window::set_minimized` is ignored on iOS") } + pub fn is_minimized(&self) -> Option { + warn!("`Window::is_minimized` is ignored on iOS"); + None + } + pub fn set_maximized(&self, _maximized: bool) { warn!("`Window::set_maximized` is ignored on iOS") } diff --git a/src/platform_impl/linux/mod.rs b/src/platform_impl/linux/mod.rs index 44d4bf14..efefeea6 100644 --- a/src/platform_impl/linux/mod.rs +++ b/src/platform_impl/linux/mod.rs @@ -464,6 +464,11 @@ impl Window { x11_or_wayland!(match self; Window(w) => w.set_minimized(minimized)) } + #[inline] + pub fn is_minimized(&self) -> Option { + x11_or_wayland!(match self; Window(w) => w.is_minimized()) + } + #[inline] pub(crate) fn fullscreen(&self) -> Option { x11_or_wayland!(match self; Window(w) => w.fullscreen()) diff --git a/src/platform_impl/linux/wayland/window/mod.rs b/src/platform_impl/linux/wayland/window/mod.rs index e6f6b9f1..b6894556 100644 --- a/src/platform_impl/linux/wayland/window/mod.rs +++ b/src/platform_impl/linux/wayland/window/mod.rs @@ -483,6 +483,11 @@ impl Window { self.decorated.load(Ordering::Relaxed) } + #[inline] + pub fn is_minimized(&self) -> Option { + None + } + #[inline] pub fn set_minimized(&self, minimized: bool) { // You can't unminimize the window on Wayland. diff --git a/src/platform_impl/linux/x11/window.rs b/src/platform_impl/linux/x11/window.rs index 9f61d22d..49036b19 100644 --- a/src/platform_impl/linux/x11/window.rs +++ b/src/platform_impl/linux/x11/window.rs @@ -802,6 +802,20 @@ impl UnownedWindow { self.xconn.primary_monitor() } + #[inline] + pub fn is_minimized(&self) -> Option { + let state_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_STATE\0") }; + let state = self + .xconn + .get_property(self.xwindow, state_atom, ffi::XA_ATOM); + let hidden_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_STATE_HIDDEN\0") }; + + Some(match state { + Ok(atoms) => atoms.iter().any(|atom: &ffi::Atom| *atom == hidden_atom), + _ => false, + }) + } + fn set_minimized_inner(&self, minimized: bool) -> util::Flusher<'_> { unsafe { if minimized { diff --git a/src/platform_impl/macos/window.rs b/src/platform_impl/macos/window.rs index c9ab15a3..7ceaa823 100644 --- a/src/platform_impl/macos/window.rs +++ b/src/platform_impl/macos/window.rs @@ -864,6 +864,11 @@ impl WinitWindow { } } + #[inline] + pub fn is_minimized(&self) -> Option { + Some(self.isMiniaturized()) + } + #[inline] pub fn set_maximized(&self, maximized: bool) { let is_zoomed = self.is_zoomed(); diff --git a/src/platform_impl/orbital/window.rs b/src/platform_impl/orbital/window.rs index 384684f6..eda103d9 100644 --- a/src/platform_impl/orbital/window.rs +++ b/src/platform_impl/orbital/window.rs @@ -276,6 +276,11 @@ impl Window { #[inline] pub fn set_minimized(&self, _minimized: bool) {} + #[inline] + pub fn is_minimized(&self) -> Option { + None + } + #[inline] pub fn set_maximized(&self, _maximized: bool) {} diff --git a/src/platform_impl/web/window.rs b/src/platform_impl/web/window.rs index 48e0ba44..15d82ac0 100644 --- a/src/platform_impl/web/window.rs +++ b/src/platform_impl/web/window.rs @@ -287,6 +287,12 @@ impl Window { // Intentionally a no-op, as canvases cannot be 'minimized' } + #[inline] + pub fn is_minimized(&self) -> Option { + // Canvas cannot be 'minimized' + Some(false) + } + #[inline] pub fn set_maximized(&self, _maximized: bool) { // Intentionally a no-op, as canvases cannot be 'maximized' diff --git a/src/platform_impl/windows/util.rs b/src/platform_impl/windows/util.rs index 5f09bee6..1f94220c 100644 --- a/src/platform_impl/windows/util.rs +++ b/src/platform_impl/windows/util.rs @@ -24,9 +24,10 @@ use windows_sys::{ Input::KeyboardAndMouse::GetActiveWindow, WindowsAndMessaging::{ ClipCursor, GetClientRect, GetClipCursor, GetSystemMetrics, GetWindowRect, - ShowCursor, IDC_APPSTARTING, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_HELP, IDC_IBEAM, - IDC_NO, IDC_SIZEALL, IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE, IDC_SIZEWE, IDC_WAIT, - SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN, SM_XVIRTUALSCREEN, SM_YVIRTUALSCREEN, + IsIconic, ShowCursor, IDC_APPSTARTING, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_HELP, + IDC_IBEAM, IDC_NO, IDC_SIZEALL, IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE, IDC_SIZEWE, + IDC_WAIT, SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN, SM_XVIRTUALSCREEN, + SM_YVIRTUALSCREEN, }, }, }, @@ -135,6 +136,10 @@ pub fn is_focused(window: HWND) -> bool { window == unsafe { GetActiveWindow() } } +pub fn is_minimized(window: HWND) -> bool { + unsafe { IsIconic(window) != false.into() } +} + pub fn get_instance_handle() -> HINSTANCE { // Gets the instance handle by taking the address of the // pseudo-variable created by the microsoft linker: diff --git a/src/platform_impl/windows/window.rs b/src/platform_impl/windows/window.rs index a82a42f0..9894d064 100644 --- a/src/platform_impl/windows/window.rs +++ b/src/platform_impl/windows/window.rs @@ -40,7 +40,7 @@ use windows_sys::Win32::{ }, WindowsAndMessaging::{ CreateWindowExW, FlashWindowEx, GetClientRect, GetCursorPos, GetForegroundWindow, - GetSystemMetrics, GetWindowPlacement, GetWindowTextLengthW, GetWindowTextW, IsIconic, + GetSystemMetrics, GetWindowPlacement, GetWindowTextLengthW, GetWindowTextW, IsWindowVisible, LoadCursorW, PeekMessageW, PostMessageW, RegisterClassExW, SetCursor, SetCursorPos, SetForegroundWindow, SetWindowDisplayAffinity, SetWindowPlacement, SetWindowPos, SetWindowTextW, CS_HREDRAW, CS_VREDRAW, CW_USEDEFAULT, FLASHWINFO, @@ -462,7 +462,7 @@ impl Window { let window = self.window.clone(); let window_state = Arc::clone(&self.window_state); - let is_minimized = self.is_minimized(); + let is_minimized = util::is_minimized(self.hwnd()); self.thread_executor.execute_in_thread(move || { let _ = &window; @@ -475,6 +475,11 @@ impl Window { }); } + #[inline] + pub fn is_minimized(&self) -> Option { + Some(util::is_minimized(self.hwnd())) + } + #[inline] pub fn set_maximized(&self, maximized: bool) { let window = self.window.clone(); @@ -494,11 +499,6 @@ impl Window { window_state.window_flags.contains(WindowFlags::MAXIMIZED) } - #[inline] - pub fn is_minimized(&self) -> bool { - unsafe { IsIconic(self.hwnd()) == 1 } - } - #[inline] pub fn fullscreen(&self) -> Option { let window_state = self.window_state_lock(); @@ -810,7 +810,7 @@ impl Window { let window_flags = self.window_state_lock().window_flags(); let is_visible = window_flags.contains(WindowFlags::VISIBLE); - let is_minimized = window_flags.contains(WindowFlags::MINIMIZED); + let is_minimized = util::is_minimized(self.hwnd()); let is_foreground = window.0 == unsafe { GetForegroundWindow() }; if is_visible && !is_minimized && !is_foreground { diff --git a/src/window.rs b/src/window.rs index 3b8431a3..ab431ccc 100644 --- a/src/window.rs +++ b/src/window.rs @@ -842,6 +842,23 @@ impl Window { self.window.set_minimized(minimized); } + /// Gets the window's current minimized state. + /// + /// `None` will be returned, if the minimized state couldn't be determined. + /// + /// ## Note + /// + /// - You shouldn't stop rendering for minimized windows, however you could lower the fps. + /// + /// ## Platform-specific + /// + /// - **Wayland**: always `None`. + /// - **iOS / Android / Web / Orbital:** Unsupported. + #[inline] + pub fn is_minimized(&self) -> Option { + self.window.is_minimized() + } + /// Sets the window to maximized or back. /// /// ## Platform-specific