Commit 7619ad3430382c1ac2923562d083766eafd1dcc1

Ryan C. Gordon 2015-05-31T21:43:36

Cocoa: deal with mouse focus when warping the cursor from outside a window. Otherwise, you might not get appropriate mouse enter/leave events. Better fix for Bugzilla #2984.

diff --git a/src/video/cocoa/SDL_cocoamouse.m b/src/video/cocoa/SDL_cocoamouse.m
index 9c37c47..3c0c478 100644
--- a/src/video/cocoa/SDL_cocoamouse.m
+++ b/src/video/cocoa/SDL_cocoamouse.m
@@ -195,6 +195,21 @@ Cocoa_ShowCursor(SDL_Cursor * cursor)
     return 0;
 }}
 
+static SDL_Window *
+SDL_FindWindowAtPoint(const int x, const int y)
+{
+    const SDL_Point pt = { x, y };
+    SDL_Window *i;
+    for (i = SDL_GetVideoDevice()->windows; i; i = i->next) {
+        const SDL_Rect r = { i->x, i->y, i->w, i->h };
+        if (SDL_PointInRect(&pt, &r)) {
+            return i;
+        }
+    }
+
+    return NULL;
+}
+
 static void
 Cocoa_WarpMouseGlobal(int x, int y)
 {
@@ -207,7 +222,7 @@ Cocoa_WarpMouseGlobal(int x, int y)
             return;
         }
     }
-    CGPoint point = CGPointMake((float)x, (float)y);
+    const CGPoint point = CGPointMake((float)x, (float)y);
 
     Cocoa_HandleMouseWarp(point.x, point.y);
 
@@ -219,21 +234,22 @@ Cocoa_WarpMouseGlobal(int x, int y)
     CGWarpMouseCursorPosition(point);
     CGSetLocalEventsSuppressionInterval(0.25);
 
-    if (!mouse->relative_mode && mouse->focus) {
-        /* CGWarpMouseCursorPosition doesn't generate a window event, unlike our
-         * other implementations' APIs.
-         */
-        SDL_SendMouseMotion(mouse->focus, mouse->mouseID, 0, x - mouse->focus->x, y - mouse->focus->y);
+    /* CGWarpMouseCursorPosition doesn't generate a window event, unlike our
+     * other implementations' APIs. Send what's appropriate.
+     */
+    if (!mouse->relative_mode) {
+        SDL_Window *win = SDL_FindWindowAtPoint(x, y);
+        SDL_SetMouseFocus(win);
+        if (win) {
+            SDL_assert(win == mouse->focus);
+            SDL_SendMouseMotion(win, mouse->mouseID, 0, x - win->x, y - win->y);
+        }
     }
 }
 
 static void
 Cocoa_WarpMouse(SDL_Window * window, int x, int y)
 {
-    /* pretend we have the mouse focus, even if we don't, so
-        Cocoa_WarpMouseGlobal() will properly fake a mouse motion event. */
-    SDL_Mouse *mouse = SDL_GetMouse();
-    mouse->focus = window;
     Cocoa_WarpMouseGlobal(x + window->x, y + window->y);
 }