From 88e4755c26d5fd5c9f8da17fb0e1659ff46d9203 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 27 Jul 2021 12:43:00 -0700 Subject: [PATCH] Make sure we don't try to turn on relative mouse mode while clicking on the window title bar. This fixes bug https://github.com/libsdl-org/SDL/issues/4469 --- src/video/cocoa/SDL_cocoamouse.m | 49 +++++++++++++++++++++++++++++-- src/video/cocoa/SDL_cocoawindow.h | 5 ++++ src/video/cocoa/SDL_cocoawindow.m | 47 +++++++++++++++++++++++++++-- 3 files changed, 95 insertions(+), 6 deletions(-) diff --git a/src/video/cocoa/SDL_cocoamouse.m b/src/video/cocoa/SDL_cocoamouse.m index b6942af08..5680ef58c 100644 --- a/src/video/cocoa/SDL_cocoamouse.m +++ b/src/video/cocoa/SDL_cocoamouse.m @@ -215,8 +215,8 @@ Cocoa_WarpMouseGlobal(int x, int y) SDL_Mouse *mouse = SDL_GetMouse(); if (mouse->focus) { SDL_WindowData *data = (SDL_WindowData *) mouse->focus->driverdata; - if ([data->listener isMoving]) { - DLog("Postponing warp, window being moved."); + if ([data->listener isMovingOrFocusClickPending]) { + DLog("Postponing warp, window being moved or focused."); [data->listener setPendingMoveX:x Y:y]; return 0; } @@ -271,7 +271,7 @@ Cocoa_SetRelativeMouseMode(SDL_bool enabled) * if it is being moved right now. */ SDL_WindowData *data = (SDL_WindowData *) window->driverdata; - if ([data->listener isMoving]) { + if ([data->listener isMovingOrFocusClickPending]) { return 0; } @@ -353,6 +353,34 @@ Cocoa_InitMouse(_THIS) return 0; } +void +Cocoa_HandleTitleButtonEvent(_THIS, NSEvent *event) +{ + SDL_Window *window; + NSWindow *nswindow = [event window]; + + for (window = _this->windows; window; window = window->next) { + SDL_WindowData *data = (SDL_WindowData *)window->driverdata; + if (data && data->nswindow == nswindow) { + switch ([event type]) { + case NSEventTypeLeftMouseDown: + case NSEventTypeRightMouseDown: + case NSEventTypeOtherMouseDown: + [data->listener setFocusClickPending:[event buttonNumber]]; + break; + case NSEventTypeLeftMouseUp: + case NSEventTypeRightMouseUp: + case NSEventTypeOtherMouseUp: + [data->listener clearFocusClickPending:[event buttonNumber]]; + break; + default: + break; + } + break; + } + } +} + void Cocoa_HandleMouseEvent(_THIS, NSEvent *event) { @@ -363,6 +391,21 @@ Cocoa_HandleMouseEvent(_THIS, NSEvent *event) case NSEventTypeOtherMouseDragged: break; + case NSEventTypeLeftMouseDown: + case NSEventTypeLeftMouseUp: + case NSEventTypeRightMouseDown: + case NSEventTypeRightMouseUp: + case NSEventTypeOtherMouseDown: + case NSEventTypeOtherMouseUp: + if ([event window]) { + NSRect windowRect = [[[event window] contentView] frame]; + if (!NSMouseInRect([event locationInWindow], windowRect, NO)) { + Cocoa_HandleTitleButtonEvent(_this, event); + return; + } + } + return; + default: /* Ignore any other events. */ return; diff --git a/src/video/cocoa/SDL_cocoawindow.h b/src/video/cocoa/SDL_cocoawindow.h index e14bb1d47..37bec665e 100644 --- a/src/video/cocoa/SDL_cocoawindow.h +++ b/src/video/cocoa/SDL_cocoawindow.h @@ -48,6 +48,7 @@ typedef enum BOOL inFullscreenTransition; PendingWindowOperation pendingWindowOperation; BOOL isMoving; + int focusClickPending; int pendingWindowWarpX, pendingWindowWarpY; BOOL isDragAreaRunning; } @@ -62,8 +63,12 @@ typedef enum -(void) close; -(BOOL) isMoving; +-(BOOL) isMovingOrFocusClickPending; +-(void) setFocusClickPending:(int) button; +-(void) clearFocusClickPending:(int) button; -(void) setPendingMoveX:(int)x Y:(int)y; -(void) windowDidFinishMoving; +-(void) onMovingOrFocusClickPendingStateCleared; /* Window delegate functionality */ -(BOOL) windowShouldClose:(id) sender; diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index 4586073b5..7a1446f09 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -508,6 +508,26 @@ SetWindowStyle(SDL_Window * window, NSUInteger style) return isMoving; } +- (BOOL)isMovingOrFocusClickPending +{ + return isMoving || (focusClickPending != 0); +} + +-(void) setFocusClickPending:(int) button +{ + focusClickPending |= (1 << button); +} + +-(void) clearFocusClickPending:(int) button +{ + if ((focusClickPending & (1 << button)) != 0) { + focusClickPending &= ~(1 << button); + if (focusClickPending == 0) { + [self onMovingOrFocusClickPendingStateCleared]; + } + } +} + -(void) setPendingMoveX:(int)x Y:(int)y { pendingWindowWarpX = x; @@ -516,15 +536,36 @@ SetWindowStyle(SDL_Window * window, NSUInteger style) - (void)windowDidFinishMoving { - if ([self isMoving]) { + if (isMoving) { isMoving = NO; + [self onMovingOrFocusClickPendingStateCleared]; + } +} +- (void)onMovingOrFocusClickPendingStateCleared +{ + if (![self isMovingOrFocusClickPending]) { SDL_Mouse *mouse = SDL_GetMouse(); if (pendingWindowWarpX != INT_MAX && pendingWindowWarpY != INT_MAX) { mouse->WarpMouseGlobal(pendingWindowWarpX, pendingWindowWarpY); pendingWindowWarpX = pendingWindowWarpY = INT_MAX; } if (mouse->relative_mode && !mouse->relative_mode_warp && mouse->focus == _data->window) { + /* Move the cursor to the nearest point in the window */ + { + int x, y; + CGPoint cgpoint; + + SDL_GetMouseState(&x, &y); + cgpoint.x = _data->window->x + x; + cgpoint.y = _data->window->y + y; + + Cocoa_HandleMouseWarp(cgpoint.x, cgpoint.y); + + DLog("Returning cursor to (%g, %g)", cgpoint.x, cgpoint.y); + CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint); + } + mouse->SetRelativeMouseMode(SDL_TRUE); } } @@ -641,7 +682,7 @@ SetWindowStyle(SDL_Window * window, NSUInteger style) /* This needs to be done before restoring the relative mouse mode. */ SDL_SetKeyboardFocus(window); - if (mouse->relative_mode && !mouse->relative_mode_warp && ![self isMoving]) { + if (mouse->relative_mode && !mouse->relative_mode_warp && ![self isMovingOrFocusClickPending]) { mouse->SetRelativeMouseMode(SDL_TRUE); } @@ -1970,7 +2011,7 @@ Cocoa_SetWindowMouseGrab(_THIS, SDL_Window * window, SDL_bool grabbed) SDL_WindowData *data = (SDL_WindowData *) window->driverdata; /* Move the cursor to the nearest point in the window */ - if (grabbed && data && ![data->listener isMoving]) { + if (grabbed && data && ![data->listener isMovingOrFocusClickPending]) { int x, y; CGPoint cgpoint;