Browse Source

cocoa: Immediately update the mouse focus when showing/hiding a popup menu

When showing or hiding a popup menu, manually check and set the focus if the new topmost window under the cursor is an SDL window. Otherwise, the focus won't be updated until the cursor is actually moved.

(cherry picked from commit 6f5892e5436259357fe3befad74e55844d8fa02d)
Frank Praznik 3 months ago
parent
commit
01000c73b0
1 changed files with 36 additions and 1 deletions
  1. 36 1
      src/video/cocoa/SDL_cocoawindow.m

+ 36 - 1
src/video/cocoa/SDL_cocoawindow.m

@@ -2115,6 +2115,36 @@ static void Cocoa_SendMouseButtonClicks(SDL_Mouse *mouse, NSEvent *theEvent, SDL
 
 @end
 
+static void Cocoa_UpdateMouseFocus()
+{
+    const NSPoint mouseLocation = [NSEvent mouseLocation];
+
+    // Find the topmost window under the pointer and send a motion event if it is an SDL window.
+    [NSApp enumerateWindowsWithOptions:NSWindowListOrderedFrontToBack
+                            usingBlock:^(NSWindow *nswin, BOOL *stop) {
+                              NSRect r = [nswin contentRectForFrameRect:[nswin frame]];
+                              if (NSPointInRect(mouseLocation, r)) {
+                                  SDL_VideoDevice *vid = SDL_GetVideoDevice();
+                                  SDL_Window *sdlwindow;
+                                  for (sdlwindow = vid->windows; sdlwindow; sdlwindow = sdlwindow->next) {
+                                      if (nswin == ((__bridge SDL_CocoaWindowData *)sdlwindow->internal).nswindow) {
+                                          break;
+                                      }
+                                  }
+                                  *stop = YES;
+                                  if (sdlwindow) {
+                                      int wx, wy;
+                                      SDL_RelativeToGlobalForWindow(sdlwindow, sdlwindow->x, sdlwindow->y, &wx, &wy);
+
+                                      // Calculate the cursor coordinates relative to the window.
+                                      const float dx = mouseLocation.x - wx;
+                                      const float dy = (CGDisplayPixelsHigh(kCGDirectMainDisplay) - mouseLocation.y) - wy;
+                                      SDL_SendMouseMotion(0, sdlwindow, SDL_GLOBAL_MOUSE_ID, false, dx, dy);
+                                  }
+                              }
+                            }];
+}
+
 static bool SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, NSWindow *nswindow, NSView *nsview)
 {
     @autoreleasepool {
@@ -2213,8 +2243,9 @@ static bool SetupWindowData(SDL_VideoDevice *_this, SDL_Window *window, NSWindow
             if (window->flags & SDL_WINDOW_TOOLTIP) {
                 [nswindow setIgnoresMouseEvents:YES];
                 [nswindow setAcceptsMouseMovedEvents:NO];
-            } else if (window->flags & SDL_WINDOW_POPUP_MENU) {
+            } else if ((window->flags & SDL_WINDOW_POPUP_MENU) && !(window->flags & SDL_WINDOW_HIDDEN)) {
                 Cocoa_SetKeyboardFocus(window, window->parent == SDL_GetKeyboardFocus());
+                Cocoa_UpdateMouseFocus();
             }
         }
 
@@ -2599,6 +2630,9 @@ void Cocoa_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
                         [nswindow orderWindow:NSWindowBelow relativeTo:[[NSApp keyWindow] windowNumber]];
                     }
                 }
+            } else if (window->flags & SDL_WINDOW_POPUP_MENU) {
+                Cocoa_SetKeyboardFocus(window, window->parent == SDL_GetKeyboardFocus());
+                Cocoa_UpdateMouseFocus();
             }
         }
         [nswindow setIsVisible:YES];
@@ -2646,6 +2680,7 @@ void Cocoa_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
             }
 
             Cocoa_SetKeyboardFocus(new_focus, set_focus);
+            Cocoa_UpdateMouseFocus();
         } else if (window->parent && waskey) {
             /* Key status is not automatically set on the parent when a child is hidden. Check if the
              * child window was key, and set the first visible parent to be key if so.