windows: Fix scrolling bug (#12431)

张小白 created

Closes #12369 



https://github.com/zed-industries/zed/assets/14981363/14df820e-9be3-4b89-882b-a083ea42d59e



Release Notes:

- N/A

Change summary

crates/gpui/src/platform/windows/events.rs | 94 ++++++++++++++++-------
crates/gpui/src/platform/windows/window.rs |  3 
2 files changed, 68 insertions(+), 29 deletions(-)

Detailed changes

crates/gpui/src/platform/windows/events.rs 🔗

@@ -62,14 +62,16 @@ pub(crate) fn handle_msg(
         WM_NCMBUTTONUP => {
             handle_nc_mouse_up_msg(handle, MouseButton::Middle, wparam, lparam, state_ptr)
         }
-        WM_LBUTTONDOWN => handle_mouse_down_msg(MouseButton::Left, lparam, state_ptr),
-        WM_RBUTTONDOWN => handle_mouse_down_msg(MouseButton::Right, lparam, state_ptr),
-        WM_MBUTTONDOWN => handle_mouse_down_msg(MouseButton::Middle, lparam, state_ptr),
-        WM_XBUTTONDOWN => handle_xbutton_msg(wparam, lparam, handle_mouse_down_msg, state_ptr),
-        WM_LBUTTONUP => handle_mouse_up_msg(MouseButton::Left, lparam, state_ptr),
-        WM_RBUTTONUP => handle_mouse_up_msg(MouseButton::Right, lparam, state_ptr),
-        WM_MBUTTONUP => handle_mouse_up_msg(MouseButton::Middle, lparam, state_ptr),
-        WM_XBUTTONUP => handle_xbutton_msg(wparam, lparam, handle_mouse_up_msg, state_ptr),
+        WM_LBUTTONDOWN => handle_mouse_down_msg(handle, MouseButton::Left, lparam, state_ptr),
+        WM_RBUTTONDOWN => handle_mouse_down_msg(handle, MouseButton::Right, lparam, state_ptr),
+        WM_MBUTTONDOWN => handle_mouse_down_msg(handle, MouseButton::Middle, lparam, state_ptr),
+        WM_XBUTTONDOWN => {
+            handle_xbutton_msg(handle, wparam, lparam, handle_mouse_down_msg, state_ptr)
+        }
+        WM_LBUTTONUP => handle_mouse_up_msg(handle, MouseButton::Left, lparam, state_ptr),
+        WM_RBUTTONUP => handle_mouse_up_msg(handle, MouseButton::Right, lparam, state_ptr),
+        WM_MBUTTONUP => handle_mouse_up_msg(handle, MouseButton::Middle, lparam, state_ptr),
+        WM_XBUTTONUP => handle_xbutton_msg(handle, wparam, lparam, handle_mouse_up_msg, state_ptr),
         WM_MOUSEWHEEL => handle_mouse_wheel_msg(handle, wparam, lparam, state_ptr),
         WM_MOUSEHWHEEL => handle_mouse_horizontal_wheel_msg(handle, wparam, lparam, state_ptr),
         WM_SYSKEYDOWN => handle_syskeydown_msg(wparam, lparam, state_ptr),
@@ -409,10 +411,12 @@ fn handle_char_msg(
 }
 
 fn handle_mouse_down_msg(
+    handle: HWND,
     button: MouseButton,
     lparam: LPARAM,
     state_ptr: Rc<WindowsWindowStatePtr>,
 ) -> Option<isize> {
+    unsafe { SetCapture(handle) };
     let mut lock = state_ptr.state.borrow_mut();
     if let Some(mut callback) = lock.callbacks.input.take() {
         let x = lparam.signed_loword() as f32;
@@ -443,10 +447,12 @@ fn handle_mouse_down_msg(
 }
 
 fn handle_mouse_up_msg(
+    _handle: HWND,
     button: MouseButton,
     lparam: LPARAM,
     state_ptr: Rc<WindowsWindowStatePtr>,
 ) -> Option<isize> {
+    unsafe { ReleaseCapture().log_err() };
     let mut lock = state_ptr.state.borrow_mut();
     if let Some(mut callback) = lock.callbacks.input.take() {
         let x = lparam.signed_loword() as f32;
@@ -475,9 +481,10 @@ fn handle_mouse_up_msg(
 }
 
 fn handle_xbutton_msg(
+    handle: HWND,
     wparam: WPARAM,
     lparam: LPARAM,
-    handler: impl Fn(MouseButton, LPARAM, Rc<WindowsWindowStatePtr>) -> Option<isize>,
+    handler: impl Fn(HWND, MouseButton, LPARAM, Rc<WindowsWindowStatePtr>) -> Option<isize>,
     state_ptr: Rc<WindowsWindowStatePtr>,
 ) -> Option<isize> {
     let nav_dir = match wparam.hiword() {
@@ -485,7 +492,7 @@ fn handle_xbutton_msg(
         XBUTTON2 => NavigationDirection::Forward,
         _ => return Some(1),
     };
-    handler(MouseButton::Navigate(nav_dir), lparam, state_ptr)
+    handler(handle, MouseButton::Navigate(nav_dir), lparam, state_ptr)
 }
 
 fn handle_mouse_wheel_msg(
@@ -919,7 +926,7 @@ fn handle_nc_mouse_down_msg(
     }
 
     let mut lock = state_ptr.state.borrow_mut();
-    let result = if let Some(mut callback) = lock.callbacks.input.take() {
+    if let Some(mut callback) = lock.callbacks.input.take() {
         let scale_factor = lock.scale_factor;
         let mut cursor_point = POINT {
             x: lparam.signed_loword().into(),
@@ -943,13 +950,25 @@ fn handle_nc_mouse_down_msg(
         };
         state_ptr.state.borrow_mut().callbacks.input = Some(callback);
 
-        result
+        if result.is_some() {
+            return result;
+        }
     } else {
-        None
+        drop(lock);
     };
 
     // Since these are handled in handle_nc_mouse_up_msg we must prevent the default window proc
-    result.or_else(|| matches!(wparam.0 as u32, HTMINBUTTON | HTMAXBUTTON | HTCLOSE).then_some(0))
+    if button == MouseButton::Left {
+        match wparam.0 as u32 {
+            HTMINBUTTON => state_ptr.state.borrow_mut().nc_button_pressed = Some(HTMINBUTTON),
+            HTMAXBUTTON => state_ptr.state.borrow_mut().nc_button_pressed = Some(HTMAXBUTTON),
+            HTCLOSE => state_ptr.state.borrow_mut().nc_button_pressed = Some(HTCLOSE),
+            _ => return None,
+        };
+        Some(0)
+    } else {
+        None
+    }
 }
 
 fn handle_nc_mouse_up_msg(
@@ -991,24 +1010,41 @@ fn handle_nc_mouse_up_msg(
         drop(lock);
     }
 
-    if button == MouseButton::Left {
+    let last_pressed = state_ptr.state.borrow_mut().nc_button_pressed.take();
+    if button == MouseButton::Left && last_pressed.is_some() {
+        let last_button = last_pressed.unwrap();
+        let mut handled = false;
         match wparam.0 as u32 {
-            HTMINBUTTON => unsafe {
-                ShowWindowAsync(handle, SW_MINIMIZE).ok().log_err();
-            },
-            HTMAXBUTTON => unsafe {
-                if state_ptr.state.borrow().is_maximized() {
-                    ShowWindowAsync(handle, SW_NORMAL).ok().log_err();
-                } else {
-                    ShowWindowAsync(handle, SW_MAXIMIZE).ok().log_err();
+            HTMINBUTTON => {
+                if last_button == HTMINBUTTON {
+                    unsafe { ShowWindowAsync(handle, SW_MINIMIZE).ok().log_err() };
+                    handled = true;
                 }
-            },
-            HTCLOSE => unsafe {
-                PostMessageW(handle, WM_CLOSE, WPARAM::default(), LPARAM::default()).log_err();
-            },
-            _ => return None,
+            }
+            HTMAXBUTTON => {
+                if last_button == HTMAXBUTTON {
+                    if state_ptr.state.borrow().is_maximized() {
+                        unsafe { ShowWindowAsync(handle, SW_NORMAL).ok().log_err() };
+                    } else {
+                        unsafe { ShowWindowAsync(handle, SW_MAXIMIZE).ok().log_err() };
+                    }
+                    handled = true;
+                }
+            }
+            HTCLOSE => {
+                if last_button == HTCLOSE {
+                    unsafe {
+                        PostMessageW(handle, WM_CLOSE, WPARAM::default(), LPARAM::default())
+                            .log_err()
+                    };
+                    handled = true;
+                }
+            }
+            _ => {}
         };
-        return Some(0);
+        if handled {
+            return Some(0);
+        }
     }
 
     None

crates/gpui/src/platform/windows/window.rs 🔗

@@ -45,6 +45,7 @@ pub struct WindowsWindowState {
     pub click_state: ClickState,
     pub system_settings: WindowsSystemSettings,
     pub current_cursor: HCURSOR,
+    pub nc_button_pressed: Option<u32>,
 
     pub display: WindowsDisplay,
     fullscreen: Option<StyleAndBounds>,
@@ -82,6 +83,7 @@ impl WindowsWindowState {
         let input_handler = None;
         let click_state = ClickState::new();
         let system_settings = WindowsSystemSettings::new();
+        let nc_button_pressed = None;
         let fullscreen = None;
 
         Self {
@@ -95,6 +97,7 @@ impl WindowsWindowState {
             click_state,
             system_settings,
             current_cursor,
+            nc_button_pressed,
             display,
             fullscreen,
             hwnd,