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@codeweavers.com --- 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 @@ @interface WineApplicationController : NSObject <NSApplicationDelegate> 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 @@ - (id) init
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 @@ - (void) windowWillOrderOut:(WineWindow*)window } }
- - (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 @@ - (void) handleMouseButton:(NSEvent*)theEvent 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 @@ - (BOOL) handleEvent:(NSEvent*)anEvent [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 @@ - (void) setupObservations [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
This approach was added by 5cf64084fb6 to work around changes to event behavior in macOS Catalina, 10.15. However, more reliable notification center messages for dragging are available on 10.12+, making this path unnecessary.
Signed-off-by: Tim Clem tclem@codeweavers.com --- dlls/winemac.drv/cocoa_app.m | 8 -------- 1 file changed, 8 deletions(-)
diff --git a/dlls/winemac.drv/cocoa_app.m b/dlls/winemac.drv/cocoa_app.m index fe10ee8c41d..2d18da7f99a 100644 --- a/dlls/winemac.drv/cocoa_app.m +++ b/dlls/winemac.drv/cocoa_app.m @@ -1747,14 +1747,6 @@ - (void) handleMouseButton:(NSEvent*)theEvent WineWindow* windowBroughtForward = nil; BOOL process = FALSE;
- if (!useDragNotifications && - type == NSEventTypeLeftMouseUp && - [windowsBeingDragged count] && - [window isKindOfClass:[WineWindow class]]) - { - [self handleWindowDrag:window begin:NO]; - } - if ([window isKindOfClass:[WineWindow class]] && type == NSEventTypeLeftMouseDown && ![theEvent wine_commandKeyDown])
FWIW, this series looks good to me.
Huw.