 Chromium Code Reviews
 Chromium Code Reviews Issue 23005021:
  Replicate standard menus for apps.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 23005021:
  Replicate standard menus for apps.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| OLD | NEW | 
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #import "chrome/browser/ui/cocoa/apps/app_menu_controller_mac.h" | 5 #import "chrome/browser/ui/cocoa/apps/app_menu_controller_mac.h" | 
| 6 | 6 | 
| 7 #include "apps/app_shim/extension_app_shim_handler_mac.h" | 7 #include "apps/app_shim/extension_app_shim_handler_mac.h" | 
| 8 #include "apps/shell_window.h" | 8 #include "apps/shell_window.h" | 
| 9 #include "apps/shell_window_registry.h" | 9 #include "apps/shell_window_registry.h" | 
| 10 #include "base/strings/sys_string_conversions.h" | 10 #include "base/strings/sys_string_conversions.h" | 
| 11 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" | 
| 12 #import "chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h" | 12 #import "chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h" | 
| 13 #include "chrome/common/extensions/extension.h" | 13 #include "chrome/common/extensions/extension.h" | 
| 14 #include "grit/chromium_strings.h" | |
| 14 #include "grit/generated_resources.h" | 15 #include "grit/generated_resources.h" | 
| 15 #include "ui/base/l10n/l10n_util.h" | 16 #include "ui/base/l10n/l10n_util.h" | 
| 16 #include "ui/base/l10n/l10n_util_mac.h" | 17 #include "ui/base/l10n/l10n_util_mac.h" | 
| 17 | 18 | 
| 19 namespace { | |
| 20 | |
| 21 // Iterates through top level items in the main menu and returns the first one | |
| 22 // with the given title. | |
| 23 NSMenuItem* FindItemByTitle(const string16& title_utf16) { | |
| 
tapted
2013/08/22 05:16:15
nit: base::string16
 
jackhou1
2013/08/29 04:25:21
Done.
 | |
| 24 NSString* title = base::SysUTF16ToNSString(title_utf16); | |
| 25 for (NSMenuItem* menu in [[NSApp mainMenu] itemArray]) { | |
| 26 NSMenuItem* item = [[menu submenu] itemWithTitle:title]; | |
| 27 if (item) | |
| 28 return item; | |
| 29 } | |
| 30 return nil; | |
| 31 } | |
| 32 | |
| 33 // Creates a new NSMenuItem with the same title, action, and key equivalent as | |
| 34 // |original|. Also creates a submenu |original| had a submenu. | |
| 35 // The returned object is not released. | |
| 36 NSMenuItem* DuplicateItem(NSMenuItem* original) { | |
| 37 NSMenuItem* item = [[NSMenuItem alloc] | |
| 
tapted
2013/08/22 05:16:15
should assign to a scoped_nsobject when using allo
 
jackhou1
2013/08/29 04:25:21
Done.
 | |
| 38 initWithTitle:[original title] | |
| 39 action:[original action] | |
| 40 keyEquivalent:[original keyEquivalent]]; | |
| 41 if ([original hasSubmenu]) { | |
| 42 base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] | |
| 43 initWithTitle:[[original submenu] title]]); | |
| 44 [item setSubmenu:menu]; | |
| 45 } | |
| 46 return item; | |
| 47 } | |
| 48 | |
| 49 // Finds an item using |message_id| and adds a duplicate of it to the submenu of | |
| 50 // |top_level_item|. | |
| 51 NSMenuItem* AddDuplicateItem(NSMenuItem* top_level_item, int message_id) { | |
| 52 NSMenu* menu = [top_level_item submenu]; | |
| 53 NSMenuItem* original = FindItemByTitle(l10n_util::GetStringUTF16(message_id)); | |
| 54 base::scoped_nsobject<NSMenuItem> item(DuplicateItem(original)); | |
| 
tapted
2013/08/22 05:16:15
NSMenuItem implements the NSCopying protocol, so i
 
jackhou1
2013/08/29 04:25:21
Done.
 | |
| 55 [menu addItem:item]; | |
| 56 return item; | |
| 57 } | |
| 58 | |
| 59 } // namespace | |
| 60 | |
| 18 @interface AppMenuController () | 61 @interface AppMenuController () | 
| 19 // Construct the NSMenuItems for apps. | 62 // Construct the NSMenuItems for apps. | 
| 20 - (void)buildAppMenuItems; | 63 - (void)buildAppMenuItems; | 
| 21 // Register for NSWindow notifications. | 64 // Register for NSWindow notifications. | 
| 22 - (void)registerEventHandlers; | 65 - (void)registerEventHandlers; | 
| 23 // If the window is an app window, add or remove menu items. | 66 // If the window is an app window, add or remove menu items. | 
| 24 - (void)windowMainStatusChanged:(NSNotification*)notification; | 67 - (void)windowMainStatusChanged:(NSNotification*)notification; | 
| 25 // Add menu items for an app and hide Chrome menu items. | 68 // Add menu items for an app and hide Chrome menu items. | 
| 26 - (void)addMenuItems:(const extensions::Extension*)app; | 69 - (void)addMenuItems:(const extensions::Extension*)app; | 
| 27 // If the window belongs to the currently focused app, remove the menu items and | 70 // If the window belongs to the currently focused app, remove the menu items and | 
| (...skipping 11 matching lines...) Expand all Loading... | |
| 39 } | 82 } | 
| 40 return self; | 83 return self; | 
| 41 } | 84 } | 
| 42 | 85 | 
| 43 - (void)dealloc { | 86 - (void)dealloc { | 
| 44 [[NSNotificationCenter defaultCenter] removeObserver:self]; | 87 [[NSNotificationCenter defaultCenter] removeObserver:self]; | 
| 45 [super dealloc]; | 88 [super dealloc]; | 
| 46 } | 89 } | 
| 47 | 90 | 
| 48 - (void)buildAppMenuItems { | 91 - (void)buildAppMenuItems { | 
| 49 quitChromeItem_ = [[[[[NSApp mainMenu] itemAtIndex:0] submenu] itemArray] | 92 quitChromeItem_ = FindItemByTitle(l10n_util::GetStringFUTF16( | 
| 50 lastObject]; | 93 IDS_EXIT_MAC, l10n_util::GetStringUTF16(IDS_PRODUCT_NAME))); | 
| 94 DCHECK(quitChromeItem_); | |
| 51 | 95 | 
| 96 // The app's menu. | |
| 52 appMenuItem_.reset([[NSMenuItem alloc] initWithTitle:@"" | 97 appMenuItem_.reset([[NSMenuItem alloc] initWithTitle:@"" | 
| 53 action:nil | 98 action:nil | 
| 54 keyEquivalent:@""]); | 99 keyEquivalent:@""]); | 
| 55 base::scoped_nsobject<NSMenu> appMenu([[NSMenu alloc] initWithTitle:@""]); | 100 base::scoped_nsobject<NSMenu> appMenu([[NSMenu alloc] initWithTitle:@""]); | 
| 56 [appMenu setAutoenablesItems:NO]; | 101 [appMenu setAutoenablesItems:NO]; | 
| 57 NSMenuItem* appQuitItem = [appMenu addItemWithTitle:@"" | 102 NSMenuItem* appQuitItem = [appMenu addItemWithTitle:@"" | 
| 58 action:nil | 103 action:nil | 
| 59 keyEquivalent:@""]; | 104 keyEquivalent:@""]; | 
| 60 [appQuitItem setTarget:self]; | 105 [appQuitItem setTarget:self]; | 
| 61 [appQuitItem setEnabled:YES]; | 106 [appQuitItem setEnabled:YES]; | 
| 62 [appMenuItem_ setSubmenu:appMenu]; | 107 [appMenuItem_ setSubmenu:appMenu]; | 
| 108 | |
| 109 // File menu. | |
| 110 fileMenuItem_.reset(DuplicateItem([[NSApp mainMenu] | |
| 111 itemWithTitle:l10n_util::GetNSString(IDS_FILE_MENU_MAC)])); | |
| 112 AddDuplicateItem(fileMenuItem_, IDS_CLOSE_WINDOW_MAC); | |
| 113 | |
| 114 // Edit menu. | |
| 115 editMenuItem_.reset(DuplicateItem([[NSApp mainMenu] | |
| 
tapted
2013/08/22 05:16:15
NSMenu supports NSCopying as well.. and I'm thinki
 
jackhou1
2013/08/29 04:25:21
I'd rather keep the items minimal until we decide
 | |
| 116 itemWithTitle:l10n_util::GetNSString(IDS_EDIT_MENU_MAC)])); | |
| 117 AddDuplicateItem(editMenuItem_, IDS_EDIT_UNDO_MAC); | |
| 118 AddDuplicateItem(editMenuItem_, IDS_EDIT_REDO_MAC); | |
| 119 [[editMenuItem_ submenu] addItem:[NSMenuItem separatorItem]]; | |
| 120 AddDuplicateItem(editMenuItem_, IDS_CUT_MAC); | |
| 121 AddDuplicateItem(editMenuItem_, IDS_COPY_MAC); | |
| 122 AddDuplicateItem(editMenuItem_, IDS_PASTE_MAC); | |
| 123 AddDuplicateItem(editMenuItem_, IDS_EDIT_DELETE_MAC); | |
| 124 AddDuplicateItem(editMenuItem_, IDS_EDIT_SELECT_ALL_MAC); | |
| 125 | |
| 126 // Window menu. | |
| 127 windowMenuItem_.reset(DuplicateItem([[NSApp mainMenu] | |
| 128 itemWithTitle:l10n_util::GetNSString(IDS_WINDOW_MENU_MAC)])); | |
| 129 AddDuplicateItem(windowMenuItem_, IDS_MINIMIZE_WINDOW_MAC); | |
| 130 AddDuplicateItem(windowMenuItem_, IDS_ZOOM_WINDOW_MAC); | |
| 131 [[windowMenuItem_ submenu] addItem:[NSMenuItem separatorItem]]; | |
| 132 AddDuplicateItem(windowMenuItem_, IDS_ALL_WINDOWS_FRONT_MAC); | |
| 63 } | 133 } | 
| 64 | 134 | 
| 65 - (void)registerEventHandlers { | 135 - (void)registerEventHandlers { | 
| 66 [[NSNotificationCenter defaultCenter] | 136 [[NSNotificationCenter defaultCenter] | 
| 67 addObserver:self | 137 addObserver:self | 
| 68 selector:@selector(windowMainStatusChanged:) | 138 selector:@selector(windowMainStatusChanged:) | 
| 69 name:NSWindowDidBecomeMainNotification | 139 name:NSWindowDidBecomeMainNotification | 
| 70 object:nil]; | 140 object:nil]; | 
| 71 | 141 | 
| 72 [[NSNotificationCenter defaultCenter] | 142 [[NSNotificationCenter defaultCenter] | 
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 127 | 197 | 
| 128 NSString* quit_localized_string = | 198 NSString* quit_localized_string = | 
| 129 l10n_util::GetNSStringF(IDS_EXIT_MAC, base::UTF8ToUTF16(app->name())); | 199 l10n_util::GetNSStringF(IDS_EXIT_MAC, base::UTF8ToUTF16(app->name())); | 
| 130 NSMenuItem* appQuitItem = [[[appMenuItem_ submenu] itemArray] lastObject]; | 200 NSMenuItem* appQuitItem = [[[appMenuItem_ submenu] itemArray] lastObject]; | 
| 131 [appQuitItem setTitle:quit_localized_string]; | 201 [appQuitItem setTitle:quit_localized_string]; | 
| 132 [appQuitItem setAction:[quitChromeItem_ action]]; | 202 [appQuitItem setAction:[quitChromeItem_ action]]; | 
| 133 [appQuitItem setKeyEquivalent:[quitChromeItem_ keyEquivalent]]; | 203 [appQuitItem setKeyEquivalent:[quitChromeItem_ keyEquivalent]]; | 
| 134 | 204 | 
| 135 [appMenuItem_ setTitle:appId]; | 205 [appMenuItem_ setTitle:appId]; | 
| 136 [[appMenuItem_ submenu] setTitle:title]; | 206 [[appMenuItem_ submenu] setTitle:title]; | 
| 207 | |
| 137 [mainMenu addItem:appMenuItem_]; | 208 [mainMenu addItem:appMenuItem_]; | 
| 209 [mainMenu addItem:fileMenuItem_]; | |
| 210 [mainMenu addItem:editMenuItem_]; | |
| 211 [mainMenu addItem:windowMenuItem_]; | |
| 138 } | 212 } | 
| 139 | 213 | 
| 140 - (void)removeMenuItems:(NSString*)appId { | 214 - (void)removeMenuItems:(NSString*)appId { | 
| 141 if (![appId_ isEqualToString:appId]) | 215 if (![appId_ isEqualToString:appId]) | 
| 142 return; | 216 return; | 
| 143 | 217 | 
| 218 // Remove menu items for packaged app. | |
| 144 appId_.reset(); | 219 appId_.reset(); | 
| 145 | 220 | 
| 146 NSMenu* mainMenu = [NSApp mainMenu]; | 221 NSMenu* mainMenu = [NSApp mainMenu]; | 
| 147 [mainMenu removeItem:appMenuItem_]; | 222 [mainMenu removeItem:appMenuItem_]; | 
| 223 [mainMenu removeItem:fileMenuItem_]; | |
| 224 [mainMenu removeItem:editMenuItem_]; | |
| 225 [mainMenu removeItem:windowMenuItem_]; | |
| 148 | 226 | 
| 149 // Restore the Chrome main menu bar. | 227 // Restore the Chrome main menu bar. | 
| 150 for (NSMenuItem* item in [mainMenu itemArray]) | 228 for (NSMenuItem* item in [mainMenu itemArray]) | 
| 151 [item setHidden:NO]; | 229 [item setHidden:NO]; | 
| 152 | 230 | 
| 153 [quitChromeItem_ setAction:@selector(terminate:)]; | 231 [quitChromeItem_ setAction:@selector(terminate:)]; | 
| 154 } | 232 } | 
| 155 | 233 | 
| 156 // If the currently focused window belongs to a platform app, quit the app. | 234 // If the currently focused window belongs to a platform app, quit the app. | 
| 157 - (void)quitCurrentPlatformApp { | 235 - (void)quitCurrentPlatformApp { | 
| 158 apps::ShellWindow* shellWindow = | 236 apps::ShellWindow* shellWindow = | 
| 159 apps::ShellWindowRegistry::GetShellWindowForNativeWindowAnyProfile( | 237 apps::ShellWindowRegistry::GetShellWindowForNativeWindowAnyProfile( | 
| 160 [NSApp keyWindow]); | 238 [NSApp keyWindow]); | 
| 161 if (shellWindow) | 239 if (shellWindow) | 
| 162 apps::ExtensionAppShimHandler::QuitAppForWindow(shellWindow); | 240 apps::ExtensionAppShimHandler::QuitAppForWindow(shellWindow); | 
| 163 } | 241 } | 
| 164 | 242 | 
| 165 @end | 243 @end | 
| OLD | NEW |