Ken Thomases : winemac: Forcibly release mouse capture for clicks in Mac menu bar or app deactivation .

Alexandre Julliard julliard at winehq.org
Thu Jun 20 15:31:16 CDT 2013


Module: wine
Branch: master
Commit: 153f3e27c4dce070def05bc03da46f6c9ba2fa5e
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=153f3e27c4dce070def05bc03da46f6c9ba2fa5e

Author: Ken Thomases <ken at 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());
+    }
+}




More information about the wine-cvs mailing list