From b0c34802627f00f9beb22f4ce88db53b0ac5e10c Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Fri, 30 Jul 2021 10:44:28 -0700 Subject: [PATCH] fix(wm): float/monocle toggle, invisible borders This commit fixes issues with toggling on and off Monocle and Floating Window mode by ensuring that the relevant windows are always at the top of the Z order, and in the latter case, ensuring that the top visible window is used to search the local floating window state of the process. After some experimenting I seem to have been able to adjust to remove all of the invisible window borders by default, so if desired, a user can now have no gaps at all. Also upgraded to the latest version of the windows-rs crate since I saw it was available. Thankfully no breaking changes. --- Cargo.lock | 12 ++-- bindings/Cargo.toml | 4 +- komorebi-core/src/rect.rs | 2 +- komorebi/src/main.rs | 2 + komorebi/src/monitor.rs | 8 ++- komorebi/src/process_command.rs | 2 +- komorebi/src/process_event.rs | 28 ++++++++-- komorebi/src/set_window_position.rs | 38 +++++++++++++ komorebi/src/window.rs | 38 ++++++++++++- komorebi/src/window_manager.rs | 25 +++++---- komorebi/src/windows_api.rs | 85 ++++++++++++++++++++++++----- komorebi/src/workspace.rs | 24 +++++--- 12 files changed, 212 insertions(+), 56 deletions(-) create mode 100644 komorebi/src/set_window_position.rs diff --git a/Cargo.lock b/Cargo.lock index 46e3c1ba..e4134f02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1074,9 +1074,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.17.2" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f1c7f11b289e450f78d55dd9dc09ae91c6ae8faed980bbf3e3a4c8f166ac259" +checksum = "68088239696c06152844eadc03d262f088932cce50c67e4ace86e19d95e976fe" dependencies = [ "const-sha1", "windows_gen", @@ -1085,15 +1085,15 @@ dependencies = [ [[package]] name = "windows_gen" -version = "0.17.2" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57f5facfb04bc84b5fcd27018266d90ce272e11f8b91745dfdd47282e8e0607e" +checksum = "cf583322dc423ee021035b358e535015f7fd163058a31e2d37b99a939141121d" [[package]] name = "windows_macros" -version = "0.17.2" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c32753c378262520a4fa70c2e4389f4649e751faab2a887090567cff192d299" +checksum = "58acfb8832e9f707f8997bd161e537a1c1f603e60a5bd9c3cf53484fdcc998f3" dependencies = [ "syn", "windows_gen", diff --git a/bindings/Cargo.toml b/bindings/Cargo.toml index 2e995854..d2550407 100644 --- a/bindings/Cargo.toml +++ b/bindings/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -windows = "0.17.2" +windows = "0.18" [build-dependencies] -windows = "0.17.2" \ No newline at end of file +windows = "0.18" \ No newline at end of file diff --git a/komorebi-core/src/rect.rs b/komorebi-core/src/rect.rs index ab0fc545..d7b8c34c 100644 --- a/komorebi-core/src/rect.rs +++ b/komorebi-core/src/rect.rs @@ -1,6 +1,6 @@ use bindings::Windows::Win32::Foundation::RECT; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub struct Rect { pub left: i32, pub top: i32, diff --git a/komorebi/src/main.rs b/komorebi/src/main.rs index c494a698..f2ad7e9c 100644 --- a/komorebi/src/main.rs +++ b/komorebi/src/main.rs @@ -24,6 +24,7 @@ mod monitor; mod process_command; mod process_event; mod ring; +mod set_window_position; mod styles; mod window; mod window_manager; @@ -117,6 +118,7 @@ fn main() -> Result<()> { tracing::error!( "received ctrl-c, restoring all hidden windows and terminating process" ); + wm.lock().unwrap().restore_all_windows(); std::process::exit(130); } diff --git a/komorebi/src/monitor.rs b/komorebi/src/monitor.rs index 81c2fba8..b26f844b 100644 --- a/komorebi/src/monitor.rs +++ b/komorebi/src/monitor.rs @@ -30,15 +30,17 @@ pub fn new(id: isize, monitor_size: Rect, work_area_size: Rect) -> Monitor { } impl Monitor { - pub fn load_focused_workspace(&mut self) { + pub fn load_focused_workspace(&mut self) -> Result<()> { let focused_idx = self.focused_workspace_idx(); for (i, workspace) in self.workspaces_mut().iter_mut().enumerate() { if i == focused_idx { - workspace.restore(); + workspace.restore()?; } else { workspace.hide(); } } + + Ok(()) } pub fn add_container(&mut self, container: Container) -> Result<()> { @@ -121,7 +123,7 @@ impl Monitor { pub fn update_focused_workspace(&mut self) -> Result<()> { tracing::info!("updating workspace: {}", self.focused_workspace_idx()); - let work_area = self.work_area_size().clone(); + let work_area = *self.work_area_size(); self.focused_workspace_mut() .context("there is no workspace")? diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 6933411d..660d6c1e 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -116,7 +116,7 @@ impl WindowManager { } SocketMessage::Retile => { for monitor in self.monitors_mut() { - let work_area = monitor.work_area_size().clone(); + let work_area = *monitor.work_area_size(); monitor .focused_workspace_mut() .context("there is no workspace")? diff --git a/komorebi/src/process_event.rs b/komorebi/src/process_event.rs index eebde1de..c5f3f715 100644 --- a/komorebi/src/process_event.rs +++ b/komorebi/src/process_event.rs @@ -52,7 +52,7 @@ impl WindowManager { } for (i, monitor) in self.monitors_mut().iter_mut().enumerate() { - let work_area = monitor.work_area_size().clone(); + let work_area = *monitor.work_area_size(); for (j, workspace) in monitor.workspaces_mut().iter_mut().enumerate() { let reaped_orphans = workspace.reap_orphans()?; if reaped_orphans.0 > 0 || reaped_orphans.1 > 0 { @@ -89,9 +89,19 @@ impl WindowManager { self.update_focused_workspace(false)?; } } - WindowManagerEvent::FocusChange(_, window) => self - .focused_workspace_mut()? - .focus_container_by_window(window.hwnd)?, + WindowManagerEvent::FocusChange(_, window) => { + let workspace = self.focused_workspace_mut()?; + if workspace + .floating_windows() + .iter() + .any(|w| w.hwnd == window.hwnd) + { + return Ok(()); + } + + self.focused_workspace_mut()? + .focus_container_by_window(window.hwnd)?; + } WindowManagerEvent::Show(_, window) => { let workspace = self.focused_workspace_mut()?; @@ -103,8 +113,16 @@ impl WindowManager { WindowManagerEvent::MoveResizeStart(_, _window) => { // TODO: Implement dragging resize (one day) } - WindowManagerEvent::MoveResizeEnd(_, _window) => { + WindowManagerEvent::MoveResizeEnd(_, window) => { let workspace = self.focused_workspace_mut()?; + if workspace + .floating_windows() + .iter() + .any(|w| w.hwnd == window.hwnd) + { + return Ok(()); + } + let focused_idx = workspace.focused_container_idx(); match workspace.container_idx_from_current_point() { diff --git a/komorebi/src/set_window_position.rs b/komorebi/src/set_window_position.rs new file mode 100644 index 00000000..c0e6110c --- /dev/null +++ b/komorebi/src/set_window_position.rs @@ -0,0 +1,38 @@ +use bitflags::bitflags; + +use bindings::Windows::Win32::UI::WindowsAndMessaging::SWP_ASYNCWINDOWPOS; +use bindings::Windows::Win32::UI::WindowsAndMessaging::SWP_DEFERERASE; +use bindings::Windows::Win32::UI::WindowsAndMessaging::SWP_DRAWFRAME; +use bindings::Windows::Win32::UI::WindowsAndMessaging::SWP_FRAMECHANGED; +use bindings::Windows::Win32::UI::WindowsAndMessaging::SWP_HIDEWINDOW; +use bindings::Windows::Win32::UI::WindowsAndMessaging::SWP_NOACTIVATE; +use bindings::Windows::Win32::UI::WindowsAndMessaging::SWP_NOCOPYBITS; +use bindings::Windows::Win32::UI::WindowsAndMessaging::SWP_NOMOVE; +use bindings::Windows::Win32::UI::WindowsAndMessaging::SWP_NOOWNERZORDER; +use bindings::Windows::Win32::UI::WindowsAndMessaging::SWP_NOREDRAW; +use bindings::Windows::Win32::UI::WindowsAndMessaging::SWP_NOREPOSITION; +use bindings::Windows::Win32::UI::WindowsAndMessaging::SWP_NOSENDCHANGING; +use bindings::Windows::Win32::UI::WindowsAndMessaging::SWP_NOSIZE; +use bindings::Windows::Win32::UI::WindowsAndMessaging::SWP_NOZORDER; +use bindings::Windows::Win32::UI::WindowsAndMessaging::SWP_SHOWWINDOW; + +bitflags! { + #[derive(Default)] + pub struct SetWindowPosition: u32 { + const ASYNC_WINDOW_POS = SWP_ASYNCWINDOWPOS.0; + const DEFER_ERASE = SWP_DEFERERASE.0; + const DRAW_FRAME = SWP_DRAWFRAME.0; + const FRAME_CHANGED = SWP_FRAMECHANGED.0; + const HIDE_WINDOW = SWP_HIDEWINDOW.0; + const NO_ACTIVATE = SWP_NOACTIVATE.0; + const NO_COPY_BITS = SWP_NOCOPYBITS.0; + const NO_MOVE = SWP_NOMOVE.0; + const NO_OWNER_Z_ORDER = SWP_NOOWNERZORDER.0; + const NO_REDRAW = SWP_NOREDRAW.0; + const NO_REPOSITION = SWP_NOREPOSITION.0; + const NO_SEND_CHANGING = SWP_NOSENDCHANGING.0; + const NO_SIZE = SWP_NOSIZE.0; + const NO_Z_ORDER = SWP_NOZORDER.0; + const SHOW_WINDOW = SWP_SHOWWINDOW.0; + } +} diff --git a/komorebi/src/window.rs b/komorebi/src/window.rs index d3c3bc7a..141c69ba 100644 --- a/komorebi/src/window.rs +++ b/komorebi/src/window.rs @@ -50,8 +50,42 @@ impl Window { HWND(self.hwnd) } - pub fn set_position(&mut self, layout: &Rect) -> Result<()> { - WindowsApi::set_window_pos(self.hwnd(), layout) + pub fn set_position(&mut self, layout: &Rect, top: bool) -> Result<()> { + // NOTE: This is how the border variable below was calculated; every time this code was + // run on any window in any position, the generated border was always the same, so I am + // hard coding the border Rect to avoid two calls to set_window_pos and making the screen + // flicker on container/window movement. Still not 100% sure if this is DPI-aware. + + // Set the new position first to be able to get the extended frame bounds + // WindowsApi::set_window_pos(self.hwnd(), layout, false, false)?; + // let mut rect = WindowsApi::window_rect(self.hwnd())?; + + // Get the extended frame bounds of the new position + // let frame = WindowsApi::window_rect_with_extended_frame_bounds(self.hwnd())?; + + // Calculate the invisible border diff + // let border = Rect { + // left: frame.left - rect.left, + // top: frame.top - rect.top, + // right: rect.right - frame.right, + // bottom: rect.bottom - frame.bottom, + // }; + + let mut rect = *layout; + let border = Rect { + left: 12, + top: 0, + right: 24, + bottom: 12, + }; + + // Remove the invisible border + rect.left -= border.left; + rect.top -= border.top; + rect.right += border.right; + rect.bottom += border.bottom; + + WindowsApi::position_window(self.hwnd(), &rect, top) } pub fn hide(&self) { diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 96873cb4..8cbe423e 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -106,7 +106,7 @@ impl WindowManager { .context("there is no monitor")?; target_monitor.add_container(container)?; - target_monitor.load_focused_workspace(); + target_monitor.load_focused_workspace()?; if follow { self.focus_monitor(idx)?; @@ -118,7 +118,7 @@ impl WindowManager { pub fn move_container_to_workspace(&mut self, idx: usize, follow: bool) -> Result<()> { let monitor = self.focused_monitor_mut().context("there is no monitor")?; monitor.move_container_to_workspace(idx, follow)?; - monitor.load_focused_workspace(); + monitor.load_focused_workspace()?; self.update_focused_workspace(true) } @@ -210,7 +210,7 @@ impl WindowManager { } pub fn toggle_float(&mut self) -> Result<()> { - let hwnd = WindowsApi::foreground_window()?; + let hwnd = WindowsApi::top_visible_window()?; let workspace = self.focused_workspace_mut()?; let mut is_floating_window = false; @@ -222,12 +222,14 @@ impl WindowManager { } if is_floating_window { + tracing::info!("unfloating window"); self.unfloat_window()?; + self.update_focused_workspace(true) } else { + tracing::info!("floating window"); self.float_window()?; + self.update_focused_workspace(false) } - - self.update_focused_workspace(true) } pub fn float_window(&mut self) -> Result<()> { @@ -251,7 +253,7 @@ impl WindowManager { bottom: half_weight, }; - window.set_position(¢er)?; + window.set_position(¢er, true)?; window.focus()?; Ok(()) @@ -270,7 +272,7 @@ impl WindowManager { Some(_) => self.monocle_off()?, } - self.update_focused_workspace(true) + self.update_focused_workspace(false) } pub fn monocle_on(&mut self) -> Result<()> { @@ -366,7 +368,7 @@ impl WindowManager { .get_mut(monitor_idx) .context("there is no monitor")?; - let work_area = monitor.work_area_size().clone(); + let work_area = *monitor.work_area_size(); let focused_workspace_idx = monitor.focused_workspace_idx(); let workspace = monitor @@ -472,11 +474,10 @@ impl WindowManager { } pub fn focused_monitor_work_area(&self) -> Result { - Ok(self + Ok(*self .focused_monitor() .context("there is no monitor")? - .work_area_size() - .clone()) + .work_area_size()) } pub fn focus_monitor(&mut self, idx: usize) -> Result<()> { @@ -521,7 +522,7 @@ impl WindowManager { .context("there is no workspace")?; monitor.focus_workspace(idx)?; - monitor.load_focused_workspace(); + monitor.load_focused_workspace()?; self.update_focused_workspace(true) } diff --git a/komorebi/src/windows_api.rs b/komorebi/src/windows_api.rs index a7cedc36..0e9ffb11 100644 --- a/komorebi/src/windows_api.rs +++ b/komorebi/src/windows_api.rs @@ -12,17 +12,22 @@ use bindings::Windows::Win32::Foundation::HWND; use bindings::Windows::Win32::Foundation::LPARAM; use bindings::Windows::Win32::Foundation::POINT; use bindings::Windows::Win32::Foundation::PWSTR; +use bindings::Windows::Win32::Foundation::RECT; use bindings::Windows::Win32::Graphics::Dwm::DwmGetWindowAttribute; use bindings::Windows::Win32::Graphics::Dwm::DWMWA_CLOAKED; +use bindings::Windows::Win32::Graphics::Dwm::DWMWA_EXTENDED_FRAME_BOUNDS; +use bindings::Windows::Win32::Graphics::Dwm::DWMWINDOWATTRIBUTE; use bindings::Windows::Win32::Graphics::Dwm::DWM_CLOAKED_APP; use bindings::Windows::Win32::Graphics::Dwm::DWM_CLOAKED_INHERITED; use bindings::Windows::Win32::Graphics::Dwm::DWM_CLOAKED_SHELL; use bindings::Windows::Win32::Graphics::Gdi::EnumDisplayMonitors; +use bindings::Windows::Win32::Graphics::Gdi::GetMonitorInfoW; use bindings::Windows::Win32::Graphics::Gdi::MonitorFromWindow; use bindings::Windows::Win32::Graphics::Gdi::HDC; +use bindings::Windows::Win32::Graphics::Gdi::HMONITOR; use bindings::Windows::Win32::Graphics::Gdi::MONITORENUMPROC; +use bindings::Windows::Win32::Graphics::Gdi::MONITORINFO; use bindings::Windows::Win32::Graphics::Gdi::MONITOR_DEFAULTTONEAREST; -use bindings::Windows::Win32::Graphics::Gdi::{GetMonitorInfoW, HMONITOR, MONITORINFO}; use bindings::Windows::Win32::System::Threading::AttachThreadInput; use bindings::Windows::Win32::System::Threading::GetCurrentProcessId; use bindings::Windows::Win32::System::Threading::GetCurrentThreadId; @@ -35,7 +40,8 @@ use bindings::Windows::Win32::UI::KeyboardAndMouseInput::SetFocus; use bindings::Windows::Win32::UI::WindowsAndMessaging::AllowSetForegroundWindow; use bindings::Windows::Win32::UI::WindowsAndMessaging::EnumWindows; use bindings::Windows::Win32::UI::WindowsAndMessaging::GetCursorPos; -use bindings::Windows::Win32::UI::WindowsAndMessaging::GetForegroundWindow; +use bindings::Windows::Win32::UI::WindowsAndMessaging::GetTopWindow; +use bindings::Windows::Win32::UI::WindowsAndMessaging::GetWindow; use bindings::Windows::Win32::UI::WindowsAndMessaging::GetWindowLongPtrW; use bindings::Windows::Win32::UI::WindowsAndMessaging::GetWindowRect; use bindings::Windows::Win32::UI::WindowsAndMessaging::GetWindowTextW; @@ -51,9 +57,11 @@ use bindings::Windows::Win32::UI::WindowsAndMessaging::SetWindowPos; use bindings::Windows::Win32::UI::WindowsAndMessaging::ShowWindow; use bindings::Windows::Win32::UI::WindowsAndMessaging::GWL_EXSTYLE; use bindings::Windows::Win32::UI::WindowsAndMessaging::GWL_STYLE; +use bindings::Windows::Win32::UI::WindowsAndMessaging::GW_HWNDNEXT; use bindings::Windows::Win32::UI::WindowsAndMessaging::HWND_NOTOPMOST; +use bindings::Windows::Win32::UI::WindowsAndMessaging::HWND_TOPMOST; +use bindings::Windows::Win32::UI::WindowsAndMessaging::SET_WINDOW_POS_FLAGS; use bindings::Windows::Win32::UI::WindowsAndMessaging::SHOW_WINDOW_CMD; -use bindings::Windows::Win32::UI::WindowsAndMessaging::SWP_NOACTIVATE; use bindings::Windows::Win32::UI::WindowsAndMessaging::SW_HIDE; use bindings::Windows::Win32::UI::WindowsAndMessaging::SW_RESTORE; use bindings::Windows::Win32::UI::WindowsAndMessaging::WINDOW_LONG_PTR_INDEX; @@ -61,10 +69,12 @@ use bindings::Windows::Win32::UI::WindowsAndMessaging::WNDENUMPROC; use komorebi_core::Rect; use crate::container::Container; +use crate::monitor; use crate::monitor::Monitor; use crate::ring::Ring; +use crate::set_window_position::SetWindowPosition; +use crate::windows_callbacks; use crate::workspace::Workspace; -use crate::{monitor, windows_callbacks}; pub enum WindowsResult { Err(E), @@ -211,16 +221,23 @@ impl WindowsApi { unsafe { MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST) }.0 } - pub fn set_window_pos(hwnd: HWND, layout: &Rect) -> Result<()> { + pub fn position_window(hwnd: HWND, layout: &Rect, top: bool) -> Result<()> { + let flags = SetWindowPosition::NO_ACTIVATE; + + let position = if top { HWND_TOPMOST } else { HWND_NOTOPMOST }; + Self::set_window_pos(hwnd, layout, position, flags.bits()) + } + + pub fn set_window_pos(hwnd: HWND, layout: &Rect, position: HWND, flags: u32) -> Result<()> { Result::from(WindowsResult::from(unsafe { SetWindowPos( hwnd, - HWND_NOTOPMOST, + position, layout.left, layout.top, layout.right, layout.bottom, - SWP_NOACTIVATE, + SET_WINDOW_POS_FLAGS(flags), ) })) } @@ -255,8 +272,29 @@ impl WindowsApi { } } - pub fn foreground_window() -> Result { - Result::from(WindowsResult::from(unsafe { GetForegroundWindow().0 })) + pub fn top_window() -> Result { + Result::from(WindowsResult::from(unsafe { GetTopWindow(HWND::NULL).0 })) + } + + pub fn next_window(hwnd: HWND) -> Result { + Result::from(WindowsResult::from(unsafe { + GetWindow(hwnd, GW_HWNDNEXT).0 + })) + } + + pub fn top_visible_window() -> Result { + let hwnd = Self::top_window()?; + let mut next_hwnd = hwnd; + + while next_hwnd != 0 { + if Self::is_window_visible(HWND(next_hwnd)) { + return Ok(next_hwnd); + } + + next_hwnd = Self::next_window(HWND(next_hwnd))?; + } + + Err(eyre::anyhow!("could not find next window")) } pub fn window_rect(hwnd: HWND) -> Result { @@ -417,18 +455,35 @@ impl WindowsApi { Ok(String::from_utf16(&class[0..len as usize])?) } - pub fn is_window_cloaked(hwnd: HWND) -> Result { - let mut cloaked: u32 = 0; - + pub fn dwm_get_window_attribute( + hwnd: HWND, + attribute: DWMWINDOWATTRIBUTE, + value: &mut T, + ) -> Result<()> { unsafe { DwmGetWindowAttribute( hwnd, - std::mem::transmute::<_, u32>(DWMWA_CLOAKED), - (&mut cloaked as *mut u32).cast(), - u32::try_from(std::mem::size_of::())?, + std::mem::transmute::<_, u32>(attribute), + (value as *mut T).cast(), + u32::try_from(std::mem::size_of::())?, )?; } + Ok(()) + } + + #[allow(dead_code)] + pub fn window_rect_with_extended_frame_bounds(hwnd: HWND) -> Result { + let mut rect = RECT::default(); + Self::dwm_get_window_attribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &mut rect)?; + + Ok(Rect::from(rect)) + } + + pub fn is_window_cloaked(hwnd: HWND) -> Result { + let mut cloaked: u32 = 0; + Self::dwm_get_window_attribute(hwnd, DWMWA_CLOAKED, &mut cloaked)?; + Ok(matches!( cloaked, DWM_CLOAKED_APP | DWM_CLOAKED_SHELL | DWM_CLOAKED_INHERITED diff --git a/komorebi/src/workspace.rs b/komorebi/src/workspace.rs index 93f3e712..af6fcb8b 100644 --- a/komorebi/src/workspace.rs +++ b/komorebi/src/workspace.rs @@ -37,8 +37,8 @@ impl Default for Workspace { floating_windows: Vec::default(), layout: Layout::BSP, layout_flip: None, - workspace_padding: Option::from(20), - container_padding: Option::from(5), + workspace_padding: Option::from(10), + container_padding: Option::from(10), latest_layout: vec![], } } @@ -53,22 +53,28 @@ impl Workspace { } } - pub fn restore(&mut self) { - for container in self.containers_mut() { + pub fn restore(&mut self) -> Result<()> { + let idx = self.focused_container_idx(); + for (i, container) in self.containers_mut().iter_mut().enumerate() { if let Some(window) = container.visible_window_mut() { window.restore(); + + if idx == i { + window.focus()?; + } } } + + Ok(()) } pub fn update(&mut self, work_area: &Rect) -> Result<()> { - let mut adjusted_work_area = work_area.clone(); + let mut adjusted_work_area = *work_area; adjusted_work_area.add_padding(self.workspace_padding()); if let Some(container) = self.monocle_container_mut() { if let Some(window) = container.focused_window_mut() { - window.set_position(&adjusted_work_area)?; - window.focus()?; + window.set_position(&adjusted_work_area, true)?; } } else { let layouts = self.layout().calculate( @@ -81,7 +87,7 @@ impl Workspace { let windows = self.visible_windows_mut(); for (i, window) in windows.into_iter().enumerate() { if let (Some(window), Some(layout)) = (window, layouts.get(i)) { - window.set_position(layout)?; + window.set_position(layout, false)?; } } @@ -453,7 +459,7 @@ impl Workspace { } pub fn remove_focused_floating_window(&mut self) -> Option { - let hwnd = WindowsApi::foreground_window().ok()?; + let hwnd = WindowsApi::top_visible_window().ok()?; let mut idx = None; for (i, window) in self.floating_windows.iter().enumerate() {