diff --git a/dlls/winemac.drv/cocoa_app.m b/dlls/winemac.drv/cocoa_app.m index 20050bf55ab..25081db2892 100644 --- a/dlls/winemac.drv/cocoa_app.m +++ b/dlls/winemac.drv/cocoa_app.m @@ -1719,6 +1719,7 @@ - (void) setupObservations { NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; NSNotificationCenter* wsnc = [[NSWorkspace sharedWorkspace] notificationCenter]; + NSDistributedNotificationCenter* dnc = [NSDistributedNotificationCenter defaultCenter]; [nc addObserverForName:NSWindowDidBecomeKeyNotification object:nil @@ -1760,6 +1761,17 @@ - (void) setupObservations selector:@selector(activeSpaceDidChange) name:NSWorkspaceActiveSpaceDidChangeNotification object:nil]; + + [nc addObserver:self + selector:@selector(releaseMouseCapture) + name:NSMenuDidBeginTrackingNotification + object:nil]; + + [dnc addObserver:self + selector:@selector(releaseMouseCapture) + name:@"com.apple.HIToolbox.beginMenuTrackingNotification" + object:nil + suspensionBehavior:NSNotificationSuspensionBehaviorDrop]; } - (BOOL) inputSourceIsInputMethod @@ -1781,6 +1793,26 @@ - (BOOL) inputSourceIsInputMethod return inputSourceIsInputMethod; } + - (void) releaseMouseCapture + { + // This might be invoked on a background thread by the distributed + // notification center. Shunt it to the main thread. + if (![NSThread isMainThread]) + { + dispatch_async(dispatch_get_main_queue(), ^{ [self releaseMouseCapture]; }); + return; + } + + if (mouseCaptureWindow) + { + macdrv_event* event; + + event = macdrv_create_event(RELEASE_CAPTURE, mouseCaptureWindow); + [mouseCaptureWindow.queue postEvent:event]; + macdrv_release_event(event); + } + } + /* * ---------- NSApplicationDelegate methods ---------- @@ -1850,6 +1882,8 @@ - (void)applicationDidResignActive:(NSNotification *)notification [eventQueuesLock unlock]; macdrv_release_event(event); + + [self releaseMouseCapture]; } - (NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication *)sender diff --git a/dlls/winemac.drv/event.c b/dlls/winemac.drv/event.c index deac187d7c4..5eb823e167c 100644 --- a/dlls/winemac.drv/event.c +++ b/dlls/winemac.drv/event.c @@ -44,6 +44,7 @@ static const char *dbgstr_event(int type) "MOUSE_MOVED_ABSOLUTE", "MOUSE_SCROLL", "QUERY_EVENT", + "RELEASE_CAPTURE", "STATUS_ITEM_CLICKED", "WINDOW_CLOSE_REQUESTED", "WINDOW_DID_MINIMIZE", @@ -104,6 +105,7 @@ static macdrv_event_mask get_event_mask(DWORD mask) if (mask & QS_SENDMESSAGE) { event_mask |= event_mask_for_type(QUERY_EVENT); + event_mask |= event_mask_for_type(RELEASE_CAPTURE); } return event_mask; @@ -202,6 +204,9 @@ void macdrv_handle_event(const macdrv_event *event) case QUERY_EVENT: macdrv_query_event(hwnd, event); break; + case RELEASE_CAPTURE: + macdrv_release_capture(hwnd, event); + break; case STATUS_ITEM_CLICKED: macdrv_status_item_clicked(event); break; diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index cdfe85b6110..40173bae8fd 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -175,6 +175,7 @@ extern int macdrv_set_display_mode(const struct macdrv_display* display, MOUSE_MOVED_ABSOLUTE, MOUSE_SCROLL, QUERY_EVENT, + RELEASE_CAPTURE, STATUS_ITEM_CLICKED, WINDOW_CLOSE_REQUESTED, WINDOW_DID_MINIMIZE, diff --git a/dlls/winemac.drv/mouse.c b/dlls/winemac.drv/mouse.c index 2e49909bd0d..b729d5584cc 100644 --- a/dlls/winemac.drv/mouse.c +++ b/dlls/winemac.drv/mouse.c @@ -918,3 +918,26 @@ void macdrv_mouse_scroll(HWND hwnd, const macdrv_event *event) event->mouse_scroll.x, event->mouse_scroll.y, event->mouse_scroll.x_scroll, FALSE, event->mouse_scroll.time_ms); } + + +/*********************************************************************** + * macdrv_release_capture + * + * Handler for RELEASE_CAPTURE events. + */ +void macdrv_release_capture(HWND hwnd, const macdrv_event *event) +{ + struct macdrv_thread_data *thread_data = macdrv_thread_data(); + HWND capture = GetCapture(); + HWND capture_top = GetAncestor(capture, GA_ROOT); + + TRACE("win %p/%p thread_data->capture_window %p GetCapture() %p in %p\n", hwnd, + event->window, thread_data->capture_window, capture, capture_top); + + if (event->window == thread_data->capture_window && hwnd == capture_top) + { + ReleaseCapture(); + if (!PostMessageW(capture, WM_CANCELMODE, 0, 0)) + WARN("failed to post WM_CANCELMODE; error 0x%08x\n", GetLastError()); + } +}