gardesk/tarmac / ee6e68b

Browse files

detect monitor edge before BSP adjacency for cross-monitor nav

both focus_direction and swap_direction now check if the focused
window's edge touches the monitor boundary before consulting
find_adjacent. prevents the BSP spiral from trapping navigation
at the edge — if a window is flush with the right edge of the
monitor, pressing right crosses to the next monitor instead of
spiraling deeper into the BSP tree.
Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
ee6e68bce1dfee77d562d0f542c7a7d49cd4edf8
Parents
23927cb
Tree
c9cd343

1 changed file

StatusFile+-
M tarmac/src/core/state.rs 65 19
tarmac/src/core/state.rsmodified
@@ -705,21 +705,43 @@ impl WmState {
705
             let geoms =
705
             let geoms =
706
                 ws.tree
706
                 ws.tree
707
                     .calculate_geometries_with_gaps(sr, self.gap_inner, self.gap_outer, true);
707
                     .calculate_geometries_with_gaps(sr, self.gap_inner, self.gap_outer, true);
708
-            if let Some(target) = Node::find_adjacent(&geoms, from, direction) {
708
+
709
-                self.focus_window(target);
709
+            // Check if focused window is at the monitor edge in the requested
710
-                if self.mouse_follows_focus
710
+            // direction. If so, cross monitors instead of spiraling into the BSP tree.
711
-                    && let Some((_, rect)) = geoms.iter().find(|(id, _)| *id == target)
711
+            let at_edge = if let Some((_, rect)) = geoms.iter().find(|(w, _)| *w == from) {
712
-                {
712
+                let tolerance = self.gap_outer + 2.0;
713
-                    warp_mouse_to_center(rect);
713
+                match direction {
714
-                    self.ffm_cooldown_until =
714
+                    Direction::Right => {
715
-                        Some(std::time::Instant::now() + std::time::Duration::from_millis(200));
715
+                        (rect.x + rect.width) >= (sr.x + sr.width - tolerance)
716
-                    self.ffm_last_window = Some(target);
716
+                    }
717
+                    Direction::Left => rect.x <= (sr.x + tolerance),
718
+                    Direction::Down => {
719
+                        (rect.y + rect.height) >= (sr.y + sr.height - tolerance)
720
+                    }
721
+                    Direction::Up => rect.y <= (sr.y + tolerance),
722
+                }
723
+            } else {
724
+                false
725
+            };
726
+
727
+            if !at_edge {
728
+                if let Some(target) = Node::find_adjacent(&geoms, from, direction) {
729
+                    self.focus_window(target);
730
+                    if self.mouse_follows_focus
731
+                        && let Some((_, rect)) = geoms.iter().find(|(id, _)| *id == target)
732
+                    {
733
+                        warp_mouse_to_center(rect);
734
+                        self.ffm_cooldown_until = Some(
735
+                            std::time::Instant::now() + std::time::Duration::from_millis(200),
736
+                        );
737
+                        self.ffm_last_window = Some(target);
738
+                    }
739
+                    return;
717
                 }
740
                 }
718
-                return;
719
             }
741
             }
720
         }
742
         }
721
 
743
 
722
-        // No adjacent window (or empty workspace) — try crossing monitors
744
+        // At monitor edge or no adjacent window — try crossing monitors
723
         if self.monitors.len() <= 1 {
745
         if self.monitors.len() <= 1 {
724
             return;
746
             return;
725
         }
747
         }
@@ -779,17 +801,41 @@ impl WmState {
779
             None => return,
801
             None => return,
780
         };
802
         };
781
         let sr = self.focused_rect();
803
         let sr = self.focused_rect();
782
-        let geoms = ws.tree.calculate_geometries(sr);
804
+        let geoms = ws.tree.calculate_geometries_with_gaps(
783
-        if let Some(target) = Node::find_adjacent(&geoms, focused, direction) {
805
+            sr,
784
-            tracing::debug!(focused, target, ?direction, "swap_direction");
806
+            self.gap_inner,
785
-            if self.active_workspace_mut().tree.swap(focused, target) {
807
+            self.gap_outer,
786
-                self.apply_layout();
808
+            true,
787
-                self.fix_oversized_windows();
809
+        );
810
+
811
+        // Check if the focused window touches the monitor edge in the
812
+        // requested direction. If so, skip intra-workspace swap and move
813
+        // to the adjacent monitor. This prevents the BSP spiral from
814
+        // trapping windows at the edge.
815
+        let at_edge = if let Some((_, rect)) = geoms.iter().find(|(w, _)| *w == focused) {
816
+            let tolerance = self.gap_outer + 2.0;
817
+            match direction {
818
+                Direction::Right => (rect.x + rect.width) >= (sr.x + sr.width - tolerance),
819
+                Direction::Left => rect.x <= (sr.x + tolerance),
820
+                Direction::Down => (rect.y + rect.height) >= (sr.y + sr.height - tolerance),
821
+                Direction::Up => rect.y <= (sr.y + tolerance),
822
+            }
823
+        } else {
824
+            false
825
+        };
826
+
827
+        if !at_edge {
828
+            if let Some(target) = Node::find_adjacent(&geoms, focused, direction) {
829
+                tracing::debug!(focused, target, ?direction, "swap_direction");
830
+                if self.active_workspace_mut().tree.swap(focused, target) {
831
+                    self.apply_layout();
832
+                    self.fix_oversized_windows();
833
+                }
834
+                return;
788
             }
835
             }
789
-            return;
790
         }
836
         }
791
 
837
 
792
-        // No adjacent window — move window to adjacent monitor
838
+        // At monitor edge or no adjacent window — move to adjacent monitor
793
         if self.monitors.len() <= 1 {
839
         if self.monitors.len() <= 1 {
794
             return;
840
             return;
795
         }
841
         }