| 
									
										
										
										
											2014-10-31 11:17:05 -07:00
										 |  |  | // Copyright (c) 2013 GitHub, Inc. | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
					
						
							| 
									
										
										
										
											2014-04-25 17:49:37 +08:00
										 |  |  | // Use of this source code is governed by the MIT license that can be | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  | // found in the LICENSE file. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-16 08:30:26 +08:00
										 |  |  | #import "atom/browser/ui/cocoa/atom_menu_controller.h" | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-10 12:39:05 +08:00
										 |  |  | #include "atom/browser/ui/atom_menu_model.h" | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  | #include "base/logging.h" | 
					
						
							|  |  |  | #include "base/strings/sys_string_conversions.h" | 
					
						
							| 
									
										
										
										
											2015-09-01 19:48:11 +08:00
										 |  |  | #include "base/strings/utf_string_conversions.h" | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  | #include "ui/base/accelerators/accelerator.h" | 
					
						
							|  |  |  | #include "ui/base/accelerators/platform_accelerator_cocoa.h" | 
					
						
							|  |  |  | #include "ui/base/l10n/l10n_util_mac.h" | 
					
						
							| 
									
										
										
										
											2017-02-22 11:47:58 -08:00
										 |  |  | #include "content/public/browser/browser_thread.h" | 
					
						
							| 
									
										
										
										
											2015-07-29 12:01:27 +08:00
										 |  |  | #include "ui/events/cocoa/cocoa_event_utils.h" | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  | #include "ui/gfx/image/image.h" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-22 11:47:58 -08:00
										 |  |  | using content::BrowserThread; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-01 19:48:11 +08:00
										 |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct Role { | 
					
						
							|  |  |  |   SEL selector; | 
					
						
							|  |  |  |   const char* role; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | Role kRolesMap[] = { | 
					
						
							|  |  |  |   { @selector(orderFrontStandardAboutPanel:), "about" }, | 
					
						
							|  |  |  |   { @selector(hide:), "hide" }, | 
					
						
							|  |  |  |   { @selector(hideOtherApplications:), "hideothers" }, | 
					
						
							|  |  |  |   { @selector(unhideAllApplications:), "unhide" }, | 
					
						
							|  |  |  |   { @selector(arrangeInFront:), "front" }, | 
					
						
							|  |  |  |   { @selector(undo:), "undo" }, | 
					
						
							|  |  |  |   { @selector(redo:), "redo" }, | 
					
						
							|  |  |  |   { @selector(cut:), "cut" }, | 
					
						
							|  |  |  |   { @selector(copy:), "copy" }, | 
					
						
							|  |  |  |   { @selector(paste:), "paste" }, | 
					
						
							| 
									
										
										
										
											2016-03-07 15:53:09 -08:00
										 |  |  |   { @selector(delete:), "delete" }, | 
					
						
							| 
									
										
										
										
											2016-06-04 11:23:35 -04:00
										 |  |  |   { @selector(pasteAndMatchStyle:), "pasteandmatchstyle" }, | 
					
						
							| 
									
										
										
										
											2015-09-01 19:48:11 +08:00
										 |  |  |   { @selector(selectAll:), "selectall" }, | 
					
						
							| 
									
										
										
										
											2016-08-08 00:02:32 +02:00
										 |  |  |   { @selector(startSpeaking:), "startspeaking" }, | 
					
						
							|  |  |  |   { @selector(stopSpeaking:), "stopspeaking" }, | 
					
						
							| 
									
										
										
										
											2015-09-01 19:48:11 +08:00
										 |  |  |   { @selector(performMiniaturize:), "minimize" }, | 
					
						
							|  |  |  |   { @selector(performClose:), "close" }, | 
					
						
							| 
									
										
										
										
											2016-03-07 16:01:46 -08:00
										 |  |  |   { @selector(performZoom:), "zoom" }, | 
					
						
							| 
									
										
										
										
											2016-06-20 17:03:59 -07:00
										 |  |  |   { @selector(terminate:), "quit" }, | 
					
						
							| 
									
										
										
										
											2016-06-21 09:34:12 -07:00
										 |  |  |   { @selector(toggleFullScreen:), "togglefullscreen" }, | 
					
						
							| 
									
										
										
										
											2017-08-15 11:27:25 -04:00
										 |  |  |   { @selector(toggleTabBar:), "toggletabbar" }, | 
					
						
							|  |  |  |   { @selector(selectNextTab:), "selectnexttab" }, | 
					
						
							|  |  |  |   { @selector(selectPreviousTab:), "selectprevioustab" }, | 
					
						
							|  |  |  |   { @selector(mergeAllWindows:), "mergeallwindows" }, | 
					
						
							|  |  |  |   { @selector(moveTabToNewWindow:), "movetabtonewwindow" }, | 
					
						
							| 
									
										
										
										
											2015-09-01 19:48:11 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }  // namespace | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | @implementation AtomMenuController | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @synthesize model = model_; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-02 11:47:40 +09:00
										 |  |  | - (id)initWithModel:(atom::AtomMenuModel*)model useDefaultAccelerator:(BOOL)use { | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  |   if ((self = [super init])) { | 
					
						
							|  |  |  |     model_ = model; | 
					
						
							| 
									
										
										
										
											2016-07-02 11:47:40 +09:00
										 |  |  |     isMenuOpen_ = NO; | 
					
						
							|  |  |  |     useDefaultAccelerator_ = use; | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  |     [self menu]; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return self; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)dealloc { | 
					
						
							|  |  |  |   [menu_ setDelegate:nil]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Close the menu if it is still open. This could happen if a tab gets closed | 
					
						
							|  |  |  |   // while its context menu is still open. | 
					
						
							|  |  |  |   [self cancel]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-18 21:52:52 -08:00
										 |  |  |   model_ = nil; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   [openRecentMenuItem_ release]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  |   [super dealloc]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-16 10:58:02 -08:00
										 |  |  | - (void)setCloseCallback:(const base::Callback<void()>&)callback { | 
					
						
							|  |  |  |   closeCallback = callback; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-02 11:47:40 +09:00
										 |  |  | - (void)populateWithModel:(atom::AtomMenuModel*)model { | 
					
						
							| 
									
										
										
										
											2014-11-16 20:24:29 +08:00
										 |  |  |   if (!menu_) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-18 21:52:52 -08:00
										 |  |  |   // Retain submenu for recent documents | 
					
						
							|  |  |  |   if (!openRecentMenuItem_) { | 
					
						
							|  |  |  |     openRecentMenuItem_ = [[[[NSApp mainMenu] | 
					
						
							|  |  |  |         itemWithTitle:@"Electron"] submenu] itemWithTitle:@"Open Recent"]; | 
					
						
							| 
									
										
										
										
											2017-11-18 22:02:39 -08:00
										 |  |  |     [openRecentMenuItem_ setHidden:NO]; | 
					
						
							| 
									
										
										
										
											2017-11-18 21:52:52 -08:00
										 |  |  |     [openRecentMenuItem_ retain]; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-16 20:24:29 +08:00
										 |  |  |   model_ = model; | 
					
						
							|  |  |  |   [menu_ removeAllItems]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const int count = model->GetItemCount(); | 
					
						
							|  |  |  |   for (int index = 0; index < count; index++) { | 
					
						
							| 
									
										
										
										
											2016-07-02 11:47:40 +09:00
										 |  |  |     if (model->GetTypeAt(index) == atom::AtomMenuModel::TYPE_SEPARATOR) | 
					
						
							| 
									
										
										
										
											2014-11-16 20:24:29 +08:00
										 |  |  |       [self addSeparatorToMenu:menu_ atIndex:index]; | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       [self addItemToMenu:menu_ atIndex:index fromModel:model]; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  | - (void)cancel { | 
					
						
							|  |  |  |   if (isMenuOpen_) { | 
					
						
							|  |  |  |     [menu_ cancelTracking]; | 
					
						
							| 
									
										
										
										
											2017-01-23 17:53:53 +09:00
										 |  |  |     model_->MenuWillClose(); | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  |     isMenuOpen_ = NO; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Creates a NSMenu from the given model. If the model has submenus, this can | 
					
						
							|  |  |  | // be invoked recursively. | 
					
						
							| 
									
										
										
										
											2016-07-02 11:47:40 +09:00
										 |  |  | - (NSMenu*)menuFromModel:(atom::AtomMenuModel*)model { | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  |   NSMenu* menu = [[[NSMenu alloc] initWithTitle:@""] autorelease]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const int count = model->GetItemCount(); | 
					
						
							|  |  |  |   for (int index = 0; index < count; index++) { | 
					
						
							| 
									
										
										
										
											2016-07-02 11:47:40 +09:00
										 |  |  |     if (model->GetTypeAt(index) == atom::AtomMenuModel::TYPE_SEPARATOR) | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  |       [self addSeparatorToMenu:menu atIndex:index]; | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       [self addItemToMenu:menu atIndex:index fromModel:model]; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return menu; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Adds a separator item at the given index. As the separator doesn't need | 
					
						
							|  |  |  | // anything from the model, this method doesn't need the model index as the | 
					
						
							|  |  |  | // other method below does. | 
					
						
							|  |  |  | - (void)addSeparatorToMenu:(NSMenu*)menu | 
					
						
							|  |  |  |                    atIndex:(int)index { | 
					
						
							|  |  |  |   NSMenuItem* separator = [NSMenuItem separatorItem]; | 
					
						
							|  |  |  |   [menu insertItem:separator atIndex:index]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Adds an item or a hierarchical menu to the item at the |index|, | 
					
						
							|  |  |  | // associated with the entry in the model identified by |modelIndex|. | 
					
						
							|  |  |  | - (void)addItemToMenu:(NSMenu*)menu | 
					
						
							|  |  |  |               atIndex:(NSInteger)index | 
					
						
							| 
									
										
										
										
											2016-07-02 11:47:40 +09:00
										 |  |  |             fromModel:(atom::AtomMenuModel*)model { | 
					
						
							| 
									
										
										
										
											2014-06-28 22:33:00 +08:00
										 |  |  |   base::string16 label16 = model->GetLabelAt(index); | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  |   NSString* label = l10n_util::FixUpWindowsStyleLabel(label16); | 
					
						
							| 
									
										
										
										
											2017-11-18 21:52:52 -08:00
										 |  |  |   base::string16 role = model->GetRoleAt(index); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (role == base::ASCIIToUTF16("openrecent")) { | 
					
						
							|  |  |  |     // Special role for recent documents | 
					
						
							|  |  |  |     [[openRecentMenuItem_ menu] removeItem:openRecentMenuItem_]; | 
					
						
							|  |  |  |     [openRecentMenuItem_ setTitle:label]; | 
					
						
							|  |  |  |     [[openRecentMenuItem_ submenu] setTitle:label]; | 
					
						
							|  |  |  |     [menu insertItem:openRecentMenuItem_ atIndex:index]; | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-11 15:48:19 +08:00
										 |  |  |   base::scoped_nsobject<NSMenuItem> item( | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  |       [[NSMenuItem alloc] initWithTitle:label | 
					
						
							|  |  |  |                                  action:@selector(itemSelected:) | 
					
						
							|  |  |  |                           keyEquivalent:@""]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // If the menu item has an icon, set it. | 
					
						
							|  |  |  |   gfx::Image icon; | 
					
						
							|  |  |  |   if (model->GetIconAt(index, &icon) && !icon.IsEmpty()) | 
					
						
							|  |  |  |     [item setImage:icon.ToNSImage()]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-02 11:47:40 +09:00
										 |  |  |   atom::AtomMenuModel::ItemType type = model->GetTypeAt(index); | 
					
						
							|  |  |  |   if (type == atom::AtomMenuModel::TYPE_SUBMENU) { | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  |     // Recursively build a submenu from the sub-model at this index. | 
					
						
							|  |  |  |     [item setTarget:nil]; | 
					
						
							|  |  |  |     [item setAction:nil]; | 
					
						
							| 
									
										
										
										
											2016-07-02 11:47:40 +09:00
										 |  |  |     atom::AtomMenuModel* submenuModel = static_cast<atom::AtomMenuModel*>( | 
					
						
							|  |  |  |         model->GetSubmenuModelAt(index)); | 
					
						
							| 
									
										
										
										
											2015-08-10 12:39:05 +08:00
										 |  |  |     NSMenu* submenu = [self menuFromModel:submenuModel]; | 
					
						
							| 
									
										
										
										
											2013-08-14 22:33:18 +08:00
										 |  |  |     [submenu setTitle:[item title]]; | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  |     [item setSubmenu:submenu]; | 
					
						
							| 
									
										
										
										
											2013-08-14 22:33:18 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-01 19:48:11 +08:00
										 |  |  |     // Set submenu's role. | 
					
						
							| 
									
										
										
										
											2015-12-30 19:36:02 -08:00
										 |  |  |     if (role == base::ASCIIToUTF16("window") && [submenu numberOfItems]) | 
					
						
							| 
									
										
										
										
											2013-08-14 22:33:18 +08:00
										 |  |  |       [NSApp setWindowsMenu:submenu]; | 
					
						
							| 
									
										
										
										
											2015-09-01 19:48:11 +08:00
										 |  |  |     else if (role == base::ASCIIToUTF16("help")) | 
					
						
							| 
									
										
										
										
											2013-10-17 10:15:57 +08:00
										 |  |  |       [NSApp setHelpMenu:submenu]; | 
					
						
							| 
									
										
										
										
											2017-11-18 17:56:37 -08:00
										 |  |  |     else if (role == base::ASCIIToUTF16("services")) | 
					
						
							| 
									
										
										
										
											2014-09-05 13:07:05 +08:00
										 |  |  |       [NSApp setServicesMenu:submenu]; | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  |   } else { | 
					
						
							|  |  |  |     // The MenuModel works on indexes so we can't just set the command id as the | 
					
						
							|  |  |  |     // tag like we do in other menus. Also set the represented object to be | 
					
						
							|  |  |  |     // the model so hierarchical menus check the correct index in the correct | 
					
						
							|  |  |  |     // model. Setting the target to |self| allows this class to participate | 
					
						
							|  |  |  |     // in validation of the menu items. | 
					
						
							|  |  |  |     [item setTag:index]; | 
					
						
							|  |  |  |     NSValue* modelObject = [NSValue valueWithPointer:model]; | 
					
						
							|  |  |  |     [item setRepresentedObject:modelObject];  // Retains |modelObject|. | 
					
						
							|  |  |  |     ui::Accelerator accelerator; | 
					
						
							| 
									
										
										
										
											2016-07-02 11:47:40 +09:00
										 |  |  |     if (model->GetAcceleratorAtWithParams( | 
					
						
							|  |  |  |             index, useDefaultAccelerator_, &accelerator)) { | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  |       const ui::PlatformAcceleratorCocoa* platformAccelerator = | 
					
						
							|  |  |  |           static_cast<const ui::PlatformAcceleratorCocoa*>( | 
					
						
							|  |  |  |               accelerator.platform_accelerator()); | 
					
						
							|  |  |  |       if (platformAccelerator) { | 
					
						
							|  |  |  |         [item setKeyEquivalent:platformAccelerator->characters()]; | 
					
						
							|  |  |  |         [item setKeyEquivalentModifierMask: | 
					
						
							|  |  |  |             platformAccelerator->modifier_mask()]; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-09-01 19:48:11 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Set menu item's role. | 
					
						
							|  |  |  |     base::string16 role = model->GetRoleAt(index); | 
					
						
							| 
									
										
										
										
											2016-08-08 10:09:45 -07:00
										 |  |  |     [item setTarget:self]; | 
					
						
							|  |  |  |     if (!role.empty()) { | 
					
						
							| 
									
										
										
										
											2015-09-01 19:48:11 +08:00
										 |  |  |       for (const Role& pair : kRolesMap) { | 
					
						
							|  |  |  |         if (role == base::ASCIIToUTF16(pair.role)) { | 
					
						
							| 
									
										
										
										
											2016-08-08 10:09:45 -07:00
										 |  |  |           [item setTarget:nil]; | 
					
						
							| 
									
										
										
										
											2015-09-01 19:48:11 +08:00
										 |  |  |           [item setAction:pair.selector]; | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  |   } | 
					
						
							|  |  |  |   [menu insertItem:item atIndex:index]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Called before the menu is to be displayed to update the state (enabled, | 
					
						
							|  |  |  | // radio, etc) of each item in the menu. Also will update the title if | 
					
						
							|  |  |  | // the item is marked as "dynamic". | 
					
						
							|  |  |  | - (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item { | 
					
						
							|  |  |  |   SEL action = [item action]; | 
					
						
							|  |  |  |   if (action != @selector(itemSelected:)) | 
					
						
							|  |  |  |     return NO; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   NSInteger modelIndex = [item tag]; | 
					
						
							| 
									
										
										
										
											2016-07-02 11:47:40 +09:00
										 |  |  |   atom::AtomMenuModel* model = | 
					
						
							|  |  |  |       static_cast<atom::AtomMenuModel*>( | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  |           [[(id)item representedObject] pointerValue]); | 
					
						
							|  |  |  |   DCHECK(model); | 
					
						
							|  |  |  |   if (model) { | 
					
						
							|  |  |  |     BOOL checked = model->IsItemCheckedAt(modelIndex); | 
					
						
							|  |  |  |     DCHECK([(id)item isKindOfClass:[NSMenuItem class]]); | 
					
						
							|  |  |  |     [(id)item setState:(checked ? NSOnState : NSOffState)]; | 
					
						
							|  |  |  |     [(id)item setHidden:(!model->IsVisibleAt(modelIndex))]; | 
					
						
							|  |  |  |     if (model->IsItemDynamicAt(modelIndex)) { | 
					
						
							|  |  |  |       // Update the label and the icon. | 
					
						
							|  |  |  |       NSString* label = | 
					
						
							|  |  |  |           l10n_util::FixUpWindowsStyleLabel(model->GetLabelAt(modelIndex)); | 
					
						
							|  |  |  |       [(id)item setTitle:label]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       gfx::Image icon; | 
					
						
							|  |  |  |       model->GetIconAt(modelIndex, &icon); | 
					
						
							|  |  |  |       [(id)item setImage:icon.IsEmpty() ? nil : icon.ToNSImage()]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return model->IsEnabledAt(modelIndex); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return NO; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Called when the user chooses a particular menu item. |sender| is the menu | 
					
						
							|  |  |  | // item chosen. | 
					
						
							|  |  |  | - (void)itemSelected:(id)sender { | 
					
						
							|  |  |  |   NSInteger modelIndex = [sender tag]; | 
					
						
							| 
									
										
										
										
											2016-07-02 11:47:40 +09:00
										 |  |  |   atom::AtomMenuModel* model = | 
					
						
							|  |  |  |       static_cast<atom::AtomMenuModel*>( | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  |           [[sender representedObject] pointerValue]); | 
					
						
							|  |  |  |   DCHECK(model); | 
					
						
							|  |  |  |   if (model) { | 
					
						
							| 
									
										
										
										
											2015-07-29 12:01:27 +08:00
										 |  |  |     NSEvent* event = [NSApp currentEvent]; | 
					
						
							|  |  |  |     model->ActivatedAt(modelIndex, | 
					
						
							|  |  |  |                        ui::EventFlagsFromModifiers([event modifierFlags])); | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (NSMenu*)menu { | 
					
						
							| 
									
										
										
										
											2014-11-16 21:06:16 +08:00
										 |  |  |   if (menu_) | 
					
						
							|  |  |  |     return menu_.get(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   menu_.reset([[NSMenu alloc] initWithTitle:@""]); | 
					
						
							|  |  |  |   [menu_ setDelegate:self]; | 
					
						
							|  |  |  |   if (model_) | 
					
						
							|  |  |  |     [self populateWithModel:model_]; | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  |   return menu_.get(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (BOOL)isMenuOpen { | 
					
						
							|  |  |  |   return isMenuOpen_; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)menuWillOpen:(NSMenu*)menu { | 
					
						
							|  |  |  |   isMenuOpen_ = YES; | 
					
						
							|  |  |  |   model_->MenuWillShow(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - (void)menuDidClose:(NSMenu*)menu { | 
					
						
							|  |  |  |   if (isMenuOpen_) { | 
					
						
							|  |  |  |     isMenuOpen_ = NO; | 
					
						
							| 
									
										
										
										
											2017-02-16 10:58:02 -08:00
										 |  |  |     model_->MenuWillClose(); | 
					
						
							| 
									
										
										
										
											2017-02-22 11:47:58 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Post async task so that itemSelected runs before the close callback | 
					
						
							|  |  |  |     // deletes the controller from the map which deallocates it | 
					
						
							| 
									
										
										
										
											2017-02-16 10:58:02 -08:00
										 |  |  |     if (!closeCallback.is_null()) | 
					
						
							| 
									
										
										
										
											2017-02-22 11:47:58 -08:00
										 |  |  |       BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, closeCallback); | 
					
						
							| 
									
										
										
										
											2013-08-14 22:24:21 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @end |