Add logging when WM_CAPTURECHANGED is dropped
WM_CAPTURECHANGED now logs when the message is dropped because of reentrancy. Make sure not to call ReleaseCapture while a mutable reference exists to the window state.
@@ -273,18 +273,9 @@ impl WndState {
self.captured_mouse_buttons |= 1 << (button as u32);
}
- fn exit_mouse_capture(&mut self, button: MouseButton) {
+ fn exit_mouse_capture(&mut self, button: MouseButton) -> bool {
self.captured_mouse_buttons &= !(1 << (button as u32));
- if self.captured_mouse_buttons == 0 {
- unsafe {
- if ReleaseCapture() == FALSE {
- warn!(
- "failed to release mouse capture: {}",
- Error::Hr(HRESULT_FROM_WIN32(GetLastError()))
- );
- }
- }
- }
+ self.captured_mouse_buttons == 0
}
}
@@ -626,6 +617,7 @@ impl WndProc for MyWndProc {
WM_LBUTTONDBLCLK | WM_LBUTTONDOWN | WM_LBUTTONUP | WM_MBUTTONDBLCLK
| WM_MBUTTONDOWN | WM_MBUTTONUP | WM_RBUTTONDBLCLK | WM_RBUTTONDOWN | WM_RBUTTONUP
| WM_XBUTTONDBLCLK | WM_XBUTTONDOWN | WM_XBUTTONUP => {
+ let mut should_release_capture = false;
if let Ok(mut s) = self.state.try_borrow_mut() {
let s = s.as_mut().unwrap();
let button = match msg {
@@ -667,11 +659,26 @@ impl WndProc for MyWndProc {
s.handler.mouse_down(&event);
} else {
s.handler.mouse_up(&event);
- s.exit_mouse_capture(button);
+ should_release_capture = s.exit_mouse_capture(button);
}
} else {
self.log_dropped_msg(hwnd, msg, wparam, lparam);
}
+
+ // ReleaseCapture() is deferred: it needs to be called without having a mutable
+ // reference to the window state, because it will generate a reentrant
+ // WM_CAPTURECHANGED event.
+ if should_release_capture {
+ unsafe {
+ if ReleaseCapture() == FALSE {
+ warn!(
+ "failed to release mouse capture: {}",
+ Error::Hr(HRESULT_FROM_WIN32(GetLastError()))
+ );
+ }
+ }
+ }
+
Some(0)
}
XI_REQUEST_DESTROY => {
@@ -706,6 +713,8 @@ impl WndProc for MyWndProc {
if let Ok(mut s) = self.state.try_borrow_mut() {
let s = s.as_mut().unwrap();
s.captured_mouse_buttons = 0;
+ } else {
+ self.log_dropped_msg(hwnd, msg, wparam, lparam);
}
Some(0)
}
