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@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Tim Clem 2021-09-14 13:22:45 -07:00 committed by Alexandre Julliard
parent b5e17b669a
commit bb28d54d08
2 changed files with 66 additions and 28 deletions

View File

@ -131,6 +131,7 @@ @interface WineApplicationController : NSObject <NSApplicationDelegate>
BOOL beenActive; BOOL beenActive;
NSMutableSet* windowsBeingDragged; NSMutableSet* windowsBeingDragged;
BOOL useDragNotifications;
} }
@property (nonatomic) CGEventSourceKeyboardType keyboardType; @property (nonatomic) CGEventSourceKeyboardType keyboardType;

View File

@ -27,6 +27,12 @@
static NSString* const WineAppWaitQueryResponseMode = @"WineAppWaitQueryResponseMode"; 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; int macdrv_err_on;
@ -181,6 +187,15 @@ - (id) init
windowsBeingDragged = [[NSMutableSet alloc] 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 || if (!requests || !requestsManipQueue || !eventQueues || !eventQueuesLock ||
!keyWindows || !originalDisplayModes || !latentDisplayModes || !warpRecords) !keyWindows || !originalDisplayModes || !latentDisplayModes || !warpRecords)
{ {
@ -1554,10 +1569,7 @@ - (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; macdrv_event* event;
int eventType; int eventType;
@ -1580,7 +1592,6 @@ - (void) handleWindowDrag:(NSEvent*)anEvent begin:(BOOL)begin
[window.queue postEvent:event]; [window.queue postEvent:event];
macdrv_release_event(event); macdrv_release_event(event);
} }
}
- (void) handleMouseMove:(NSEvent*)anEvent - (void) handleMouseMove:(NSEvent*)anEvent
{ {
@ -1736,8 +1747,13 @@ - (void) handleMouseButton:(NSEvent*)theEvent
WineWindow* windowBroughtForward = nil; WineWindow* windowBroughtForward = nil;
BOOL process = FALSE; BOOL process = FALSE;
if (type == NSEventTypeLeftMouseUp && [windowsBeingDragged count]) if (!useDragNotifications &&
[self handleWindowDrag:theEvent begin:NO]; type == NSEventTypeLeftMouseUp &&
[windowsBeingDragged count] &&
[window isKindOfClass:[WineWindow class]])
{
[self handleWindowDrag:window begin:NO];
}
if ([window isKindOfClass:[WineWindow class]] && if ([window isKindOfClass:[WineWindow class]] &&
type == NSEventTypeLeftMouseDown && type == NSEventTypeLeftMouseDown &&
@ -2085,15 +2101,16 @@ - (BOOL) handleEvent:(NSEvent*)anEvent
[window postKeyEvent:anEvent]; [window postKeyEvent:anEvent];
} }
} }
else if (type == NSEventTypeAppKitDefined) else if (!useDragNotifications && type == NSEventTypeAppKitDefined)
{ {
WineWindow *window = (WineWindow *)[anEvent window];
short subtype = [anEvent subtype]; short subtype = [anEvent subtype];
// These subtypes are not documented but they appear to mean // These subtypes are not documented but they appear to mean
// "a window is being dragged" and "a window is no longer being // "a window is being dragged" and "a window is no longer being
// dragged", respectively. // dragged", respectively.
if (subtype == 20 || subtype == 21) if ((subtype == 20 || subtype == 21) && [window isKindOfClass:[WineWindow class]])
[self handleWindowDrag:anEvent begin:(subtype == 20)]; [self handleWindowDrag:window begin:(subtype == 20)];
} }
return ret; return ret;
@ -2155,6 +2172,26 @@ - (void) setupObservations
[self updateCursorClippingState]; [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 [nc addObserver:self
selector:@selector(keyboardSelectionDidChange) selector:@selector(keyboardSelectionDidChange)
name:NSTextInputContextKeyboardSelectionDidChangeNotification name:NSTextInputContextKeyboardSelectionDidChangeNotification