Skip to content

Commit 12f1d96

Browse files
committed
Improve menu popup positioning on macOS
Refactored the Menu::Open method to better handle window and view selection, coordinate conversion, and menu popup on the main run loop. This ensures more reliable context menu display, especially when the main or key window is available, and properly accounts for flipped views.
1 parent cb4025e commit 12f1d96

File tree

1 file changed

+49
-18
lines changed

1 file changed

+49
-18
lines changed

src/platform/macos/menu_macos.mm

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -790,28 +790,59 @@ - (void)menuDidClose:(NSMenu*)menu {
790790
}
791791

792792
bool Menu::Open(double x, double y) {
793-
NSPoint point = NSMakePoint(x, y);
794-
795-
// Convert screen coordinates to window coordinates if needed
796-
NSEvent* event = [NSEvent mouseEventWithType:NSEventTypeRightMouseDown
797-
location:point
798-
modifierFlags:0
799-
timestamp:0
800-
windowNumber:0
801-
context:nil
802-
eventNumber:0
803-
clickCount:1
804-
pressure:1.0];
793+
// Get the main window
794+
NSWindow* mainWindow = [[NSApplication sharedApplication] mainWindow];
795+
if (!mainWindow) {
796+
// Fallback to key window if main window is not available
797+
mainWindow = [[NSApplication sharedApplication] keyWindow];
798+
}
799+
800+
if (!mainWindow) {
801+
// If still no window, use the old implementation
802+
NSPoint point = NSMakePoint(x, y);
803+
NSEvent* event = [NSEvent mouseEventWithType:NSEventTypeRightMouseDown
804+
location:point
805+
modifierFlags:0
806+
timestamp:0
807+
windowNumber:0
808+
context:nil
809+
eventNumber:0
810+
clickCount:1
811+
pressure:1.0];
812+
813+
pimpl_->visible_ = true;
814+
815+
@autoreleasepool {
816+
NSView* dummyView = [[NSView alloc] init];
817+
[NSMenu popUpContextMenu:pimpl_->ns_menu_ withEvent:event forView:dummyView];
818+
}
805819

806-
pimpl_->visible_ = true;
820+
pimpl_->visible_ = false;
821+
return true;
822+
}
807823

808-
@autoreleasepool {
809-
// Create a dummy view to avoid the nil warning
810-
NSView* dummyView = [[NSView alloc] init];
811-
[NSMenu popUpContextMenu:pimpl_->ns_menu_ withEvent:event forView:dummyView];
824+
NSView* contentView = [mainWindow contentView];
825+
if (!contentView) {
826+
return false;
812827
}
813828

814-
pimpl_->visible_ = false;
829+
// Convert coordinates if the content view is not flipped
830+
// In macOS, the default coordinate system has origin at bottom-left
831+
// If view is not flipped, we need to convert from top-left origin
832+
CGFloat finalY = y;
833+
if (![contentView isFlipped]) {
834+
CGFloat frameHeight = [contentView frame].size.height;
835+
finalY = frameHeight - y;
836+
}
837+
838+
NSPoint point = NSMakePoint(x, finalY);
839+
840+
pimpl_->visible_ = true;
841+
842+
// Use dispatch to ensure menu popup happens on the main run loop
843+
dispatch_async(dispatch_get_main_queue(), ^{
844+
[pimpl_->ns_menu_ popUpMenuPositioningItem:nil atLocation:point inView:contentView];
845+
});
815846

816847
return true;
817848
}

0 commit comments

Comments
 (0)