On Mon, 9 Mar 2026 19:38:15 GMT, Jose Pereda <[email protected]> wrote:

> This PR adds a fix to close the popup windows on macOS when clicking over the 
> system menu bar. 
> 
> According to the macOS standard behaviour for native applications, when a 
> popup window is showing, and the user clicks on the system menu bar, the 
> click event is consumed and the popup is closed. A second click is then 
> required to open the system menu bar.
> 
> This is done by the popup windows directly, as they are NSMenu objects that 
> enable a modal event tracking loop, capturing all events including those from 
> the system menu bar, in order to dismiss the popup when the click is outside 
> the window.
> 
> However, JavaFX just implements regular NSWindows, and there is no such event 
> loop. Therefore, this PR adds a notification to the system menu instead. When 
> the menu is about to open, the popup window gets a notification, which is 
> processed to cancel the menu animation, preventing it from showing up, and 
> also closing the popup. And then, with the popup closed, a new click from the 
> user will open the system menus as usual.
> 
> This applies to all JavaFX menus from the system menu bar, that is: the 
> application menu (the "java" menu when the application is not packaged yet) 
> and other menus created by the application, if any. 
> 
> It doesn't apply to the Apple system menu, which is not handle by JavaFX, 
> though. This causes a difference with native applications, that treat such 
> menu in the same way.

## Pull request overview

This PR aims to make JavaFX popup windows on macOS dismiss when the user clicks 
the system menu bar (so the first click closes the popup and a second click is 
needed to open the menu), matching typical native macOS behavior.

**Changes:**
- Post a new notification from `GlassMenu` right before a menu starts opening.
- Register popup windows to observe that notification.
- When observed, attempt to cancel menu tracking and dismiss the popup.

### Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 
comments.

| File | Description |
| ---- | ----------- |
| modules/javafx.graphics/src/main/native-glass/mac/GlassWindow.m | Registers 
popup windows as observers of a new “menubar will open” notification. |
| modules/javafx.graphics/src/main/native-glass/mac/GlassWindow+Overrides.m | 
Adds the notification handler intended to cancel menu opening and dismiss the 
popup; removes the observer on close. |
| modules/javafx.graphics/src/main/native-glass/mac/GlassMenu.m | Posts the 
notification from `menuWillOpen:` before running existing Java callbacks. |
| modules/javafx.graphics/src/main/native-glass/mac/GlassMenu.h | Introduces 
the notification name constant. |





---

💡 <a 
href="/openjdk/jfx/new/master?filename=.github/instructions/*.instructions.md" 
class="Link--inTextBlock" target="_blank" rel="noopener noreferrer">Add Copilot 
custom instructions</a> for smarter, more guided reviews. <a 
href="https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot";
 class="Link--inTextBlock" target="_blank" rel="noopener noreferrer">Learn how 
to get started</a>.

modules/javafx.graphics/src/main/native-glass/mac/GlassWindow+Overrides.m line 
329:

> 327:     if (menu != nil) {
> 328:         [menu cancelTrackingWithoutAnimation];
> 329:     }

menuWillOpenHandler will run for every popup window that registered the 
observer, including popups that are currently hidden via orderOut (see 
_setVisible(false) in GlassWindow.m). Without a visibility/grab check, a hidden 
popup can still cancelTrackingWithoutAnimation and prevent the menu bar from 
opening (consuming the first click even though no popup is showing). Consider 
returning early unless the popup is actually visible (and ideally the one 
holding the current grab) before cancelling menu tracking / dismissing it.

modules/javafx.graphics/src/main/native-glass/mac/GlassWindow+Overrides.m line 
333:

> 331:     // Close the popup window
> 332:     [self->nsWindow close];
> 333: }

Calling [self->nsWindow close] here will destroy the Glass window 
(notifyDestroy sets ptr=0) rather than just dismissing/hiding the popup, which 
can break popup reuse (PopupStage typically toggles visibility instead of 
closing). It also bypasses the existing deferred-close logic in 
MacWindow._close (performSelectorOnMainThread) that avoids AppKit reentrancy 
crashes. Prefer dismissing the popup via the existing ungrab/hide path (e.g., 
_ungrabFocus + orderOut / triggering the Java-side hide) rather than closing 
the NSWindow directly.

-------------

PR Review: https://git.openjdk.org/jfx/pull/2102#pullrequestreview-3917817226
PR Review Comment: https://git.openjdk.org/jfx/pull/2102#discussion_r2907584133
PR Review Comment: https://git.openjdk.org/jfx/pull/2102#discussion_r2907584153

Reply via email to