diff --git a/komorebi-bar/src/bar.rs b/komorebi-bar/src/bar.rs index e9e337ee..a8e0cae7 100644 --- a/komorebi-bar/src/bar.rs +++ b/komorebi-bar/src/bar.rs @@ -802,7 +802,7 @@ impl Komobar { pub fn position_bar(&self) { if let Some(hwnd) = self.hwnd { let window = komorebi_client::Window::from(hwnd); - match window.set_position(&self.size_rect, false) { + match window.set_position(&self.size_rect, false, false) { Ok(_) => { tracing::info!("updated bar position"); } diff --git a/komorebi/src/core/rect.rs b/komorebi/src/core/rect.rs index 04ad653d..35d08e2a 100644 --- a/komorebi/src/core/rect.rs +++ b/komorebi/src/core/rect.rs @@ -85,6 +85,15 @@ impl Rect { && point.1 <= self.top + self.bottom } + pub fn contains_within_horizontal_bounds(&self, other: &Rect) -> bool { + let left_corner_is_within_bounds = + other.left >= self.left && other.left < self.left + self.right; + let right_corner_is_within_bounds = other.left + other.right >= self.left + && other.left + other.right < self.left + self.right; + + left_corner_is_within_bounds || right_corner_is_within_bounds + } + #[must_use] pub const fn scale(&self, system_dpi: i32, rect_dpi: i32) -> Rect { Rect { diff --git a/komorebi/src/stackbar_manager/stackbar.rs b/komorebi/src/stackbar_manager/stackbar.rs index ac51e335..b07ba6a4 100644 --- a/komorebi/src/stackbar_manager/stackbar.rs +++ b/komorebi/src/stackbar_manager/stackbar.rs @@ -355,7 +355,7 @@ impl Stackbar { // tile if index != focused_window_idx && let Err(err) = - window.set_position(&focused_window_rect, false) + window.set_position(&focused_window_rect, false, false) { tracing::error!( "stackbar WM_LBUTTONDOWN repositioning error: hwnd {} ({})", diff --git a/komorebi/src/static_config.rs b/komorebi/src/static_config.rs index b268e93a..4ef57960 100644 --- a/komorebi/src/static_config.rs +++ b/komorebi/src/static_config.rs @@ -1361,8 +1361,6 @@ impl StaticConfig { workspace_matching_rules.clear(); drop(workspace_matching_rules); - let monitor_count = wm.monitors().len(); - let offset = wm.work_area_offset; for (i, monitor) in wm.monitors_mut().iter_mut().enumerate() { let preferred_config_idx = { @@ -1411,15 +1409,6 @@ impl StaticConfig { monitor.update_workspaces_globals(offset); for (j, ws) in monitor.workspaces_mut().iter_mut().enumerate() { if let Some(workspace_config) = monitor_config.workspaces.get_mut(j) { - if monitor_count > 1 - && matches!(workspace_config.layout, Some(DefaultLayout::Scrolling)) - { - tracing::warn!( - "scrolling layout is only supported for a single monitor; falling back to columns layout" - ); - workspace_config.layout = Some(DefaultLayout::Columns); - } - ws.load_static_config(workspace_config)?; } } diff --git a/komorebi/src/window.rs b/komorebi/src/window.rs index cc431e0f..b3e6b015 100644 --- a/komorebi/src/window.rs +++ b/komorebi/src/window.rs @@ -165,6 +165,7 @@ struct MovementRenderDispatcher { target_rect: Rect, top: bool, style: AnimationStyle, + end_with_hide: bool, } impl MovementRenderDispatcher { @@ -176,6 +177,7 @@ impl MovementRenderDispatcher { target_rect: Rect, top: bool, style: AnimationStyle, + end_with_hide: bool, ) -> Self { Self { hwnd, @@ -183,6 +185,7 @@ impl MovementRenderDispatcher { target_rect, top, style, + end_with_hide, } } } @@ -193,6 +196,11 @@ impl RenderDispatcher for MovementRenderDispatcher { } fn pre_render(&self) -> eyre::Result<()> { + let window = Window::from(self.hwnd); + if window.is_cloaked().unwrap_or(true) { + window.restore() + } + stackbar_manager::STACKBAR_TEMPORARILY_DISABLED.store(true, Ordering::SeqCst); stackbar_manager::send_notification(); @@ -213,7 +221,13 @@ impl RenderDispatcher for MovementRenderDispatcher { fn post_render(&self) -> eyre::Result<()> { // we don't add the async_window_pos flag here because animations // are always run on a separate thread - WindowsApi::position_window(self.hwnd, &self.target_rect, self.top, false)?; + if self.end_with_hide { + let window = Window::from(self.hwnd); + window.hide(); + } else { + WindowsApi::position_window(self.hwnd, &self.target_rect, self.top, false)?; + } + if ANIMATION_MANAGER .lock() .count_in_progress(MovementRenderDispatcher::PREFIX) @@ -383,7 +397,7 @@ impl Window { let anim_count = ANIMATION_MANAGER .lock() .count_in_progress(MovementRenderDispatcher::PREFIX); - self.set_position(&new_rect, true)?; + self.set_position(&new_rect, true, false)?; let hwnd = self.hwnd; // Wait for the animation to finish before maximizing the window again, otherwise // we would be maximizing the window on the current monitor anyway @@ -402,11 +416,11 @@ impl Window { windows_api::WindowsApi::maximize_window(hwnd); }); } else { - self.set_position(&new_rect, true)?; + self.set_position(&new_rect, true, false)?; windows_api::WindowsApi::maximize_window(self.hwnd); } } else { - self.set_position(&new_rect, true)?; + self.set_position(&new_rect, true, false)?; } Ok(()) @@ -436,10 +450,11 @@ impl Window { bottom: target_height, }, true, + false, ) } - pub fn set_position(&self, layout: &Rect, top: bool) -> eyre::Result<()> { + pub fn set_position(&self, layout: &Rect, top: bool, end_with_hide: bool) -> eyre::Result<()> { let window_rect = WindowsApi::window_rect(self.hwnd)?; if window_rect.eq(layout) { @@ -463,11 +478,24 @@ impl Window { .get(&MovementRenderDispatcher::PREFIX) .unwrap_or(&ANIMATION_STYLE_GLOBAL.lock()); - let render_dispatcher = - MovementRenderDispatcher::new(self.hwnd, window_rect, *layout, top, style); + let render_dispatcher = MovementRenderDispatcher::new( + self.hwnd, + window_rect, + *layout, + top, + style, + end_with_hide, + ); AnimationEngine::animate(render_dispatcher, duration) + } else if end_with_hide { + self.hide(); + Ok(()) } else { + if self.is_cloaked().unwrap_or(true) { + self.restore() + } + WindowsApi::position_window(self.hwnd, layout, top, true) } } diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index a9f2aeef..31348e4f 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -3088,16 +3088,8 @@ impl WindowManager { pub fn change_workspace_layout_default(&mut self, layout: DefaultLayout) -> eyre::Result<()> { tracing::info!("changing layout"); - let monitor_count = self.monitors().len(); let workspace = self.focused_workspace_mut()?; - if monitor_count > 1 && matches!(layout, DefaultLayout::Scrolling) { - tracing::warn!( - "scrolling layout is only supported for a single monitor; not changing layout" - ); - return Ok(()); - } - match &workspace.layout { Layout::Default(_) => {} Layout::Custom(layout) => { diff --git a/komorebi/src/workspace.rs b/komorebi/src/workspace.rs index fafadeb9..e92b8268 100644 --- a/komorebi/src/workspace.rs +++ b/komorebi/src/workspace.rs @@ -531,7 +531,7 @@ impl Workspace { adjusted_work_area.add_padding(container_padding); adjusted_work_area.add_padding(border_offset); adjusted_work_area.add_padding(border_width); - window.set_position(&adjusted_work_area, true)?; + window.set_position(&adjusted_work_area, true, false)?; }; } else if let Some(window) = &mut self.maximized_window { window.maximize(); @@ -553,6 +553,8 @@ impl Workspace { let no_titlebar = NO_TITLEBAR.lock().clone(); let regex_identifiers = REGEX_IDENTIFIERS.lock().clone(); + let is_scrolling = matches!(self.layout, Layout::Default(DefaultLayout::Scrolling)); + let containers = self.containers_mut(); for (i, container) in containers.iter_mut().enumerate() { @@ -597,7 +599,13 @@ impl Workspace { WindowsApi::restore_window(window.hwnd); } } - window.set_position(layout, false)?; + + window.set_position( + layout, + false, + is_scrolling + && !work_area.contains_within_horizontal_bounds(layout), + )?; } } } @@ -1581,6 +1589,14 @@ impl Workspace { tracing::info!("focusing container"); self.containers.focus(idx); + + if matches!(self.layout, Layout::Default(DefaultLayout::Scrolling)) + && let Some(container) = self.focused_container() + && let Some(window) = container.focused_window() + && window.is_cloaked().unwrap_or(true) + { + window.restore(); + } } pub fn swap_containers(&mut self, i: usize, j: usize) {