From e7d5c4c94a2152b87b0107b84f2ff445d0a346c1 Mon Sep 17 00:00:00 2001 From: Lars Berger Date: Sat, 3 Aug 2024 21:47:07 +0800 Subject: [PATCH] fix: floating windows being snapped to tiling without dragging --- .../events/handle_window_location_changed.rs | 135 ++++++++---------- .../handle_window_moved_or_resized_end.rs | 65 ++++----- .../handle_window_moved_or_resized_start.rs | 8 +- 3 files changed, 87 insertions(+), 121 deletions(-) diff --git a/packages/wm/src/common/events/handle_window_location_changed.rs b/packages/wm/src/common/events/handle_window_location_changed.rs index b7e0f30a5..7e380fe1c 100644 --- a/packages/wm/src/common/events/handle_window_location_changed.rs +++ b/packages/wm/src/common/events/handle_window_location_changed.rs @@ -4,15 +4,13 @@ use tracing::info; use crate::{ common::{platform::NativeWindow, Rect}, containers::{ - commands::{ - attach_container, detach_container, move_container_within_tree, - }, + commands::{flatten_split_container, move_container_within_tree}, traits::{CommonGetters, PositionGetters}, - Container, WindowContainer, + WindowContainer, }, user_config::{FloatingStateConfig, FullscreenStateConfig, UserConfig}, windows::{ - commands::update_window_state, traits::WindowGetters, + commands::update_window_state, traits::WindowGetters, ActiveDrag, ActiveDragOperation, TilingWindow, WindowState, }, wm_state::WmState, @@ -30,14 +28,6 @@ pub fn handle_window_location_changed( let frame_position: Rect = window.native().refresh_frame_position()?; let old_frame_position: Rect = window.to_rect()?; - update_window_operation( - state, - config, - &window, - &frame_position, - &old_frame_position, - )?; - let is_minimized = window.native().refresh_is_minimized()?; let old_is_maximized = window.native().is_maximized()?; @@ -47,6 +37,17 @@ pub fn handle_window_location_changed( .nearest_monitor(&window.native()) .context("Failed to get workspace of nearest monitor.")?; + // TODO: Include this as part of the `match` statement below. + if let Some(tiling_window) = window.as_tiling_window() { + update_drag_state( + tiling_window.clone(), + &frame_position, + &old_frame_position, + state, + config, + )?; + } + match window.state() { WindowState::Fullscreen(fullscreen_state) => { let monitor_rect = if config.has_outer_gaps() { @@ -156,80 +157,56 @@ pub fn handle_window_location_changed( /// This function determines whether a window is being moved or resized and /// updates its operation state accordingly. If the window is being moved, /// it's set to floating mode. -fn update_window_operation( - state: &mut WmState, - config: &UserConfig, - window: &WindowContainer, +fn update_drag_state( + window: TilingWindow, frame_position: &Rect, old_frame_position: &Rect, -) -> anyhow::Result<()> { - if let Some(tiling_window) = window.as_tiling_window() { - if let Some(mut active_drag) = tiling_window.active_drag() { - if active_drag.operation.is_none() - && frame_position != old_frame_position - { - if frame_position.height() == old_frame_position.height() - && frame_position.width() == old_frame_position.width() - { - active_drag.operation = Some(ActiveDragOperation::Moving); - tiling_window.set_active_drag(Some(active_drag)); - set_into_floating(tiling_window.clone(), state, config)?; - } else { - active_drag.operation = Some(ActiveDragOperation::Resizing); - tiling_window.set_active_drag(Some(active_drag)); - } - } - } - } - Ok(()) -} - -/// Converts a tiling window to a floating window and updates the window -/// hierarchy. -/// -/// This function handles the process of transitioning a tiling window to a -/// floating state, including necessary adjustments to the window hierarchy -/// and updating the window's state. -fn set_into_floating( - moved_window: TilingWindow, state: &mut WmState, config: &UserConfig, ) -> anyhow::Result<()> { - let moved_window_parent = moved_window - .parent() - .context("Tiling window has no parent")?; - - if let Some(Container::Split(split)) = moved_window.parent() { - if split.child_count() == 2 { - let split_parent = split.parent().unwrap(); - let split_index = split.index(); - let children = split.children(); - - // Looping in reversed order to reattach them in the right order - for child in children.into_iter().rev() { - detach_container(child.clone())?; - attach_container(&child, &split_parent, Some(split_index))?; - } + if let Some(active_drag) = window.active_drag() { + let should_ignore = active_drag.operation.is_some() + || frame_position == old_frame_position; + + if should_ignore { + return Ok(()); } - } - if let Some(mut active_drag) = moved_window.active_drag() { - active_drag.is_from_tiling = true; - moved_window.set_active_drag(Some(active_drag)); + let is_move = frame_position.height() == old_frame_position.height() + && frame_position.width() == old_frame_position.width(); + + let operation = match is_move { + true => ActiveDragOperation::Moving, + false => ActiveDragOperation::Resizing, + }; + + window.set_active_drag(Some(ActiveDrag { + operation: Some(operation), + ..active_drag + })); + + // Transition window to be floating while it's being dragged. + if is_move { + let parent = window.parent().context("No parent")?; + + update_window_state( + window.into(), + WindowState::Floating(FloatingStateConfig { + centered: false, + shown_on_top: true, + }), + state, + config, + )?; + + // Flatten the parent split container if it only contains the window. + if let Some(split_parent) = parent.as_split() { + if split_parent.child_count() == 1 { + flatten_split_container(split_parent.clone())?; + } + } + } } - update_window_state( - moved_window.as_window_container().unwrap(), - WindowState::Floating(FloatingStateConfig { - centered: true, - shown_on_top: true, - }), - state, - config, - )?; - state - .pending_sync - .containers_to_redraw - .push(moved_window_parent); Ok(()) } diff --git a/packages/wm/src/common/events/handle_window_moved_or_resized_end.rs b/packages/wm/src/common/events/handle_window_moved_or_resized_end.rs index 345bf6c7b..09098c014 100644 --- a/packages/wm/src/common/events/handle_window_moved_or_resized_end.rs +++ b/packages/wm/src/common/events/handle_window_moved_or_resized_end.rs @@ -53,57 +53,43 @@ pub fn handle_window_moved_or_resized_end( let width_delta = new_rect.width() - old_rect.width(); let height_delta = new_rect.height() - old_rect.height(); - if let WindowContainer::NonTilingWindow(window) = window { - let has_window_moved = matches!((width_delta, height_delta), (0, 0)); - - if has_window_moved { - window_moved_end(window, state, config)?; + match &window { + WindowContainer::NonTilingWindow(window) => { + if let Some(active_drag) = window.active_drag() { + if active_drag.is_from_tiling + && active_drag.operation == Some(ActiveDragOperation::Moving) + { + // We continue only if it's a temporary floating window and if + // the window got moved and not resized. + window_moved_end(window.clone(), state, config)?; + } + } + } + WindowContainer::TilingWindow(window) => { + info!("Tiling window resized"); + + resize_window( + window.clone().into(), + Some(LengthValue::from_px(width_delta)), + Some(LengthValue::from_px(height_delta)), + state, + )?; } - } else if let WindowContainer::TilingWindow(window) = window { - window_resized_end(window, state, width_delta, height_delta)?; } + + window.set_active_drag(None); } Ok(()) } -/// Handles window resize events -fn window_resized_end( - window: TilingWindow, - state: &mut WmState, - width_delta: i32, - height_delta: i32, -) -> anyhow::Result<()> { - info!("Tiling window resized"); - resize_window( - window.clone().into(), - Some(LengthValue::from_px(width_delta)), - Some(LengthValue::from_px(height_delta)), - state, - ) -} - /// Handles window move events fn window_moved_end( moved_window: NonTilingWindow, state: &mut WmState, config: &UserConfig, ) -> anyhow::Result<()> { - // We continue only if it's a temporary Floating window and if the window - // got moved and not resized - if let Some(active_drag) = moved_window.active_drag() { - if active_drag.is_from_tiling == false - || !matches!( - active_drag.operation, - Some(ActiveDragOperation::Moving) - ) - { - moved_window.set_active_drag(None); - return Ok(()); - } - } - info!("Tiling window drag end event"); - + info!("Tiling window drag end event."); let mouse_position = Platform::mouse_position()?; let window_under_cursor = match get_tiling_window_at_mouse_pos( @@ -150,7 +136,6 @@ fn window_moved_end( tiling_direction, new_window_position, )?; - moved_window.set_active_drag(None); state.pending_sync.containers_to_redraw.push( window_under_cursor @@ -197,12 +182,14 @@ fn on_no_target_window( state, )?; } + update_window_state( moved_window.as_window_container().unwrap(), WindowState::Tiling, state, config, )?; + return Ok(()); } diff --git a/packages/wm/src/common/events/handle_window_moved_or_resized_start.rs b/packages/wm/src/common/events/handle_window_moved_or_resized_start.rs index b8a25ee87..07ae6ccf8 100644 --- a/packages/wm/src/common/events/handle_window_moved_or_resized_start.rs +++ b/packages/wm/src/common/events/handle_window_moved_or_resized_start.rs @@ -1,6 +1,5 @@ use crate::{ common::platform::NativeWindow, - containers::WindowContainer, windows::{traits::WindowGetters, ActiveDrag}, wm_state::WmState, }; @@ -13,8 +12,11 @@ pub fn handle_window_moved_or_resized_start( ) -> anyhow::Result<()> { let found_window = state.window_from_native(&native_window); - if let Some(WindowContainer::TilingWindow(moved_window)) = found_window { - moved_window.set_active_drag(Some(ActiveDrag::default())); + if let Some(found_window) = found_window { + found_window.set_active_drag(Some(ActiveDrag { + operation: None, + is_from_tiling: found_window.is_tiling_window(), + })); } Ok(())