From 88e4755c26d5fd5c9f8da17fb0e1659ff46d9203 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
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 b6942af084..5680ef58c4 100644
--- a/src/video/cocoa/SDL_cocoamouse.m
+++ b/src/video/cocoa/SDL_cocoamouse.m
@@ -215,8 +215,8 @@ + (NSCursor *)invisibleCursor
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 @@ + (NSCursor *)invisibleCursor
* 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 @@ + (NSCursor *)invisibleCursor
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 @@ + (NSCursor *)invisibleCursor
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 e14bb1d473..37bec665e9 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 4586073b54..7a1446f096 100644
--- a/src/video/cocoa/SDL_cocoawindow.m
+++ b/src/video/cocoa/SDL_cocoawindow.m
@@ -508,6 +508,26 @@ - (BOOL)isMoving
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 @@ -(void) setPendingMoveX:(int)x Y:(int)y
- (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 @@ - (void)windowDidBecomeKey:(NSNotification *)aNotification
/* 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 @@ - (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
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;