From 126eee49caa8f8e3e86eb4317d892be881d13be0 Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sun, 15 Aug 2021 07:31:42 -0700 Subject: [PATCH] fix(wm): don't duplicate windows across workspaces There are some applications such as Firefox where, if they are focused when a workspace switch takes place, an additional Show event will be fired. This results in the window being associated with both the original workspace and the workspace being switched to. This commit adds a check when handling WindowManagerEvent::Show to try and ignore events from windows that are already known to be associated with other workspaces (which are not the currently focused workspace). --- komorebi/src/container.rs | 2 +- komorebi/src/process_event.rs | 21 +++++++++++++++++++++ komorebi/src/workspace.rs | 6 +++++- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/komorebi/src/container.rs b/komorebi/src/container.rs index e1d9d6df..ec555895 100644 --- a/komorebi/src/container.rs +++ b/komorebi/src/container.rs @@ -26,7 +26,7 @@ impl Default for Container { } } -impl PartialEq for &Container { +impl PartialEq for Container { fn eq(&self, other: &Self) -> bool { self.id == other.id } diff --git a/komorebi/src/process_event.rs b/komorebi/src/process_event.rs index 82f73d33..cc5769cb 100644 --- a/komorebi/src/process_event.rs +++ b/komorebi/src/process_event.rs @@ -138,6 +138,27 @@ impl WindowManager { } } + // There are some applications such as Firefox where, if they are focused when a + // workspace switch takes place, it will fire an additional Show event, which will + // result in them being associated with both the original workspace and the workspace + // being switched to. This loop is to try to ensure that we don't end up with + // duplicates across multiple workspaces, as it results in ghost layout tiles. + for (i, monitor) in self.monitors().iter().enumerate() { + for (j, workspace) in monitor.workspaces().iter().enumerate() { + if workspace.container_for_window(window.hwnd).is_some() + && i != self.focused_monitor_idx() + && j != monitor.focused_workspace_idx() + { + tracing::debug!( + "ignoring show event for window already associated with another workspace" + ); + + window.hide(); + return Ok(()); + } + } + } + let workspace = self.focused_workspace_mut()?; if workspace.containers().is_empty() || !workspace.contains_window(window.hwnd) { diff --git a/komorebi/src/workspace.rs b/komorebi/src/workspace.rs index 8aed25ec..edc79689 100644 --- a/komorebi/src/workspace.rs +++ b/komorebi/src/workspace.rs @@ -182,6 +182,10 @@ impl Workspace { Ok((hwnds.len() + floating_hwnds.len(), container_ids.len())) } + pub fn container_for_window(&self, hwnd: isize) -> Option<&Container> { + self.containers().get(self.container_idx_for_window(hwnd)?) + } + pub fn focus_container_by_window(&mut self, hwnd: isize) -> Result<()> { let container_idx = self .container_idx_for_window(hwnd) @@ -249,7 +253,7 @@ impl Workspace { self.containers_mut().remove(idx) } - fn container_idx_for_window(&mut self, hwnd: isize) -> Option { + fn container_idx_for_window(&self, hwnd: isize) -> Option { let mut idx = None; for (i, x) in self.containers().iter().enumerate() { if x.contains_window(hwnd) {