blob: bb9310145a9c3559dcdedf7fe6f8fcc9aa6e8b73 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ui/base/cocoa/nsmenu_additions.h"
#include "base/check.h"
#include "base/mac/scoped_nsobject.h"
#import "ui/base/cocoa/nsmenuitem_additions.h"
namespace {
typedef void (^PreSearchBlock)(void);
PreSearchBlock g_pre_search_block;
NSMenuItem* MenuItemForKeyEquivalentEventInMenu(NSEvent* event, NSMenu* menu) {
NSMenuItem* result = nil;
for (NSMenuItem* item in [menu itemArray]) {
NSMenu* submenu = [item submenu];
if (submenu) {
if (submenu != [NSApp servicesMenu])
result = MenuItemForKeyEquivalentEventInMenu(event, submenu);
} else if ([item cr_firesForKeyEquivalentEvent:event]) {
result = item;
}
if (result)
break;
}
return result;
}
// Searches |menu| and its submenus for a NSMenuItem with |tag|.
// Returns the menu item or nil if no menu item matches.
NSMenuItem* MenuItemWithTagInMenu(int tag, NSMenu* menu) {
for (NSMenuItem* item in [menu itemArray]) {
if ([item tag] == tag)
return item;
if ([item hasSubmenu]) {
NSMenuItem* the_item = MenuItemWithTagInMenu(tag, [item submenu]);
if (the_item != nil)
return the_item;
}
}
return nil;
}
NSMenuItem* MenuItemWithTag(int tag) {
NSMenu* mainMenu = [[NSApplication sharedApplication] mainMenu];
// Validate menu items before searching.
[mainMenu update];
return MenuItemWithTagInMenu(tag, mainMenu);
}
} // namespace
@implementation NSMenu (ChromeAdditions)
+ (void)cr_setMenuItemForKeyEquivalentEventPreSearchBlock:
(void (^)(void))block {
if (block != nil)
CHECK(g_pre_search_block == nil);
g_pre_search_block = block;
}
- (NSMenuItem*)cr_menuItemForKeyEquivalentEvent:(NSEvent*)event {
if ([event type] != NSEventTypeKeyDown)
return nil;
if (g_pre_search_block) {
g_pre_search_block();
}
// Validate menu items before searching.
[self update];
return MenuItemForKeyEquivalentEventInMenu(event, self);
}
+ (BOOL)flashMenuForChromeCommand:(int)chromeCommand {
NSMenuItem* menuItem = MenuItemWithTag(chromeCommand);
if (menuItem == nil)
return NO;
// Swap out the menu item's existing target/action for a fake pair,
// so that we can flash the menu item without executing anything.
id origTarget = [menuItem target];
SEL origAction = [menuItem action];
[menuItem setTarget:self];
[menuItem setAction:@selector(cr_executeDummyCommand:)];
// -performActionForItemAtIndex: is documented as triggering highlighting in
// the menu bar as well as sending out appropriate accessibility notifications
// indicating the item was selected.
NSMenu* owningMenu = [menuItem menu];
[owningMenu performActionForItemAtIndex:[owningMenu indexOfItem:menuItem]];
// Restore.
[menuItem setTarget:origTarget];
[menuItem setAction:origAction];
return YES;
}
+ (void)cr_executeDummyCommand:(id)sender {
}
@end