Tim Clem : winemac.drv: Use window drag notifications when available.

Alexandre Julliard julliard at winehq.org
Wed Sep 15 16:21:29 CDT 2021


Module: wine
Branch: master
Commit: bb28d54d08023f6cea7be2c2c52545ab7f61e30b
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=bb28d54d08023f6cea7be2c2c52545ab7f61e30b

Author: Tim Clem <tclem at codeweavers.com>
Date:   Tue Sep 14 13:22:45 2021 -0700

winemac.drv: Use window drag notifications when available.

When running on macOS 10.12+, there are private notification center
messages we can use to reliably detect when a window is being
dragged by its titlebar. These are less finicky than the current
combination of an undocumented event subtype and a left mouse up.

Signed-off-by: Tim Clem <tclem at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/winemac.drv/cocoa_app.h |  1 +
 dlls/winemac.drv/cocoa_app.m | 93 +++++++++++++++++++++++++++++++-------------
 2 files changed, 66 insertions(+), 28 deletions(-)

diff --git a/dlls/winemac.drv/cocoa_app.h b/dlls/winemac.drv/cocoa_app.h
index 7abea0990e9..0b70a2fd55b 100644
--- a/dlls/winemac.drv/cocoa_app.h
+++ b/dlls/winemac.drv/cocoa_app.h
@@ -131,6 +131,7 @@ enum {
     BOOL beenActive;
 
     NSMutableSet* windowsBeingDragged;
+    BOOL useDragNotifications;
 }
 
 @property (nonatomic) CGEventSourceKeyboardType keyboardType;
diff --git a/dlls/winemac.drv/cocoa_app.m b/dlls/winemac.drv/cocoa_app.m
index e296d4b4af0..fe10ee8c41d 100644
--- a/dlls/winemac.drv/cocoa_app.m
+++ b/dlls/winemac.drv/cocoa_app.m
@@ -27,6 +27,12 @@
 
 static NSString* const WineAppWaitQueryResponseMode = @"WineAppWaitQueryResponseMode";
 
+// Private notifications that are reliably dispatched when a window is moved by dragging its titlebar.
+// The object of the notification is the window being dragged.
+// Available in macOS 10.12+
+static NSString* const NSWindowWillStartDraggingNotification = @"NSWindowWillStartDraggingNotification";
+static NSString* const NSWindowDidEndDraggingNotification = @"NSWindowDidEndDraggingNotification";
+
 
 int macdrv_err_on;
 
@@ -181,6 +187,15 @@ static NSString* WineLocalizedString(unsigned int stringID)
 
             windowsBeingDragged = [[NSMutableSet alloc] init];
 
+            // On macOS 10.12+, use notifications to more reliably detect when windows are being dragged.
+            if ([NSProcessInfo instancesRespondToSelector:@selector(isOperatingSystemAtLeastVersion:)])
+            {
+                NSOperatingSystemVersion requiredVersion = { 10, 12, 0 };
+                useDragNotifications = [[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:requiredVersion];
+            }
+            else
+                useDragNotifications = NO;
+
             if (!requests || !requestsManipQueue || !eventQueues || !eventQueuesLock ||
                 !keyWindows || !originalDisplayModes || !latentDisplayModes || !warpRecords)
             {
@@ -1554,32 +1569,28 @@ static NSString* WineLocalizedString(unsigned int stringID)
         }
     }
 
