gardesk/gar / 255874d

Browse files

fix: use stored geometry for pointer warp to avoid X11 race

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
255874d55cba4400e14c12c8c4a51aa7890ac50b
Parents
46d12e5
Tree
c23a6e5

5 changed files

StatusFile+-
M Cargo.lock 2 2
M gar/src/core/mod.rs 75 53
M gar/src/core/window.rs 3 0
M gar/src/x11/connection.rs 5 0
M gar/src/x11/events.rs 2 0
Cargo.lockmodified
@@ -202,7 +202,7 @@ checksum = "f449e6c6c08c865631d4890cfacf252b3d396c9bcc83adb6623cdb02a8336c41"
202202
 
203203
 [[package]]
204204
 name = "gar"
205
-version = "0.2.0"
205
+version = "0.3.0"
206206
 dependencies = [
207207
  "dirs",
208208
  "libc",
@@ -217,7 +217,7 @@ dependencies = [
217217
 
218218
 [[package]]
219219
 name = "garctl"
220
-version = "0.2.0"
220
+version = "0.3.0"
221221
 dependencies = [
222222
  "clap",
223223
  "serde",
gar/src/core/mod.rsmodified
@@ -700,11 +700,22 @@ impl WindowManager {
700700
 
701701
         // Warp pointer to center of focused window (mouse follows focus)
702702
         if warp_pointer {
703
+            // Use stored geometry instead of querying X11 (avoids race with ConfigureWindow)
704
+            if let Some(win) = self.windows.get(&window) {
705
+                let g = &win.current_geometry;
706
+                let center_x = g.x + (g.width as i16 / 2);
707
+                let center_y = g.y + (g.height as i16 / 2);
708
+                if let Err(e) = self.conn.warp_pointer(center_x, center_y) {
709
+                    tracing::warn!("Failed to warp pointer: {}", e);
710
+                }
711
+            } else {
712
+                // Fallback to querying X11 if window not in our map
703713
                 if let Err(e) = self.conn.warp_pointer_to_window(window) {
704714
                     tracing::warn!("Failed to warp pointer: {}", e);
705715
                 }
706
-            // Record warp time to suppress EnterNotify feedback loop
716
+            }
707717
             self.last_warp = std::time::Instant::now();
718
+            self.conn.flush()?;
708719
         }
709720
 
710721
         Ok(())
@@ -981,6 +992,11 @@ impl WindowManager {
981992
                         border_width,
982993
                     )?;
983994
                 }
995
+
996
+                // Store the actual geometry for pointer warping
997
+                if let Some(win) = self.windows.get_mut(window) {
998
+                    win.current_geometry = Rect::new(gapped_x, gapped_y, final_width.max(1), final_height.max(1));
999
+                }
9841000
             }
9851001
 
9861002
             // 2. Configure floating windows and stack them above tiled
@@ -988,13 +1004,17 @@ impl WindowManager {
9881004
 
9891005
             for window_id in floating_ids {
9901006
                 // Get the window's floating geometry from our state
991
-                if let Some(win) = self.windows.get(&window_id) {
992
-                    let geom = win.floating_geometry;
1007
+                let (geom, has_frame) = match self.windows.get(&window_id) {
1008
+                    Some(win) => (win.floating_geometry, win.frame.is_some()),
1009
+                    None => {
1010
+                        tracing::warn!("apply_layout: floating window {} not in windows map!", window_id);
1011
+                        continue;
1012
+                    }
1013
+                };
1014
+
9931015
                 let adjusted_width = geom.width.saturating_sub(2 * border_width as u16);
9941016
                 let adjusted_height = geom.height.saturating_sub(2 * border_width as u16);
9951017
 
996
-                    let has_frame = win.frame.is_some();
997
-
9981018
                 if has_frame && titlebar_enabled {
9991019
                     // Configure frame for floating window
10001020
                     let client_height = adjusted_height.saturating_sub(titlebar_height);
@@ -1039,8 +1059,10 @@ impl WindowManager {
10391059
                     let aux = ConfigureWindowAux::new().stack_mode(StackMode::ABOVE);
10401060
                     self.conn.conn.configure_window(window_id, &aux)?;
10411061
                 }
1042
-                } else {
1043
-                    tracing::warn!("apply_layout: floating window {} not in windows map!", window_id);
1062
+
1063
+                // Store the actual geometry for pointer warping
1064
+                if let Some(win) = self.windows.get_mut(&window_id) {
1065
+                    win.current_geometry = Rect::new(geom.x, geom.y, adjusted_width.max(1), adjusted_height.max(1));
10441066
                 }
10451067
             }
10461068
         }
gar/src/core/window.rsmodified
@@ -7,6 +7,8 @@ pub struct Window {
77
     pub id: XWindow,
88
     /// Geometry for floating mode (position and size when floating)
99
     pub floating_geometry: Rect,
10
+    /// Current actual geometry (updated by apply_layout, used for pointer warping)
11
+    pub current_geometry: Rect,
1012
     pub mapped: bool,
1113
     pub focused: bool,
1214
     pub floating: bool,
@@ -30,6 +32,7 @@ impl Window {
3032
         Self {
3133
             id,
3234
             floating_geometry: Rect::new(0, 0, 640, 480),
35
+            current_geometry: Rect::new(0, 0, 640, 480),
3336
             mapped: false,
3437
             focused: false,
3538
             floating: false,
gar/src/x11/connection.rsmodified
@@ -516,6 +516,11 @@ impl Connection {
516516
         let center_x = (geom.width / 2) as i16;
517517
         let center_y = (geom.height / 2) as i16;
518518
 
519
+        tracing::debug!(
520
+            "Warping pointer to window {}: geom={}x{}+{}+{}, center=({},{})",
521
+            window, geom.width, geom.height, geom.x, geom.y, center_x, center_y
522
+        );
523
+
519524
         self.conn.warp_pointer(
520525
             x11rb::NONE,  // src_window (none = don't check source)
521526
             window,       // dst_window
gar/src/x11/events.rsmodified
@@ -571,6 +571,8 @@ impl WindowManager {
571571
 
572572
         // Apply layout to all windows
573573
         self.apply_layout()?;
574
+        // Flush to ensure ConfigureWindow requests are processed before we query geometry
575
+        self.conn.flush()?;
574576
 
575577
         // Focus the new window if on a visible workspace
576578
         if target_visible {