Proposing an API for replacing the application menu on macOS
Martin Fox
martinfox656 at gmail.com
Thu Sep 4 21:04:54 UTC 2025
I see your point. While working on this PR I noticed how much of the menu machinery lives in javafx.controls but doesn’t need to. Even the classes for building a menu could in theory live in javafx.graphics instead. Those classes don’t build controls, they build a menu model that’s used to drive controls. And the logic in MenuBarSkin that connects these models to the Toolkit doesn’t have much to do with the rest of the skin code. So I can imagine shuffling things around to get a menu API and system menu support into javafx.graphics.
I’m not convinced it would be worth the effort. In the end clients would still be building their menus using the same classes. The only API difference would be that the property that tracks the list of common system menus would be on, say, Application instead of MenuBar. I agree that’s the correct place but it would take a lot of API churn to get it there.
There’s another way to support third-party toolkits and that’s to get out of the way. The JavaFX application menu has some pretty severe limitations (it can’t be localized and Quit doesn’t work correctly for many apps) so clients have had to turn to third-party menu toolkits like NSMenuFX. That toolkit implements system menu support entirely outside of JavaFX using JNA. We could consider supporting this sort of toolkit by providing an API that explicitly disables the JavaFX system menu bar integration. There would be one remaining point of contact: glass would need to continue passing keyDown events to NSApp.mainMenu using performKeyEquivalent. This is not a big ask since glass has always done this and I see no reason why it shouldn’t continue doing so.
> On Sep 2, 2025, at 9:30 AM, Michael Strauß <michaelstrau2 at gmail.com> wrote:
>
> This seems like a useful feature, but I have some comments on the
> proposed implementation.
>
> JavaFX purposefully differentiates between the javafx.graphics and
> javafx.controls module. The javafx.graphics module is the core API,
> it's what users can't recreate themselves. These are not only JavaFX
> primitives like the scene graph, but also platform bindings.
>
> The javafx.controls module, on the other hand, is _one_ implementation
> of a controls toolkit. Third-party developers should be able, in
> theory, to create their own controls toolkit with the APIs provided by
> javafx.graphics. Even if this is not actually done in practice, it is
> architecturally unsound to have javafx.graphics depend on
> javafx.controls, or to have controls interact with graphics in ways
> which can't be recreated by third-party developers.
>
> System menu bars are one example of where javafx.controls is
> privileged, and your proposal would further cement this special
> status. What I think we should do instead is the following:
>
> 1. Provide a core menu API in javafx.graphics
> 2. Have the menus in javafx.controls implement this core API
>
> (Note that there already exists something resembling a core API for menus.)
>
> This not only provides a well-defined API, but also allows us to take
> a new look at the implementation of an application menu. If the
> application menu is associated with the application instance, then
> maybe the Application class would be a more natural home for the app
> menu API instead of a static property on the MenuBar control.
>
>
>
> On Tue, Sep 2, 2025 at 5:34 PM Martin Fox <martinfox656 at gmail.com> wrote:
>>
>> I’ve submitted a draft PR (#1881) with an API that allows a JavaFX developer to replace the application menu on macOS. This is the first menu in the system menu bar, the one that is titled with the application’s name and sits next to the Apple menu. Currently JavaFX builds this menu internally and it’s not customizable in any way (it can’t even be localized). This menu used to require special handling at the OS level but those days are long gone so there’s no technical reason a developer can’t just replace it wholesale.
>>
>> The implementation is more straightforward than the documentation. JavaFX has never documented the presence of this menu and it exhibits some unique behavior. The application menu is always present even for JavaFX applications that don’t use the system menu bar or MenuBars in general. And unlike other JavaFX menus the application menu is accessible when all windows are iconified. The application menu lives in a separate space from the per-window menus and we now need to document that.
>>
>> The new API allows a developer to replace the application menu with a list of menus which I call the common menus. Like the current application menu the common menus are always present. Any menus provided by a MenuBar with setUseSystemMenu set to true will appear alongside the common menus. In theory a JavaFX developer could go full Mac-like and install a single set of common menus at application launch and forego per-window menus altogether. Or they could just replace the application menu and continue using per-window MenuBar’s in keeping with the JavaFX idiom.
>>
>> The application menu contains some items which require platform support (Hide, Hide Others, and Show All) and I wasn’t sure where to put those calls. I’m still not sure. I welcome feedback on that and any other part of this proposed API.
More information about the openjfx-dev
mailing list