gardesk/gar / a4f9469

Browse files

Focus history: focus last active window on close

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
a4f9469e11792bd5fdfccf593b2c8b77f4633181
Parents
46030f0
Tree
d08d114

1 changed file

StatusFile+-
M gar/src/core/mod.rs 27 7
gar/src/core/mod.rsmodified
@@ -39,6 +39,8 @@ pub struct WindowManager {
3939
     pub last_warp: std::time::Instant,
4040
     /// Frame manager for title bars
4141
     pub frames: FrameManager,
42
+    /// Focus history stack - most recently focused windows first (per workspace)
43
+    pub focus_history: Vec<XWindow>,
4244
 }
4345
 
4446
 impl WindowManager {
@@ -126,6 +128,7 @@ impl WindowManager {
126128
             i3_ipc_server,
127129
             last_warp: std::time::Instant::now(),
128130
             frames: FrameManager::new(),
131
+            focus_history: Vec::new(),
129132
         })
130133
     }
131134
 
@@ -409,10 +412,19 @@ impl WindowManager {
409412
                 self.workspaces[ws_idx].tree.remove(window);
410413
             }
411414
 
415
+            // Remove from focus history
416
+            self.focus_history.retain(|&w| w != window);
417
+
412418
             // Update focus if this was the focused window
413419
             if self.focused_window == Some(window) {
414
-                // Try to focus another window on that workspace
415
-                self.focused_window = self.workspaces[ws_idx].tree.first_window()
420
+                // Find next window from focus history that's on this workspace
421
+                let next_from_history = self.focus_history.iter()
422
+                    .find(|&&w| self.windows.get(&w).map(|win| win.workspace == ws_idx).unwrap_or(false))
423
+                    .copied();
424
+
425
+                // Fall back to first window in tree or floating list if no history
426
+                self.focused_window = next_from_history
427
+                    .or_else(|| self.workspaces[ws_idx].tree.first_window())
416428
                     .or_else(|| self.workspaces[ws_idx].floating.last().copied());
417429
                 self.workspaces[ws_idx].focused = self.focused_window;
418430
             }
@@ -466,10 +478,16 @@ impl WindowManager {
466478
     }
467479
 
468480
     /// Set focus to a window.
469
-    pub fn set_focus(&mut self, window: XWindow) -> Result<()> {
481
+    /// If `warp_pointer` is true, the mouse pointer will be moved to the window center.
482
+    /// Use true for keyboard navigation, false for mouse-initiated focus changes.
483
+    pub fn set_focus(&mut self, window: XWindow, warp_pointer: bool) -> Result<()> {
470484
         self.focused_window = Some(window);
471485
         self.current_workspace_mut().focused = Some(window);
472486
 
487
+        // Update focus history - move window to front
488
+        self.focus_history.retain(|&w| w != window);
489
+        self.focus_history.insert(0, window);
490
+
473491
         // Clear urgency when window receives focus
474492
         if let Some(win) = self.windows.get_mut(&window) {
475493
             if win.urgent {
@@ -483,11 +501,13 @@ impl WindowManager {
483501
         self.update_borders()?;
484502
 
485503
         // Warp pointer to center of focused window (mouse follows focus)
504
+        if warp_pointer {
486505
             if let Err(e) = self.conn.warp_pointer_to_window(window) {
487506
                 tracing::warn!("Failed to warp pointer: {}", e);
488507
             }
489508
             // Record warp time to suppress EnterNotify feedback loop
490509
             self.last_warp = std::time::Instant::now();
510
+        }
491511
 
492512
         Ok(())
493513
     }