Flutter Engine
The Flutter Engine
Instance Methods | Class Methods | List of all members
FlutterMenuPlugin Class Reference

#import <FlutterMenuPlugin.h>

Inheritance diagram for FlutterMenuPlugin:
<FlutterPlugin> <FlutterApplicationLifeCycleDelegate> <FlutterAppLifecycleDelegate>

Instance Methods

(instancetype) - initWithChannel: [implementation]
 
(void) - replaceAppName: [implementation]
 
(NSMenuItem *) - findProvidedMenuItem:ofType: [implementation]
 
(NSMenuItem *) - createPlatformProvidedMenu: [implementation]
 
(NSMenuItem *) - menuItemFromFlutterRepresentation: [implementation]
 
(void) - flutterMenuItemSelected: [implementation]
 
(void) - handleMethodCall:result: [implementation]
 
(void) - setMenus: [implementation]
 
- Instance Methods inherited from <FlutterPlugin>
(void) - handleMethodCall:result:
 
(void) - detachFromEngineForRegistrar:
 
(void) - handleMethodCall:result:
 
- Instance Methods inherited from <FlutterApplicationLifeCycleDelegate>
(BOOL- application:didFinishLaunchingWithOptions:
 
(BOOL- application:willFinishLaunchingWithOptions:
 
(void) - applicationDidBecomeActive:
 
(void) - applicationWillResignActive:
 
(void) - applicationDidEnterBackground:
 
(void) - applicationWillEnterForeground:
 
(void) - applicationWillTerminate:
 
(void) - application:didRegisterUserNotificationSettings:
 
(void) - application:didRegisterForRemoteNotificationsWithDeviceToken:
 
(void) - application:didFailToRegisterForRemoteNotificationsWithError:
 
(BOOL- application:didReceiveRemoteNotification:fetchCompletionHandler:
 
(void) - application:didReceiveLocalNotification:
 
(BOOL- application:openURL:options:
 
(BOOL- application:handleOpenURL:
 
(BOOL- application:openURL:sourceApplication:annotation:
 
(BOOL- application:performActionForShortcutItem:completionHandler:
 
(BOOL- application:handleEventsForBackgroundURLSession:completionHandler:
 
(BOOL- application:performFetchWithCompletionHandler:
 
(BOOL- application:continueUserActivity:restorationHandler:
 
- Instance Methods inherited from <FlutterAppLifecycleDelegate>
(void) - handleWillFinishLaunching:
 
(void) - handleDidFinishLaunching:
 
(void) - handleWillBecomeActive:
 
(void) - handleDidBecomeActive:
 
(void) - handleWillResignActive:
 
(void) - handleDidResignActive:
 
(void) - handleWillHide:
 
(void) - handleDidHide:
 
(void) - handleWillUnhide:
 
(void) - handleDidUnhide:
 
(void) - handleDidChangeScreenParameters:
 
(void) - handleDidChangeOcclusionState:
 
(BOOL- handleOpenURLs:
 
(void) - handleWillTerminate:
 

Class Methods

(void) + registerWithRegistrar:
 
- Class Methods inherited from <FlutterPlugin>
(void) + registerWithRegistrar:
 
(void) + setPluginRegistrantCallback:
 
(void) + registerWithRegistrar:
 

Detailed Description

A plugin to configure and control the native system menu.

Responsible for bridging the native macOS menu system with the Flutter framework's PlatformMenuBar class, via method channels.

Definition at line 20 of file FlutterMenuPlugin.h.

Method Documentation

◆ createPlatformProvidedMenu:

- (NSMenuItem *) createPlatformProvidedMenu: (flutter::PlatformProvidedMenu type
implementation

Definition at line 229 of file FlutterMenuPlugin.mm.

285 const std::map<flutter::PlatformProvidedMenu, SEL> providedMenus = GetMacOSProvidedMenus();
286 auto found_type = providedMenus.find(type);
287 if (found_type == providedMenus.end()) {
288 return nil;
289 }
290 SEL selectorTarget = found_type->second;
291 // Since it doesn't have a definitive selector, the Services submenu is
292 // assumed to be the first item with a submenu action in the first menu item
293 // of the default menu set. We can't just get the title to check, since that
294 // is localized, and the contents of the menu aren't fixed (or even available).
296 ? [_platformProvidedItems[0] submenu]
297 : nil;
298 NSMenuItem* found = [self findProvidedMenuItem:startingMenu ofType:selectorTarget];
299 // Return a copy because the original menu item might not have been removed
300 // from the main menu yet, and AppKit doesn't like menu items that exist in
301 // more than one menu at a time.
302 return [found copy];
303}
static const std::map< flutter::PlatformProvidedMenu, SEL > GetMacOSProvidedMenus()
GLenum type

◆ findProvidedMenuItem:ofType:

- (NSMenuItem *) findProvidedMenuItem: (NSMenu*)  menu
ofType: (SEL)  selector 
implementation

Definition at line 229 of file FlutterMenuPlugin.mm.

268 :(NSMenu*)menu ofType:(SEL)selector {
269 const NSArray<NSMenuItem*>* items = menu ? menu.itemArray : _platformProvidedItems;
270 for (NSMenuItem* item in items) {
271 if ([item action] == selector) {
272 return item;
273 }
274 if ([[item submenu] numberOfItems] > 0) {
275 NSMenuItem* foundChild = [self findProvidedMenuItem:[item submenu] ofType:selector];
276 if (foundChild) {
277 return foundChild;
278 }
279 }
280 }
281 return nil;
282}
NSArray< NSMenuItem * > * _platformProvidedItems

◆ flutterMenuItemSelected:

- (void) flutterMenuItemSelected: (id sender
implementation

Definition at line 229 of file FlutterMenuPlugin.mm.

375 :(id)sender {
376 NSMenuItem* item = sender;
377 [_channel invokeMethod:kMenuSelectedCallbackMethod arguments:@(item.tag)];
378}
const uintptr_t id

◆ handleMethodCall:result:

- (void) handleMethodCall: (FlutterMethodCall *)  call
result: (FlutterResult result 
implementation

Called if this plugin has been registered to receive FlutterMethodCalls.

Parameters
callThe method call command object.
resultA callback for submitting the result of the call.

Reimplemented from <FlutterPlugin>.

Definition at line 229 of file FlutterMenuPlugin.mm.

381 if ([call.method isEqualToString:kIsPluginAvailableMethod]) {
382 result(@YES);
383 } else if ([call.method isEqualToString:kMenuSetMenusMethod]) {
384 NSDictionary* menus = call.arguments;
385 [self setMenus:menus];
386 result(nil);
387 } else {
389 }
390}
void(^ FlutterResult)(id _Nullable result)
FLUTTER_DARWIN_EXPORT NSObject const * FlutterMethodNotImplemented
static NSString *const kIsPluginAvailableMethod
static NSString *const kMenuSetMenusMethod
GAsyncResult * result
def call(args)
Definition: dom.py:159

◆ initWithChannel:

- (instancetype) initWithChannel: (FlutterMethodChannel*)  channel
implementation

Definition at line 229 of file FlutterMenuPlugin.mm.

234 :(FlutterMethodChannel*)channel {
235 self = [super init];
236 if (self) {
237 _channel = channel;
239 _menuDelegates = [[NSMutableArray alloc] init];
240
241 // Make a copy of all the platform provided menus for later use.
242 _platformProvidedItems = [[NSApp.mainMenu itemArray] mutableCopy];
243
244 // As copied, these platform provided menu items don't yet have the APP_NAME
245 // string replaced in them, so this rectifies that.
246 [self replaceAppName:_platformProvidedItems];
247 }
248 return self;
249}
NSMutableArray< FlutterMenuDelegate * > * _menuDelegates
FlutterMethodChannel * _channel

◆ menuItemFromFlutterRepresentation:

- (NSMenuItem *) menuItemFromFlutterRepresentation: (NSDictionary*)  representation
implementation

Definition at line 229 of file FlutterMenuPlugin.mm.

305 :(NSDictionary*)representation {
306 if ([(NSNumber*)([representation valueForKey:kDividerKey]) intValue] == YES) {
307 return [NSMenuItem separatorItem];
308 }
309 NSNumber* platformProvidedMenuId = representation[kPlatformProvidedMenuKey];
310 NSString* keyEquivalent = @"";
311
312 if (platformProvidedMenuId) {
313 return [self
314 createPlatformProvidedMenu:(flutter::PlatformProvidedMenu)platformProvidedMenuId.intValue];
315 } else {
316 if (representation[kShortcutCharacterKey]) {
317 keyEquivalent = representation[kShortcutCharacterKey];
318 } else {
319 NSNumber* triggerKeyId = representation[kShortcutTriggerKey];
320 const NSDictionary<NSNumber*, NSNumber*>* specialKeys = GetMacOsSpecialKeys();
321 NSNumber* trigger = specialKeys[triggerKeyId];
322 if (trigger) {
323 keyEquivalent = [NSString stringWithFormat:@"%C", [trigger unsignedShortValue]];
324 } else {
325 if (([triggerKeyId unsignedLongLongValue] & kFlutterKeyIdPlaneMask) ==
327 keyEquivalent = [[NSString
328 stringWithFormat:@"%C", (unichar)([triggerKeyId unsignedLongLongValue] &
329 kFlutterKeyIdValueMask)] lowercaseString];
330 }
331 }
332 }
333 }
334
335 NSNumber* identifier = representation[kIdKey];
336 SEL action = (identifier ? @selector(flutterMenuItemSelected:) : NULL);
337 NSString* appName = [NSRunningApplication currentApplication].localizedName;
338 NSString* title = [representation[kLabelKey] stringByReplacingOccurrencesOfString:kAppName
339 withString:appName];
340 NSMenuItem* item = [[NSMenuItem alloc] initWithTitle:title
341 action:action
342 keyEquivalent:keyEquivalent];
343 if ([keyEquivalent length] > 0) {
344 item.keyEquivalentModifierMask =
346 }
347 if (identifier) {
348 item.tag = identifier.longLongValue;
349 item.target = self;
350 }
351 NSNumber* enabled = representation[kEnabledKey];
352 if (enabled) {
353 item.enabled = enabled.boolValue;
354 }
355
356 NSArray* children = representation[kChildrenKey];
357 if (children && children.count > 0) {
358 NSMenu* submenu = [[NSMenu alloc] initWithTitle:title];
359 FlutterMenuDelegate* delegate = [[FlutterMenuDelegate alloc] initWithIdentifier:item.tag
360 channel:_channel];
361 [_menuDelegates addObject:delegate];
362 submenu.delegate = delegate;
363 submenu.autoenablesItems = NO;
364 for (NSDictionary* child in children) {
365 NSMenuItem* newItem = [self menuItemFromFlutterRepresentation:child];
366 if (newItem) {
367 [submenu addItem:newItem];
368 }
369 }
370 item.submenu = submenu;
371 }
372 return item;
373}
constexpr uint64_t kFlutterKeyIdPlaneMask
static NSEventModifierFlags KeyEquivalentModifierMaskForModifiers(NSNumber *modifiers)
static NSString *const kShortcutCharacterKey
constexpr uint64_t kFlutterKeyIdUnicodePlane
static NSString *const kShortcutModifiersKey
static NSDictionary< NSNumber *, NSNumber * > * GetMacOsSpecialKeys()
static SkString identifier(const FontFamilyDesc &family, const FontDesc &font)
size_t length

◆ registerWithRegistrar:

+ (void) registerWithRegistrar: (nonnull id<FlutterPluginRegistrar>)  registrar

Registers a FlutterMenuPlugin with the given registrar.

Definition at line 229 of file FlutterMenuPlugin.mm.

412 :(nonnull id<FlutterPluginRegistrar>)registrar {
414 binaryMessenger:registrar.messenger];
415 FlutterMenuPlugin* instance = [[FlutterMenuPlugin alloc] initWithChannel:channel];
416 [registrar addMethodCallDelegate:instance channel:channel];
417}
VkInstance instance
Definition: main.cc:48
instancetype methodChannelWithName:binaryMessenger:(NSString *name,[binaryMessenger] NSObject< FlutterBinaryMessenger > *messenger)

◆ replaceAppName:

- (void) replaceAppName: (NSArray<NSMenuItem*>*)  items
implementation

Iterates through the given menu hierarchy, and replaces "APP_NAME" with the localized running application name.

Definition at line 229 of file FlutterMenuPlugin.mm.

255 :(NSArray<NSMenuItem*>*)items {
256 NSString* appName = [NSRunningApplication currentApplication].localizedName;
257 for (NSMenuItem* item in items) {
258 if ([[item title] containsString:kAppName]) {
259 [item setTitle:[[item title] stringByReplacingOccurrencesOfString:kAppName
260 withString:appName]];
261 }
262 if ([item hasSubmenu]) {
263 [self replaceAppName:[[item submenu] itemArray]];
264 }
265 }
266}
static NSString *const kAppName

◆ setMenus:

- (void) setMenus: (NSDictionary*)  representation
implementation

Definition at line 229 of file FlutterMenuPlugin.mm.

392 :(NSDictionary*)representation {
393 [_menuDelegates removeAllObjects];
394 NSMenu* newMenu = [[NSMenu alloc] init];
395 // There's currently only one window, named "0", but there could be other
396 // eventually, with different menu configurations.
397 for (NSDictionary* item in representation[@"0"]) {
398 NSMenuItem* menuItem = [self menuItemFromFlutterRepresentation:item];
399 menuItem.representedObject = self;
400 NSNumber* identifier = item[kIdKey];
401 FlutterMenuDelegate* delegate =
402 [[FlutterMenuDelegate alloc] initWithIdentifier:identifier.longLongValue channel:_channel];
403 [_menuDelegates addObject:delegate];
404 [menuItem submenu].delegate = delegate;
405 [newMenu addItem:menuItem];
406 }
407 NSApp.mainMenu = newMenu;
408}

The documentation for this class was generated from the following files: