diff --git a/komorebi/src/monitor.rs b/komorebi/src/monitor.rs index 07d990a2..e7044bb2 100644 --- a/komorebi/src/monitor.rs +++ b/komorebi/src/monitor.rs @@ -370,20 +370,20 @@ impl Monitor { .position(|w| w.hwnd == foreground_hwnd); if let Some(idx) = floating_window_index { - let window = workspace.floating_windows_mut().remove(idx); + if let Some(window) = workspace.floating_windows_mut().remove(idx) { + let workspaces = self.workspaces_mut(); + #[allow(clippy::option_if_let_else)] + let target_workspace = match workspaces.get_mut(target_workspace_idx) { + None => { + workspaces.resize(target_workspace_idx + 1, Workspace::default()); + workspaces.get_mut(target_workspace_idx).unwrap() + } + Some(workspace) => workspace, + }; - let workspaces = self.workspaces_mut(); - #[allow(clippy::option_if_let_else)] - let target_workspace = match workspaces.get_mut(target_workspace_idx) { - None => { - workspaces.resize(target_workspace_idx + 1, Workspace::default()); - workspaces.get_mut(target_workspace_idx).unwrap() - } - Some(workspace) => workspace, - }; - - target_workspace.floating_windows_mut().push(window); - target_workspace.set_layer(WorkspaceLayer::Floating); + target_workspace.floating_windows_mut().push_back(window); + target_workspace.set_layer(WorkspaceLayer::Floating); + } } else { let container = workspace .remove_focused_container() diff --git a/komorebi/src/process_event.rs b/komorebi/src/process_event.rs index bb34ed31..2f8447fe 100644 --- a/komorebi/src/process_event.rs +++ b/komorebi/src/process_event.rs @@ -402,7 +402,7 @@ impl WindowManager { matches!(workspace.layer, WorkspaceLayer::Floating) && !should_float && workspace.tile; - workspace.floating_windows_mut().push(window); + workspace.floating_windows_mut().push_back(window); workspace.set_layer(WorkspaceLayer::Floating); if center_spawned_floats { let mut floating_window = window; @@ -630,7 +630,7 @@ impl WindowManager { window.focus(self.mouse_follows_focus)?; } } else if window_management_behaviour.float_override { - workspace.floating_windows_mut().push(window); + workspace.floating_windows_mut().push_back(window); self.update_focused_workspace(false, false)?; } else { match window_management_behaviour.current_behaviour { diff --git a/komorebi/src/ring.rs b/komorebi/src/ring.rs index 325c14f8..3dd7d49c 100644 --- a/komorebi/src/ring.rs +++ b/komorebi/src/ring.rs @@ -76,4 +76,30 @@ macro_rules! impl_ring_elements { } } }; + ($name:ty, $element:ident, $el_name:literal) => { + paste::paste! { + impl $name { + pub const fn [<$el_name:lower s>](&self) -> &VecDeque<$element> { + self.[<$el_name:lower s>].elements() + } + + pub fn [<$el_name:lower s_mut>](&mut self) -> &mut VecDeque<$element> { + self.[<$el_name:lower s>].elements_mut() + } + + #[allow(dead_code)] + pub fn [](&self) -> Option<&$element> { + self.[<$el_name:lower s>].focused() + } + + pub const fn [](&self) -> usize { + self.[<$el_name:lower s>].focused_idx() + } + + pub fn [](&mut self) -> Option<&mut $element> { + self.[<$el_name:lower s>].focused_mut() + } + } + } + }; } diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 5138bcb1..f758f18e 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -968,7 +968,7 @@ impl WindowManager { if op.floating { target_workspace .floating_windows_mut() - .push(Window::from(op.hwnd)); + .push_back(Window::from(op.hwnd)); } else { //TODO(alex-ds13): should this take into account the target workspace //`window_container_behaviour`? @@ -1145,18 +1145,18 @@ impl WindowManager { // There is no need to physically move the floating window between areas with // `move_to_area` because the user already did that, so we only need to transfer the // window to the target `floating_windows` - let floating_window = origin_workspace.floating_windows_mut().remove(idx); + if let Some(floating_window) = origin_workspace.floating_windows_mut().remove(idx) { + let target_workspace = self + .monitors_mut() + .get_mut(target_monitor_idx) + .ok_or_else(|| anyhow!("there is no monitor at this idx"))? + .focused_workspace_mut() + .ok_or_else(|| anyhow!("there is no focused workspace for this monitor"))?; - let target_workspace = self - .monitors_mut() - .get_mut(target_monitor_idx) - .ok_or_else(|| anyhow!("there is no monitor at this idx"))? - .focused_workspace_mut() - .ok_or_else(|| anyhow!("there is no focused workspace for this monitor"))?; - - target_workspace - .floating_windows_mut() - .push(floating_window); + target_workspace + .floating_windows_mut() + .push_back(floating_window); + } } else if origin_workspace .monocle_container() .as_ref() @@ -1830,7 +1830,7 @@ impl WindowManager { .position(|w| w.hwnd == foreground_hwnd); let floating_window = - floating_window_index.map(|idx| workspace.floating_windows_mut().remove(idx)); + floating_window_index.and_then(|idx| workspace.floating_windows_mut().remove(idx)); let container = if floating_window_index.is_none() { Some( workspace @@ -1859,7 +1859,7 @@ impl WindowManager { .ok_or_else(|| anyhow!("there is no focused workspace on target monitor"))?; if let Some(window) = floating_window { - target_workspace.floating_windows_mut().push(window); + target_workspace.floating_windows_mut().push_back(window); target_workspace.set_layer(WorkspaceLayer::Floating); Window::from(window.hwnd) .move_to_area(¤t_area, target_monitor.work_area_size())?; @@ -1978,7 +1978,7 @@ impl WindowManager { direction: OperationDirection, ) -> Result<()> { let mouse_follows_focus = self.mouse_follows_focus; - let focused_workspace = self.focused_workspace()?; + let focused_workspace = self.focused_workspace_mut()?; let mut target_idx = None; let len = focused_workspace.floating_windows().len(); @@ -2123,7 +2123,7 @@ impl WindowManager { window.focus(mouse_follows_focus)?; cross_monitor_monocle_or_max = true; } - } else { + } else if focused_workspace.layer() == &WorkspaceLayer::Tiling { match direction { OperationDirection::Left => match focused_workspace.layout() { Layout::Default(layout) => { @@ -2159,8 +2159,26 @@ impl WindowManager { } if !cross_monitor_monocle_or_max { - if let Ok(focused_window) = self.focused_window_mut() { - focused_window.focus(self.mouse_follows_focus)?; + let ws = self.focused_workspace_mut()?; + if ws.is_empty() { + // This is to remove focus from the previous monitor + let desktop_window = Window::from(WindowsApi::desktop_window()?); + + match WindowsApi::raise_and_focus_window(desktop_window.hwnd) { + Ok(()) => {} + Err(error) => { + tracing::warn!("{} {}:{}", error, file!(), line!()); + } + } + } else if ws.layer() == &WorkspaceLayer::Floating && !ws.floating_windows().is_empty() { + if let Some(window) = ws.focused_floating_window() { + window.focus(self.mouse_follows_focus)?; + } + } else { + ws.set_layer(WorkspaceLayer::Tiling); + if let Ok(focused_window) = self.focused_window() { + focused_window.focus(self.mouse_follows_focus)?; + } } } @@ -2875,7 +2893,7 @@ impl WindowManager { let window = workspace .floating_windows_mut() - .last_mut() + .back_mut() .ok_or_else(|| anyhow!("there is no floating window"))?; window.center(&work_area)?; diff --git a/komorebi/src/workspace.rs b/komorebi/src/workspace.rs index 8005eaa0..ccb6bfb1 100644 --- a/komorebi/src/workspace.rs +++ b/komorebi/src/workspace.rs @@ -62,8 +62,7 @@ pub struct Workspace { #[serde(skip_serializing_if = "Option::is_none")] #[getset(get_copy = "pub", set = "pub")] pub maximized_window_restore_idx: Option, - #[getset(get = "pub", get_mut = "pub")] - pub floating_windows: Vec, + pub floating_windows: Ring, #[getset(get = "pub", get_mut = "pub", set = "pub")] pub layout: Layout, #[getset(get = "pub", get_mut = "pub", set = "pub")] @@ -117,6 +116,7 @@ impl Display for WorkspaceLayer { } impl_ring_elements!(Workspace, Container); +impl_ring_elements!(Workspace, Window, "floating_window"); impl Default for Workspace { fn default() -> Self { @@ -127,7 +127,7 @@ impl Default for Workspace { maximized_window: None, maximized_window_restore_idx: None, monocle_container_restore_idx: None, - floating_windows: Vec::default(), + floating_windows: Ring::default(), layout: Layout::Default(DefaultLayout::BSP), layout_rules: vec![], layout_flip: None, @@ -325,13 +325,13 @@ impl Workspace { } else if let Some(maximized_window) = self.maximized_window() { maximized_window.restore(); maximized_window.focus(mouse_follows_focus)?; - } else if let Some(floating_window) = self.floating_windows().first() { + } else if let Some(floating_window) = self.focused_floating_window() { floating_window.focus(mouse_follows_focus)?; } } else if let Some(maximized_window) = self.maximized_window() { maximized_window.restore(); maximized_window.focus(mouse_follows_focus)?; - } else if let Some(floating_window) = self.floating_windows().first() { + } else if let Some(floating_window) = self.focused_floating_window() { floating_window.focus(mouse_follows_focus)?; } @@ -1113,7 +1113,7 @@ impl Workspace { window }; - self.floating_windows_mut().push(window); + self.floating_windows_mut().push_back(window); Ok(()) } @@ -1431,24 +1431,11 @@ impl Workspace { pub fn new_maximized_window(&mut self) -> Result<()> { let focused_idx = self.focused_container_idx(); - let foreground_hwnd = WindowsApi::foreground_window()?; - let mut floating_window = None; - if !self.floating_windows().is_empty() { - let mut focused_floating_window_idx = None; - for (i, w) in self.floating_windows().iter().enumerate() { - if w.hwnd == foreground_hwnd { - focused_floating_window_idx = Option::from(i); - } - } - - if let Some(idx) = focused_floating_window_idx { - floating_window = Option::from(self.floating_windows_mut().remove(idx)); - } - } - - if let Some(floating_window) = floating_window { - self.set_maximized_window(Option::from(floating_window)); + if matches!(self.layer, WorkspaceLayer::Floating) { + let floating_window_idx = self.focused_floating_window_idx(); + let floating_window = self.floating_windows_mut().remove(floating_window_idx); + self.set_maximized_window(floating_window); self.set_maximized_window_restore_idx(Option::from(focused_idx)); if let Some(window) = self.maximized_window() { window.maximize(); @@ -1563,7 +1550,7 @@ impl Workspace { let hwnd = WindowsApi::foreground_window().ok()?; let mut idx = None; - for (i, window) in self.floating_windows.iter().enumerate() { + for (i, window) in self.floating_windows().iter().enumerate() { if hwnd == window.hwnd { idx = Option::from(i); } @@ -1572,8 +1559,8 @@ impl Workspace { match idx { None => None, Some(idx) => { - if self.floating_windows.get(idx).is_some() { - Option::from(self.floating_windows_mut().remove(idx)) + if self.floating_windows().get(idx).is_some() { + self.floating_windows_mut().remove(idx) } else { None }