Conversation
Items in the native main menu bar stopped reflecting their current enabled state: after a MenuBarModel::menuItemsChanged() call, opening a menu showed whatever state the items had at that moment, and later changes to the command targets were never picked up. Any app that uses MenuBarModel::setMacMainMenu() together with setApplicationCommandManagerToWatch() hits this as soon as keyboard focus moves, because ApplicationCommandManager calls commandStatusChanged() on every focus change and that ends in menuItemsChanged(). A command whose enabled state depends on something that changes without moving focus, such as a selection made with the keyboard, then shows the stale state until the next focus change. The menus created when the bar is first populated get the JuceMenuCallbackClass delegate, whose menuNeedsUpdate: rebuilds the menu from the model every time it opens. The replacement menus that menuBarItemsChanged() builds via updateTopLevelMenu() were created without that delegate, so they were never refreshed on open. Create the replacement through createMenu() with the delegate attached, as the initial menu is.
emezeske
marked this pull request as ready for review
September 11, 2026 21:39
Collaborator
|
This pull request has been mentioned on The JUCE Forum. There might be relevant details there: |
Member
|
Fixed in 9336be2 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On macOS, items in the native main menu bar stop reflecting their enabled state after the first MenuBarModel::menuItemsChanged() call: opening a menu shows whatever state the commands had at that moment, and later changes are not picked up until the next call. Any app that uses setMacMainMenu() together with setApplicationCommandManagerToWatch() hits this as soon as keyboard focus moves, because ApplicationCommandManager calls commandStatusChanged() on every focus change and that ends in menuItemsChanged().
To reproduce, register a command whose getCommandInfo() enabled state depends on something that can change without moving keyboard focus, such as a selection made with a keyboard shortcut, and put it in a menu shown through setMacMainMenu() with setApplicationCommandManagerToWatch() in effect. Move focus once so the bar is rebuilt, then change that state and open the menu. The item still shows the old state, and keeps showing it until focus moves again.
The menus built when the bar is first populated get the JuceMenuCallbackClass delegate, whose menuNeedsUpdate: rebuilds the menu from the model each time it opens. The replacements that menuBarItemsChanged() creates through updateTopLevelMenu() were allocated without that delegate, so they were never refreshed on open. This change creates them through createMenu() with the delegate attached, as the initial menus are.
Tested on macOS 26 with a standalone app: reading the menu's items through Accessibility before and after a keyboard-driven selection change now shows the enabled states following the model, where before the change they stayed at the values from the last focus change.