@@ -700,11 +700,22 @@ impl WindowManager { |
| 700 | 700 | |
| 701 | 701 | // Warp pointer to center of focused window (mouse follows focus) |
| 702 | 702 | if warp_pointer { |
| 703 | | - if let Err(e) = self.conn.warp_pointer_to_window(window) { |
| 704 | | - tracing::warn!("Failed to warp pointer: {}", e); |
| 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 |
| 713 | + if let Err(e) = self.conn.warp_pointer_to_window(window) { |
| 714 | + tracing::warn!("Failed to warp pointer: {}", e); |
| 715 | + } |
| 705 | 716 | } |
| 706 | | - // Record warp time to suppress EnterNotify feedback loop |
| 707 | 717 | self.last_warp = std::time::Instant::now(); |
| 718 | + self.conn.flush()?; |
| 708 | 719 | } |
| 709 | 720 | |
| 710 | 721 | Ok(()) |
@@ -981,6 +992,11 @@ impl WindowManager { |
| 981 | 992 | border_width, |
| 982 | 993 | )?; |
| 983 | 994 | } |
| 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 | + } |
| 984 | 1000 | } |
| 985 | 1001 | |
| 986 | 1002 | // 2. Configure floating windows and stack them above tiled |
@@ -988,59 +1004,65 @@ impl WindowManager { |
| 988 | 1004 | |
| 989 | 1005 | for window_id in floating_ids { |
| 990 | 1006 | // 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; |
| 993 | | - let adjusted_width = geom.width.saturating_sub(2 * border_width as u16); |
| 994 | | - let adjusted_height = geom.height.saturating_sub(2 * border_width as u16); |
| 995 | | - |
| 996 | | - let has_frame = win.frame.is_some(); |
| 997 | | - |
| 998 | | - if has_frame && titlebar_enabled { |
| 999 | | - // Configure frame for floating window |
| 1000 | | - let client_height = adjusted_height.saturating_sub(titlebar_height); |
| 1001 | | - self.frames.configure_frame( |
| 1002 | | - &self.conn.conn, |
| 1003 | | - window_id, |
| 1004 | | - geom.x, |
| 1005 | | - geom.y, |
| 1006 | | - adjusted_width.max(1), |
| 1007 | | - client_height.max(1), |
| 1008 | | - titlebar_height, |
| 1009 | | - border_width as u16, |
| 1010 | | - )?; |
| 1011 | | - |
| 1012 | | - // Raise frame to top of stack |
| 1013 | | - if let Some(frame) = self.frames.frame_for_client(window_id) { |
| 1014 | | - let aux = ConfigureWindowAux::new().stack_mode(StackMode::ABOVE); |
| 1015 | | - self.conn.conn.configure_window(frame, &aux)?; |
| 1016 | | - } |
| 1017 | | - |
| 1018 | | - tracing::debug!( |
| 1019 | | - "apply_layout: FLOATING+FRAME window={} at ({}, {}) size {}x{} (raising)", |
| 1020 | | - window_id, geom.x, geom.y, adjusted_width.max(1), adjusted_height.max(1) |
| 1021 | | - ); |
| 1022 | | - } else { |
| 1023 | | - tracing::debug!( |
| 1024 | | - "apply_layout: FLOATING window={} at ({}, {}) size {}x{} (raising)", |
| 1025 | | - window_id, geom.x, geom.y, adjusted_width.max(1), adjusted_height.max(1) |
| 1026 | | - ); |
| 1027 | | - |
| 1028 | | - // Configure geometry |
| 1029 | | - self.conn.configure_window( |
| 1030 | | - window_id, |
| 1031 | | - geom.x, |
| 1032 | | - geom.y, |
| 1033 | | - adjusted_width.max(1), |
| 1034 | | - adjusted_height.max(1), |
| 1035 | | - border_width, |
| 1036 | | - )?; |
| 1037 | | - |
| 1038 | | - // Raise to top of stack (each subsequent window goes above the previous) |
| 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 | + |
| 1015 | + let adjusted_width = geom.width.saturating_sub(2 * border_width as u16); |
| 1016 | + let adjusted_height = geom.height.saturating_sub(2 * border_width as u16); |
| 1017 | + |
| 1018 | + if has_frame && titlebar_enabled { |
| 1019 | + // Configure frame for floating window |
| 1020 | + let client_height = adjusted_height.saturating_sub(titlebar_height); |
| 1021 | + self.frames.configure_frame( |
| 1022 | + &self.conn.conn, |
| 1023 | + window_id, |
| 1024 | + geom.x, |
| 1025 | + geom.y, |
| 1026 | + adjusted_width.max(1), |
| 1027 | + client_height.max(1), |
| 1028 | + titlebar_height, |
| 1029 | + border_width as u16, |
| 1030 | + )?; |
| 1031 | + |
| 1032 | + // Raise frame to top of stack |
| 1033 | + if let Some(frame) = self.frames.frame_for_client(window_id) { |
| 1039 | 1034 | let aux = ConfigureWindowAux::new().stack_mode(StackMode::ABOVE); |
| 1040 | | - self.conn.conn.configure_window(window_id, &aux)?; |
| 1035 | + self.conn.conn.configure_window(frame, &aux)?; |
| 1041 | 1036 | } |
| 1037 | + |
| 1038 | + tracing::debug!( |
| 1039 | + "apply_layout: FLOATING+FRAME window={} at ({}, {}) size {}x{} (raising)", |
| 1040 | + window_id, geom.x, geom.y, adjusted_width.max(1), adjusted_height.max(1) |
| 1041 | + ); |
| 1042 | 1042 | } else { |
| 1043 | | - tracing::warn!("apply_layout: floating window {} not in windows map!", window_id); |
| 1043 | + tracing::debug!( |
| 1044 | + "apply_layout: FLOATING window={} at ({}, {}) size {}x{} (raising)", |
| 1045 | + window_id, geom.x, geom.y, adjusted_width.max(1), adjusted_height.max(1) |
| 1046 | + ); |
| 1047 | + |
| 1048 | + // Configure geometry |
| 1049 | + self.conn.configure_window( |
| 1050 | + window_id, |
| 1051 | + geom.x, |
| 1052 | + geom.y, |
| 1053 | + adjusted_width.max(1), |
| 1054 | + adjusted_height.max(1), |
| 1055 | + border_width, |
| 1056 | + )?; |
| 1057 | + |
| 1058 | + // Raise to top of stack (each subsequent window goes above the previous) |
| 1059 | + let aux = ConfigureWindowAux::new().stack_mode(StackMode::ABOVE); |
| 1060 | + self.conn.conn.configure_window(window_id, &aux)?; |
| 1061 | + } |
| 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)); |
| 1044 | 1066 | } |
| 1045 | 1067 | } |
| 1046 | 1068 | } |