gardesk/gar / c7ea6ce

Browse files

multimonitor: fix focus tracking and spawn on mouse position

Authored by espadonne
SHA
c7ea6ce4dc83b60001cb128e07a2d45dfeb26e83
Parents
066e8f2
Tree
5b6b8a0

3 changed files

StatusFile+-
M gar/src/core/mod.rs 34 0
M gar/src/x11/connection.rs 6 0
M gar/src/x11/events.rs 9 3
gar/src/core/mod.rsmodified
@@ -207,6 +207,29 @@ impl WindowManager {
207207
         self.monitors.iter().position(|m| m.active_workspace == workspace_idx)
208208
     }
209209
 
210
+    /// Find the monitor index containing a point (x, y in root window coordinates).
211
+    pub fn monitor_idx_at_point(&self, x: i16, y: i16) -> usize {
212
+        self.monitors
213
+            .iter()
214
+            .position(|m| {
215
+                let g = &m.geometry;
216
+                x >= g.x && x < g.x + g.width as i16 &&
217
+                y >= g.y && y < g.y + g.height as i16
218
+            })
219
+            .unwrap_or(self.focused_monitor) // Fallback to focused monitor
220
+    }
221
+
222
+    /// Get the workspace that should receive new windows (based on mouse position).
223
+    /// This supports spawning windows on the monitor where the mouse is.
224
+    pub fn workspace_for_new_window(&self) -> usize {
225
+        if let Ok((x, y)) = self.conn.get_pointer_position() {
226
+            let monitor_idx = self.monitor_idx_at_point(x, y);
227
+            self.monitors[monitor_idx].active_workspace
228
+        } else {
229
+            self.focused_workspace
230
+        }
231
+    }
232
+
210233
     /// Calculate struts (reserved space for panels/docks) for a monitor.
211234
     fn calculate_struts(&self, _monitor_idx: usize) -> (u32, u32, u32, u32) {
212235
         if self.config.bar_height > 0 {
@@ -602,6 +625,17 @@ impl WindowManager {
602625
             }
603626
         }
604627
 
628
+        // Update focused workspace and monitor based on the window's workspace
629
+        // This is critical for focus-follows-mouse to work correctly with multimonitor
630
+        if let Some(win) = self.windows.get(&window) {
631
+            let ws_idx = win.workspace;
632
+            self.focused_workspace = ws_idx;
633
+            // Update focused_monitor to the monitor displaying this workspace (if visible)
634
+            if let Some(monitor_idx) = self.monitor_idx_for_workspace(ws_idx) {
635
+                self.focused_monitor = monitor_idx;
636
+            }
637
+        }
638
+
605639
         self.focused_window = Some(window);
606640
         self.current_workspace_mut().focused = Some(window);
607641
 
gar/src/x11/connection.rsmodified
@@ -504,6 +504,12 @@ impl Connection {
504504
         Ok(())
505505
     }
506506
 
507
+    /// Get the current mouse pointer position (root window coordinates).
508
+    pub fn get_pointer_position(&self) -> Result<(i16, i16), Error> {
509
+        let reply = self.conn.query_pointer(self.root)?.reply()?;
510
+        Ok((reply.root_x, reply.root_y))
511
+    }
512
+
507513
     /// Set window border width and color.
508514
     pub fn set_border(&self, window: Window, width: u32, color: u32) -> Result<(), Error> {
509515
         let aux = ChangeWindowAttributesAux::new().border_pixel(color);
gar/src/x11/events.rsmodified
@@ -493,9 +493,15 @@ impl WindowManager {
493493
         // Check window rules first
494494
         let rule_actions = self.check_rules(window);
495495
 
496
-        // Determine target workspace (rule or current)
497
-        let target_workspace = rule_actions.workspace.unwrap_or(self.focused_workspace + 1);
498
-        let target_idx = target_workspace.saturating_sub(1).min(self.workspaces.len() - 1);
496
+        // Determine target workspace: rule > mouse position > focused
497
+        // This makes windows spawn on the monitor where the mouse is
498
+        let target_idx = if let Some(ws) = rule_actions.workspace {
499
+            // Rule specifies workspace (1-indexed)
500
+            ws.saturating_sub(1).min(self.workspaces.len() - 1)
501
+        } else {
502
+            // Use workspace of monitor under mouse pointer
503
+            self.workspace_for_new_window()
504
+        };
499505
 
500506
         // Determine if window should float (rule > ICCCM/EWMH hints)
501507
         let should_float = rule_actions.floating.unwrap_or_else(|| self.conn.should_float(window));