Skip to content

8372398: [macOS] Shown ContextMenu does not close when macOS system menu is clicked#2102

Closed
jperedadnr wants to merge 7 commits into
openjdk:masterfrom
jperedadnr:8372398-macoscontextmenu
Closed

8372398: [macOS] Shown ContextMenu does not close when macOS system menu is clicked#2102
jperedadnr wants to merge 7 commits into
openjdk:masterfrom
jperedadnr:8372398-macoscontextmenu

Conversation

@jperedadnr

@jperedadnr jperedadnr commented Mar 9, 2026

Copy link
Copy Markdown
Collaborator

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.



Progress

  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue
  • Change must be properly reviewed (2 reviews required, with at least 1 Reviewer, 1 Author)

Issue

  • JDK-8372398: [macOS] Shown ContextMenu does not close when macOS system menu is clicked (Bug - P3)

Reviewers

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jfx.git pull/2102/head:pull/2102
$ git checkout pull/2102

Update a local copy of the PR:
$ git checkout pull/2102
$ git pull https://git.openjdk.org/jfx.git pull/2102/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 2102

View PR using the GUI difftool:
$ git pr show -t 2102

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jfx/pull/2102.diff

Using Webrev

Link to Webrev Comment

Copilot AI review requested due to automatic review settings March 9, 2026 19:38
@bridgekeeper

bridgekeeper Bot commented Mar 9, 2026

Copy link
Copy Markdown

👋 Welcome back jpereda! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk

openjdk Bot commented Mar 9, 2026

Copy link
Copy Markdown

@jperedadnr This change now passes all automated pre-integration checks.

ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details.

After integration, the commit message for the final commit will be:

8372398: [macOS] Shown ContextMenu does not close when macOS system menu is clicked

Reviewed-by: mfox, arapte

You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed.

At the time when this comment was updated there had been 79 new commits pushed to the master branch:

As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details.

➡️ To integrate this PR with the above commit message to the master branch, type /integrate in a new comment.

@openjdk openjdk Bot added the rfr Ready for review label Mar 9, 2026
@mlbridge

mlbridge Bot commented Mar 9, 2026

Copy link
Copy Markdown

Webrevs

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread modules/javafx.graphics/src/main/native-glass/mac/GlassWindow+Overrides.m Outdated
Comment on lines +331 to +333
// Close the popup window
[self->nsWindow close];
}

Copilot AI Mar 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
@beldenfox

Copy link
Copy Markdown
Contributor

I ran into some issues with this PR. You can reproduce using the manual PopupControlTest or any app that has a standard (non-system) menu bar. Click on "Menu" to show the menu's popup, click on the system menu bar to dismiss it, and then click on "Menu" again. The popup won't appear.

I debugged this a bit. To track this sort of dismissal the Menu control relies on its popup window going through the auto-hide logic (I think auto-hide sets a transient property that Menu monitors to detect when the popup goes away). The auto-hide logic is normally triggered by a focus ungrab event. It looks like there's a similar case in the glass code already; when the user clicks on a window's title bar glass calls _ungrabFocus to ensure auto-hiding popups are closed (see sendEvent: in GlassWindow.m).

And do we have a policy on Copilot? In this case I think it got something half-right but also got several things wrong. I don't like leaving misinformation lying around in a PR but also don't want to spend time correcting an AI.

@jperedadnr

Copy link
Copy Markdown
Collaborator Author

Thanks, @beldenfox, I can reproduce the issue with PopupControlTest. I'll have a look.

@jperedadnr

Copy link
Copy Markdown
Collaborator Author

I've just pushed a change, that should fix the issue in PopupControlTest.


// For non-auto-hide popups, jWindowNotifyClose fires WINDOW_CLOSE_REQUEST,
// and that calls hide() on the popup.
if ([self->nsWindow isVisible]) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should non-auto-hide popups be hidden? The spec doesn't talk about them much and I'm not sure what they're used for.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a very good question, indeed.

I'm testing a native Xcode project, and a NSPanel by default is non-auto-hide. For instance, Finder -> Get Info opens an auxiliary window, and it won't close when opening the system menu bar or clicking elsewhere.

However, Finder -> right click on a file-> Context Menu is auto-hide (hides when clicking the system menu bar or elsewhere).

The main difference is that the native ContextMenu window is actually a NSMenu, while in JavaFX we use NSPanel for all popups, and we install event handlers to treat it as auto-hide or non-auto-hide.

With this PR as is, the non-auto-hide popups should be closed when clicking over the system menu bar, but now I see that PopupWindowPeerListener::closing overrides WindowPeerListener::closing with an empty implementation, and WINDOW_CLOSE_REQUEST is not fired at all...

So my call to jWindowNotifyClose in this case is wrong (it doesn't do anything).

And while the non-auto-hide popup won't close (okay), the click on the system menu bar event is consumed and there is no way to show it while the popup is showing (wrong).

I'll rework this.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@beldenfox It should be fixed now.

@kevinrushforth

Copy link
Copy Markdown
Member

/reviewers 2

@openjdk

openjdk Bot commented Apr 3, 2026

Copy link
Copy Markdown

@kevinrushforth
The total number of required reviews for this PR (including the jcheck configuration and the last /reviewers command) is now set to 2 (with at least 1 Reviewer, 1 Author).

@kevinrushforth kevinrushforth self-requested a review April 3, 2026 21:37
Comment thread modules/javafx.graphics/src/main/native-glass/mac/GlassMenu.m
// If this popup is not visible or is a non-auto-hide popup, return early, without cancelling the menu event
// or hiding the popup.
// Note that only auto-hide popups have an active focus grab.
if (![self->nsWindow isVisible] || ![GlassWindow _hasGrab]) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure you need the isVisible check though there's no harm in leaving it in. As far as I know there should never be an invisible popup; when JavaFX hides the popup the NSWindow is destroyed, not hidden.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we remove the notification (as discussed in the other comment), this code would be removed.

If we keep it, the visible check is indeed not needed, since there can be only one auto-hide popup with an active grab (and it will be visible), which is the one that should cancel tracking and reset the grab.

Note that I had only the visible check before I added the grab one.

@jperedadnr

Copy link
Copy Markdown
Collaborator Author

/template append

@openjdk

openjdk Bot commented Apr 10, 2026

Copy link
Copy Markdown

@jperedadnr The pull request template has been appended to the pull request body

@openjdk openjdk Bot added rfr Ready for review and removed rfr Ready for review labels Apr 10, 2026

@beldenfox beldenfox left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM and my manual testing all passed.

@bridgekeeper

bridgekeeper Bot commented May 14, 2026

Copy link
Copy Markdown

@jperedadnr This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply issue a /touch or /keepalive command to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

@jperedadnr

Copy link
Copy Markdown
Collaborator Author

/keepalive

@openjdk

openjdk Bot commented May 14, 2026

Copy link
Copy Markdown

@jperedadnr The pull request is being re-evaluated and the inactivity timeout has been reset.

@bridgekeeper

bridgekeeper Bot commented Jun 11, 2026

Copy link
Copy Markdown

@jperedadnr This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply issue a /touch or /keepalive command to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration!

@jperedadnr

Copy link
Copy Markdown
Collaborator Author

/keepalive

@openjdk

openjdk Bot commented Jun 12, 2026

Copy link
Copy Markdown

@jperedadnr The pull request is being re-evaluated and the inactivity timeout has been reset.

@arapte arapte left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sanity testing looks good to me. Tested several scenarios with ChoiceBox, ComboBox, DatePicker, ColorPicker
Could you please add a automated headful system test.

@jperedadnr

Copy link
Copy Markdown
Collaborator Author

@arapte I've added a system test, with a couple of tests: one with auto-hide popups, that fails before this PR and passes after it, and one with non-auto-hide popups that passes before and after this PR (so behaviour doesn't change).

@beldenfox beldenfox left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New test fails in master branch and succeeds in this PR. LGTM.

@arapte arapte left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@openjdk openjdk Bot added the ready Ready to be integrated label Jun 25, 2026
@jperedadnr

Copy link
Copy Markdown
Collaborator Author

/integrate

@openjdk

openjdk Bot commented Jun 25, 2026

Copy link
Copy Markdown

Going to push as commit e84b145.
Since your change was applied there have been 79 commits pushed to the master branch:

Your commit was automatically rebased without conflicts.

@openjdk openjdk Bot added the integrated Pull request has been integrated label Jun 25, 2026
@openjdk openjdk Bot closed this Jun 25, 2026
@openjdk openjdk Bot removed ready Ready to be integrated rfr Ready for review labels Jun 25, 2026
@openjdk

openjdk Bot commented Jun 25, 2026

Copy link
Copy Markdown

@jperedadnr Pushed as commit e84b145.

💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

integrated Pull request has been integrated

Development

Successfully merging this pull request may close these issues.

5 participants