fix: refresh menu item state on key equivalent dispatch (#49875)

This commit is contained in:
Shelley Vohr
2026-02-20 17:35:44 +01:00
committed by GitHub
parent ea89ba5b8d
commit 3e58c6cb3a

View File

@@ -258,7 +258,7 @@ NSArray* ConvertSharingItemToNS(const SharingItem& item) {
// Empties the source menu items to the destination.
- (void)moveMenuItems:(NSMenu*)source to:(NSMenu*)destination {
const NSInteger count = [source numberOfItems];
const NSInteger count = source.numberOfItems;
for (NSInteger index = 0; index < count; index++) {
NSMenuItem* removedItem = [source itemAtIndex:0];
[source removeItemAtIndex:0];
@@ -269,25 +269,25 @@ NSArray* ConvertSharingItemToNS(const SharingItem& item) {
// Replaces the item's submenu instance with the singleton recent documents
// menu. Previously replaced menu items will be recovered.
- (void)replaceSubmenuShowingRecentDocuments:(NSMenuItem*)item {
NSMenu* recentDocumentsMenu = [recentDocumentsMenuItem_ submenu];
NSMenu* recentDocumentsMenu = recentDocumentsMenuItem_.submenu;
// Remove menu items in recent documents back to swap menu
[self moveMenuItems:recentDocumentsMenu to:recentDocumentsMenuSwap_];
// Swap back the submenu
[recentDocumentsMenuItem_ setSubmenu:recentDocumentsMenuSwap_];
recentDocumentsMenuItem_.submenu = recentDocumentsMenuSwap_;
// Retain the item's submenu for a future recovery
recentDocumentsMenuSwap_ = [item submenu];
recentDocumentsMenuSwap_ = item.submenu;
// Repopulate with items from the submenu to be replaced
[self moveMenuItems:recentDocumentsMenuSwap_ to:recentDocumentsMenu];
// Update the submenu's title
[recentDocumentsMenu setTitle:[recentDocumentsMenuSwap_ title]];
recentDocumentsMenu.title = recentDocumentsMenuSwap_.title;
// Replace submenu
[item setSubmenu:recentDocumentsMenu];
item.submenu = recentDocumentsMenu;
DCHECK_EQ([item action], @selector(submenuAction:));
DCHECK_EQ([item target], recentDocumentsMenu);
DCHECK_EQ(item.action, @selector(submenuAction:));
DCHECK_EQ(item.target, recentDocumentsMenu);
// Remember the new menu item that carries the recent documents menu
recentDocumentsMenuItem_ = item;
@@ -303,7 +303,7 @@ NSArray* ConvertSharingItemToNS(const SharingItem& item) {
NSArray* services = [NSSharingService sharingServicesForItems:items];
for (NSSharingService* service in services)
[menu addItem:[self menuItemForService:service withItems:items]];
[menu setDelegate:self];
menu.delegate = self;
return menu;
}
@@ -313,9 +313,9 @@ NSArray* ConvertSharingItemToNS(const SharingItem& item) {
NSMenuItem* item = [[NSMenuItem alloc] initWithTitle:service.menuItemTitle
action:@selector(performShare:)
keyEquivalent:@""];
[item setTarget:self];
[item setImage:service.image];
[item setRepresentedObject:@{@"service" : service, @"items" : items}];
item.target = self;
item.image = service.image;
item.representedObject = @{@"service" : service, @"items" : items};
return item;
}
@@ -398,7 +398,7 @@ NSArray* ConvertSharingItemToNS(const SharingItem& item) {
submenu.delegate = self;
// Set submenu's role.
if ((role == u"window" || role == u"windowmenu") && [submenu numberOfItems])
if ((role == u"window" || role == u"windowmenu") && submenu.numberOfItems)
[NSApp setWindowsMenu:submenu];
else if (role == u"help")
[NSApp setHelpMenu:submenu];
@@ -463,6 +463,14 @@ NSArray* ConvertSharingItemToNS(const SharingItem& item) {
return item;
}
// Called by AppKit before displaying a menu and when a key equivalent is
// pressed. This ensures menu item states (enabled, checked, hidden) are
// refreshed from the model even when the menu is closed, which is necessary
// since we set autoenablesItems = NO.
- (void)menuNeedsUpdate:(NSMenu*)menu {
[self refreshMenuTree:menu];
}
- (void)applyStateToMenuItem:(NSMenuItem*)item {
id represented = item.representedObject;
if (!represented)
@@ -487,7 +495,7 @@ NSArray* ConvertSharingItemToNS(const SharingItem& item) {
// When the menu is closed, we need to allow shortcuts to be triggered even
// if the menu item is disabled. So we only disable the menu item when the
// menu is open. This matches behavior of |validateUserInterfaceItem|.
item.enabled = model->IsEnabledAt(index) || !isMenuOpen_;
item.enabled = model->IsEnabledAt(index);
item.hidden = !model->IsVisibleAt(index);
item.state = model->IsItemCheckedAt(index) ? NSControlStateValueOn
: NSControlStateValueOff;
@@ -566,7 +574,6 @@ NSArray* ConvertSharingItemToNS(const SharingItem& item) {
[menu removeItem:item];
}
[self refreshMenuTree:menu];
if (model_)
model_->MenuWillShow();
}
@@ -577,7 +584,6 @@ NSArray* ConvertSharingItemToNS(const SharingItem& item) {
return;
isMenuOpen_ = NO;
[self refreshMenuTree:menu];
// There are two scenarios where we should emit menu-did-close:
// 1. It's a popup and the top level menu is closed.