-    - (void) handleWindowDrag:(NSEvent*)anEvent begin:(BOOL)begin
+    - (void) handleWindowDrag:(WineWindow*)window begin:(BOOL)begin
     {
-        WineWindow* window = (WineWindow*)[anEvent window];
-        if ([window isKindOfClass:[WineWindow class]])
-        {
-            macdrv_event* event;
-            int eventType;
-
-            if (begin)
-            {
-                [windowsBeingDragged addObject:window];
-                eventType = WINDOW_DRAG_BEGIN;
-            }
-            else
-            {
-                [windowsBeingDragged removeObject:window];
-                eventType = WINDOW_DRAG_END;
-            }
-            [self updateCursorClippingState];
+        macdrv_event* event;
+        int eventType;
 
-            event = macdrv_create_event(eventType, window);
-            if (eventType == WINDOW_DRAG_BEGIN)
-                event->window_drag_begin.no_activate = [NSEvent wine_commandKeyDown];
-            [window.queue postEvent:event];
-            macdrv_release_event(event);
+        if (begin)
+        {
+            [windowsBeingDragged addObject:window];
+            eventType = WINDOW_DRAG_BEGIN;
         }
+        else
+        {
+            [windowsBeingDragged removeObject:window];
+            eventType = WINDOW_DRAG_END;
+        }
+        [self updateCursorClippingState];
+
+        event = macdrv_create_event(eventType, window);
+        if (eventType == WINDOW_DRAG_BEGIN)
+            event->window_drag_begin.no_activate = [NSEvent wine_commandKeyDown];
+        [window.queue postEvent:event];
+        macdrv_release_event(event);
     }
 
     - (void) handleMouseMove:(NSEvent*)anEvent
@@ -1736,8 +1747,13 @@ static NSString* WineLocalizedString(unsigned int stringID)
         WineWindow* windowBroughtForward = nil;
         BOOL process = FALSE;
 
-        if (type == NSEventTypeLeftMouseUp && [windowsBeingDragged count])
-            [self handleWindowDrag:theEvent begin:NO];
+        if (!useDragNotifications &&
+            type == NSEventTypeLeftMouseUp &&
+            [windowsBeingDragged count] &&
+            [window isKindOfClass:[WineWindow class]])
+        {
+            [self handleWindowDrag:window begin:NO];
+        }
 
         if ([window isKindOfClass:[WineWindow class]] &&
             type == NSEventTypeLeftMouseDown &&
@@ -2085,15 +2101,16 @@ static NSString* WineLocalizedString(unsigned int stringID)
                     [window postKeyEvent:anEvent];
             }
         }
-        else if (type == NSEventTypeAppKitDefined)
+        else if (!useDragNotifications && type == NSEventTypeAppKitDefined)
         {
+            WineWindow *window = (WineWindow *)[anEvent window];
             short subtype = [anEvent subtype];
 
             // These subtypes are not documented but they appear to mean
             // "a window is being dragged" and "a window is no longer being
             // dragged", respectively.
-            if (subtype == 20 || subtype == 21)
-                [self handleWindowDrag:anEvent begin:(subtype == 20)];
+            if ((subtype == 20 || subtype == 21) && [window isKindOfClass:[WineWindow class]])
+                [self handleWindowDrag:window begin:(subtype == 20)];
         }
 
         return ret;
@@ -2155,6 +2172,26 @@ static NSString* WineLocalizedString(unsigned int stringID)
             [self updateCursorClippingState];
         }];
 
+        if (useDragNotifications) {
+            [nc addObserverForName:NSWindowWillStartDraggingNotification
+                            object:nil
+                             queue:[NSOperationQueue mainQueue]
+                        usingBlock:^(NSNotification *note){
+                NSWindow* window = [note object];
+                if ([window isKindOfClass:[WineWindow class]])
+                    [self handleWindowDrag:(WineWindow *)window begin:YES];
+            }];
+
+            [nc addObserverForName:NSWindowDidEndDraggingNotification
+                            object:nil
+                             queue:[NSOperationQueue mainQueue]
+                        usingBlock:^(NSNotification *note){
+                NSWindow* window = [note object];
+                if ([window isKindOfClass:[WineWindow class]])
+                    [self handleWindowDrag:(WineWindow *)window begin:NO];
+            }];
+        }
+
         [nc addObserver:self
                selector:@selector(keyboardSelectionDidChange)
                    name:NSTextInputContextKeyboardSelectionDidChangeNotification




More information about the wine-cvs mailing list