Module: wine Branch: master Commit: 153f3e27c4dce070def05bc03da46f6c9ba2fa5e URL: http://source.winehq.org/git/wine.git/?a=commit;h=153f3e27c4dce070def05bc03d...
Author: Ken Thomases ken@codeweavers.com Date: Wed Jun 19 19:09:33 2013 -0500
winemac: Forcibly release mouse capture for clicks in Mac menu bar or app deactivation.
---
dlls/winemac.drv/cocoa_app.m | 34 ++++++++++++++++++++++++++++++++++ dlls/winemac.drv/event.c | 5 +++++ dlls/winemac.drv/macdrv_cocoa.h | 1 + dlls/winemac.drv/mouse.c | 23 +++++++++++++++++++++++ 4 files changed, 63 insertions(+), 0 deletions(-)
diff --git a/dlls/winemac.drv/cocoa_app.m b/dlls/winemac.drv/cocoa_app.m index 20050bf..25081db 100644 --- a/dlls/winemac.drv/cocoa_app.m +++ b/dlls/winemac.drv/cocoa_app.m @@ -1719,6 +1719,7 @@ int macdrv_err_on; { NSNotificationCenter* nc = [NSNotificationCenter defaultCenter]; NSNotificationCenter* wsnc = [[NSWorkspace sharedWorkspace] notificationCenter]; + NSDistributedNotificationCenter* dnc = [NSDistributedNotificationCenter defaultCenter];
[nc addObserverForName:NSWindowDidBecomeKeyNotification object:nil @@ -1760,6 +1761,17 @@ int macdrv_err_on; 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 @@ int macdrv_err_on; 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 @@ int macdrv_err_on; [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 deac187..5eb823e 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 cdfe85b..40173ba 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -175,6 +175,7 @@ enum { 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 2e49909..b729d55 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()); + } +}