Skip to content

Commit dd522c1

Browse files
committed
Fix native window drags losing mouse gestures on macOS and Windows
macOS: StartResizing dequeued the mouse-up in its tracking loop and performWindowDragWithEvent: takes it too, so the view that got the mouse-down never saw it. Flutter kept its button state down, reported the next press as a move, and every second gesture was lost. Forward (or synthesize) the mouse-up to the window. Windows: StartDragging posted WM_NCLBUTTONDOWN without releasing the capture held by the view under the press, so the system move loop never started. Share one path with StartResizing: release capture, pass the cursor position, and skip the hand-over when the primary button is already up, which would otherwise glue the window to the cursor until the next click. Found by tools/gui/flutter_window_drag_areas_test in the workspace.
1 parent 069d64c commit dd522c1

2 files changed

Lines changed: 47 additions & 10 deletions

File tree

‎src/platform/macos/window_macos.mm‎

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -705,10 +705,34 @@ static void NativeApiUpdateWindowClass(NSWindow* window, bool non_activating) {
705705
return [pimpl_->ns_window_ canBecomeKeyWindow];
706706
}
707707

708+
// Ends the mouse gesture of the view that received the mouse-down. The native drag and resize
709+
// loops below take the rest of the gesture, including the mouse-up; a view that never sees it
710+
// keeps its button state down (Flutter then reports the next press as a move, and that whole
711+
// gesture is lost).
712+
static void NativeApiSendMouseUp(NSWindow* window, NSEvent* mouse_up) {
713+
if (!mouse_up) {
714+
mouse_up = [NSEvent mouseEventWithType:NSEventTypeLeftMouseUp
715+
location:[window mouseLocationOutsideOfEventStream]
716+
modifierFlags:0
717+
timestamp:[NSProcessInfo processInfo].systemUptime
718+
windowNumber:window.windowNumber
719+
context:nil
720+
eventNumber:0
721+
clickCount:1
722+
pressure:0];
723+
}
724+
[window sendEvent:mouse_up];
725+
}
726+
708727
void Window::StartDragging() {
709728
NSWindow* window = pimpl_->ns_window_;
710-
if (window.currentEvent) {
711-
[window performWindowDragWithEvent:window.currentEvent];
729+
NSEvent* event = window.currentEvent;
730+
if (!event) {
731+
return;
732+
}
733+
[window performWindowDragWithEvent:event];
734+
if (event.type == NSEventTypeLeftMouseDown || event.type == NSEventTypeLeftMouseDragged) {
735+
NativeApiSendMouseUp(window, nil);
712736
}
713737
}
714738

@@ -745,6 +769,7 @@ static void NativeApiUpdateWindowClass(NSWindow* window, bool non_activating) {
745769
inMode:NSEventTrackingRunLoopMode
746770
dequeue:YES];
747771
if (!event || event.type == NSEventTypeLeftMouseUp) {
772+
NativeApiSendMouseUp(window, event);
748773
break;
749774
}
750775

‎src/platform/windows/window_windows.cpp‎

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,10 +1153,27 @@ bool Window::IsFocusable() const {
11531153
return (style & WS_DISABLED) == 0;
11541154
}
11551155

1156+
// Hands the mouse gesture in progress to the system frame, as if the press had landed on the
1157+
// given non-client area (HTCAPTION moves, HTLEFT... resize).
1158+
static void StartSystemFrameDrag(HWND hwnd, WPARAM hit_test) {
1159+
// Gesture recognizers can report a drag start after the button is already up (a plain
1160+
// click); the modal loop entered then would glue the window to the cursor until the next
1161+
// click.
1162+
const int primary = GetSystemMetrics(SM_SWAPBUTTON) ? VK_RBUTTON : VK_LBUTTON;
1163+
if ((GetAsyncKeyState(primary) & 0x8000) == 0) {
1164+
return;
1165+
}
1166+
// The caller is inside a mouse-down handler, which typically holds capture (Flutter's view
1167+
// does); release it, or the system frame never gets the drag.
1168+
ReleaseCapture();
1169+
POINT cursor;
1170+
GetCursorPos(&cursor);
1171+
PostMessage(hwnd, WM_NCLBUTTONDOWN, hit_test, MAKELPARAM(cursor.x, cursor.y));
1172+
}
1173+
11561174
void Window::StartDragging() {
11571175
if (pimpl_->hwnd_) {
1158-
// Simulate dragging by sending WM_NCLBUTTONDOWN with HTCAPTION
1159-
PostMessage(pimpl_->hwnd_, WM_NCLBUTTONDOWN, HTCAPTION, 0);
1176+
StartSystemFrameDrag(pimpl_->hwnd_, HTCAPTION);
11601177
}
11611178
}
11621179

@@ -1192,12 +1209,7 @@ void Window::StartResizing(ResizeEdge edge) {
11921209
hit_test = HTBOTTOMRIGHT;
11931210
break;
11941211
}
1195-
// The caller is inside a mouse-down handler, which typically holds capture;
1196-
// release it so the system frame can take over the drag.
1197-
ReleaseCapture();
1198-
POINT cursor;
1199-
GetCursorPos(&cursor);
1200-
PostMessage(pimpl_->hwnd_, WM_NCLBUTTONDOWN, hit_test, MAKELPARAM(cursor.x, cursor.y));
1212+
StartSystemFrameDrag(pimpl_->hwnd_, hit_test);
12011213
}
12021214

12031215
WindowId Window::GetId() const {

0 commit comments

Comments
 (0)