Chromium Code Reviews| 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_shim_menu_controller_mac.h" | 5 #import "chrome/browser/ui/cocoa/apps/app_shim_menu_controller_mac.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | |
| 7 #include "base/mac/scoped_nsautorelease_pool.h" | 8 #include "base/mac/scoped_nsautorelease_pool.h" |
| 8 #include "base/strings/sys_string_conversions.h" | 9 #include "base/strings/sys_string_conversions.h" |
| 9 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
| 10 #include "chrome/app/chrome_command_ids.h" | 11 #include "chrome/app/chrome_command_ids.h" |
| 11 #include "chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h" | 12 #include "chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h" |
| 12 #include "chrome/browser/apps/app_window_registry_util.h" | 13 #include "chrome/browser/apps/app_window_registry_util.h" |
| 13 #include "chrome/browser/profiles/profile.h" | 14 #include "chrome/browser/profiles/profile.h" |
| 14 #include "chrome/browser/ui/browser.h" | 15 #include "chrome/browser/ui/browser.h" |
| 15 #include "chrome/browser/ui/browser_finder.h" | 16 #include "chrome/browser/ui/browser_finder.h" |
| 16 #import "chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h" | 17 #import "chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h" |
| 18 #include "chrome/common/chrome_switches.h" | |
| 17 #include "chrome/grit/generated_resources.h" | 19 #include "chrome/grit/generated_resources.h" |
| 18 #include "extensions/browser/app_window/app_window.h" | 20 #include "extensions/browser/app_window/app_window.h" |
| 19 #include "extensions/common/extension.h" | 21 #include "extensions/common/extension.h" |
| 20 #include "ui/base/l10n/l10n_util.h" | 22 #include "ui/base/l10n/l10n_util.h" |
| 21 #include "ui/base/l10n/l10n_util_mac.h" | 23 #include "ui/base/l10n/l10n_util_mac.h" |
| 22 | 24 |
| 25 using extensions::Extension; | |
| 26 | |
| 23 namespace { | 27 namespace { |
| 24 | 28 |
| 29 // When an app window loses main status, AppKit may make another app window main | |
| 30 // instead. Rather than trying to predict what AppKit will do (which is hard), | |
| 31 // just protect against changes in the event queue that will clobber each other. | |
| 32 int g_window_cycle_sequence_number = 0; | |
| 33 | |
| 34 // Whether Custom Cmd+` window cycling is enabled for apps. | |
| 35 bool IsAppWindowCyclingEnabled() { | |
| 36 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | |
| 37 if (command_line->HasSwitch(switches::kDisableAppWindowCycling)) | |
| 38 return false; | |
| 39 if (command_line->HasSwitch(switches::kEnableAppWindowCycling)) | |
| 40 return true; | |
| 41 | |
| 42 return false; // Current default. | |
| 43 } | |
| 44 | |
| 25 // Gets an item from the main menu given the tag of the top level item | 45 // Gets an item from the main menu given the tag of the top level item |
| 26 // |menu_tag| and the tag of the item |item_tag|. | 46 // |menu_tag| and the tag of the item |item_tag|. |
| 27 NSMenuItem* GetItemByTag(NSInteger menu_tag, NSInteger item_tag) { | 47 NSMenuItem* GetItemByTag(NSInteger menu_tag, NSInteger item_tag) { |
| 28 return [[[[NSApp mainMenu] itemWithTag:menu_tag] submenu] | 48 return [[[[NSApp mainMenu] itemWithTag:menu_tag] submenu] |
| 29 itemWithTag:item_tag]; | 49 itemWithTag:item_tag]; |
| 30 } | 50 } |
| 31 | 51 |
| 32 // Finds a top level menu item using |menu_tag| and creates a new NSMenuItem | 52 // Finds a top level menu item using |menu_tag| and creates a new NSMenuItem |
| 33 // with the same title. | 53 // with the same title. |
| 34 NSMenuItem* NewTopLevelItemFrom(NSInteger menu_tag) { | 54 NSMenuItem* NewTopLevelItemFrom(NSInteger menu_tag) { |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 106 DCHECK([alternate_item isAlternate]); | 126 DCHECK([alternate_item isAlternate]); |
| 107 } | 127 } |
| 108 | 128 |
| 109 // The alternate item visibility should always be in sync. | 129 // The alternate item visibility should always be in sync. |
| 110 DCHECK_EQ([alternate_item isHidden], [menu_item isHidden]); | 130 DCHECK_EQ([alternate_item isHidden], [menu_item isHidden]); |
| 111 [alternate_item setAlternate:visible]; | 131 [alternate_item setAlternate:visible]; |
| 112 [alternate_item setHidden:!visible]; | 132 [alternate_item setHidden:!visible]; |
| 113 [menu_item setHidden:!visible]; | 133 [menu_item setHidden:!visible]; |
| 114 } | 134 } |
| 115 | 135 |
| 136 // Return the Extension (if any) associated with the given window. If it is not | |
| 137 // a platform app nor hosted app, but it is a browser, |is_browser| will be set | |
| 138 // to true (otherwise false). | |
| 139 const Extension* GetExtensionForNSWindow(NSWindow* window, bool* is_browser) { | |
| 140 const Extension* extension = nullptr; | |
| 141 Browser* browser = nullptr; | |
| 142 | |
| 143 extensions::AppWindow* app_window = | |
| 144 AppWindowRegistryUtil::GetAppWindowForNativeWindowAnyProfile(window); | |
| 145 if (app_window) { | |
| 146 extension = app_window->GetExtension(); | |
| 147 } else { | |
| 148 // If there is no corresponding AppWindow, this could be a hosted app, so | |
| 149 // check for a browser. | |
| 150 browser = chrome::FindBrowserWithWindow(window); | |
| 151 extension = apps::ExtensionAppShimHandler::MaybeGetAppForBrowser(browser); | |
| 152 } | |
| 153 | |
| 154 *is_browser = extension == nullptr && browser != nullptr; | |
| 155 return extension; | |
| 156 } | |
| 157 | |
| 158 // Sets or clears NSWindowCollectionBehaviorIgnoresCycle for |window|. Does not | |
| 159 // change NSWindowCollectionBehaviorParticipatesInCycle. That exists, e.g, for | |
| 160 // an NSPanel to override its default behavior, but this should only ever be | |
| 161 // called for Browser windows and App windows (which are not panels). | |
| 162 bool SetWindowParticipatesInCycle(NSWindow* window, bool participates) { | |
| 163 const NSWindowCollectionBehavior past_behavior = [window collectionBehavior]; | |
| 164 NSWindowCollectionBehavior behavior = past_behavior; | |
| 165 if (participates) | |
| 166 behavior &= ~NSWindowCollectionBehaviorIgnoresCycle; | |
| 167 else | |
| 168 behavior |= NSWindowCollectionBehaviorIgnoresCycle; | |
| 169 | |
| 170 // Often, there is no change. AppKit has no early exit since the value is | |
| 171 // derived partially from styleMask and other things, so do our own. | |
| 172 if (behavior == past_behavior) | |
| 173 return false; | |
| 174 | |
| 175 [window setCollectionBehavior:behavior]; | |
| 176 return true; | |
| 177 } | |
| 178 | |
| 179 // Sets the window cycle list to |app_id|'s windows only. | |
| 180 void SetAppCyclesWindows(const std::string& app_id, int sequence_number) { | |
| 181 if (g_window_cycle_sequence_number != sequence_number) | |
| 182 return; | |
| 183 | |
| 184 bool any_change = false; | |
| 185 for (NSWindow* window : [NSApp windows]) { | |
| 186 bool is_browser; | |
| 187 const Extension* extension = GetExtensionForNSWindow(window, &is_browser); | |
| 188 if (extension && extension->id() == app_id) | |
| 189 any_change = SetWindowParticipatesInCycle(window, true) || any_change; | |
|
Robert Sesek
2015/06/23 15:00:55
You could use |= instead of "|| any change" at the
tapted
2015/06/23 23:36:10
Done.
| |
| 190 else if (extension || is_browser) | |
| 191 any_change = SetWindowParticipatesInCycle(window, false) || any_change; | |
| 192 } | |
| 193 | |
| 194 // Without the following, -[NSApplication _getLockedWindowListForCycle] will | |
| 195 // happily return windows that were just set to ignore window cycling. Doing | |
| 196 // this seems to trick AppKit into updating the window cycle list. But it is a | |
| 197 // bit scary, so avoid it when there is no change. These attempts were based | |
| 198 // on the observation that clicking a window twice to switch focus would | |
| 199 // always work. Also tried (without luck): | |
| 200 // - [NSApp setWindowsNeedUpdate:YES], | |
| 201 // - Creating a deferred NSWindow and immediately releasing it, | |
| 202 // - Calling private methods like [NSApp _unlockWindowListForCycle], | |
| 203 // - [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined... | |
| 204 // (an attempt to tickle AppKit into an update of some kind), | |
| 205 // - Calling synchronously (i.e. not via PostTask) <- this was actually the | |
| 206 // initial attempt. Then, switching to PostTask didn't help with this | |
| 207 // quirk, but was useful for the sequence number stuff, and | |
| 208 // - Re-ordering collection behavior changes to ensure one window was always | |
| 209 // participating (i.e. all 'adds' before any 'removes'). | |
| 210 if (any_change) | |
| 211 [[NSApp keyWindow] makeKeyAndOrderFront:nil]; | |
| 212 } | |
| 213 | |
| 214 // Sets the window cycle list to Chrome browser windows only. | |
| 215 void SetChromeCyclesWindows(int sequence_number) { | |
| 216 if (g_window_cycle_sequence_number != sequence_number) | |
| 217 return; | |
| 218 | |
| 219 bool any_change = false; | |
| 220 for (NSWindow* window : [NSApp windows]) { | |
| 221 bool is_browser; | |
| 222 const Extension* extension = GetExtensionForNSWindow(window, &is_browser); | |
| 223 if (extension || is_browser) { | |
| 224 any_change = | |
| 225 SetWindowParticipatesInCycle(window, is_browser) || any_change; | |
|
Robert Sesek
2015/06/23 15:00:55
Same.
tapted
2015/06/23 23:36:10
Done.
| |
| 226 } | |
| 227 } | |
| 228 if (any_change) | |
| 229 [[NSApp keyWindow] makeKeyAndOrderFront:nil]; | |
| 230 } | |
| 231 | |
| 116 } // namespace | 232 } // namespace |
| 117 | 233 |
| 118 // Used by AppShimMenuController to manage menu items that are a copy of a | 234 // Used by AppShimMenuController to manage menu items that are a copy of a |
| 119 // Chrome menu item but with a different action. This manages unsetting and | 235 // Chrome menu item but with a different action. This manages unsetting and |
| 120 // restoring the original item's key equivalent, so that we can use the same | 236 // restoring the original item's key equivalent, so that we can use the same |
| 121 // key equivalent in the copied item with a different action. If |resourceId_| | 237 // key equivalent in the copied item with a different action. If |resourceId_| |
| 122 // is non-zero, this will also update the title to include the app name. | 238 // is non-zero, this will also update the title to include the app name. |
| 123 // If the copy (menuItem) has no key equivalent, and the title does not have the | 239 // If the copy (menuItem) has no key equivalent, and the title does not have the |
| 124 // app name, then enableForApp and disable do not need to be called. I.e. the | 240 // app name, then enableForApp and disable do not need to be called. I.e. the |
| 125 // doppelganger just copies the item and sets a new action. | 241 // doppelganger just copies the item and sets a new action. |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 142 keyEquivalent:(NSString*)keyEquivalent; | 258 keyEquivalent:(NSString*)keyEquivalent; |
| 143 // Retain the source item given |menuTag| and |sourceItemTag|. Copy | 259 // Retain the source item given |menuTag| and |sourceItemTag|. Copy |
| 144 // the menu item given |menuTag| and |targetItemTag|. | 260 // the menu item given |menuTag| and |targetItemTag|. |
| 145 // This is useful when we want a doppelganger with a different source item. | 261 // This is useful when we want a doppelganger with a different source item. |
| 146 // For example, if there are conflicting key equivalents. | 262 // For example, if there are conflicting key equivalents. |
| 147 - (id)initWithMenuTag:(NSInteger)menuTag | 263 - (id)initWithMenuTag:(NSInteger)menuTag |
| 148 sourceItemTag:(NSInteger)sourceItemTag | 264 sourceItemTag:(NSInteger)sourceItemTag |
| 149 targetItemTag:(NSInteger)targetItemTag | 265 targetItemTag:(NSInteger)targetItemTag |
| 150 keyEquivalent:(NSString*)keyEquivalent; | 266 keyEquivalent:(NSString*)keyEquivalent; |
| 151 // Set the title using |resourceId_| and unset the source item's key equivalent. | 267 // Set the title using |resourceId_| and unset the source item's key equivalent. |
| 152 - (void)enableForApp:(const extensions::Extension*)app; | 268 - (void)enableForApp:(const Extension*)app; |
| 153 // Restore the source item's key equivalent. | 269 // Restore the source item's key equivalent. |
| 154 - (void)disable; | 270 - (void)disable; |
| 155 @end | 271 @end |
| 156 | 272 |
| 157 @implementation DoppelgangerMenuItem | 273 @implementation DoppelgangerMenuItem |
| 158 | 274 |
| 159 - (NSMenuItem*)menuItem { | 275 - (NSMenuItem*)menuItem { |
| 160 return menuItem_; | 276 return menuItem_; |
| 161 } | 277 } |
| 162 | 278 |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 188 if ((self = [super init])) { | 304 if ((self = [super init])) { |
| 189 menuItem_.reset([GetItemByTag(menuTag, targetItemTag) copy]); | 305 menuItem_.reset([GetItemByTag(menuTag, targetItemTag) copy]); |
| 190 sourceItem_.reset([GetItemByTag(menuTag, sourceItemTag) retain]); | 306 sourceItem_.reset([GetItemByTag(menuTag, sourceItemTag) retain]); |
| 191 DCHECK(menuItem_); | 307 DCHECK(menuItem_); |
| 192 DCHECK(sourceItem_); | 308 DCHECK(sourceItem_); |
| 193 sourceKeyEquivalent_.reset([[sourceItem_ keyEquivalent] copy]); | 309 sourceKeyEquivalent_.reset([[sourceItem_ keyEquivalent] copy]); |
| 194 } | 310 } |
| 195 return self; | 311 return self; |
| 196 } | 312 } |
| 197 | 313 |
| 198 - (void)enableForApp:(const extensions::Extension*)app { | 314 - (void)enableForApp:(const Extension*)app { |
| 199 // It seems that two menu items that have the same key equivalent must also | 315 // It seems that two menu items that have the same key equivalent must also |
| 200 // have the same action for the keyboard shortcut to work. (This refers to the | 316 // have the same action for the keyboard shortcut to work. (This refers to the |
| 201 // original keyboard shortcut, regardless of any overrides set in OSX). | 317 // original keyboard shortcut, regardless of any overrides set in OSX). |
| 202 // In order to let the app menu items have a different action, we remove the | 318 // In order to let the app menu items have a different action, we remove the |
| 203 // key equivalent of the original items and restore them later. | 319 // key equivalent of the original items and restore them later. |
| 204 [sourceItem_ setKeyEquivalent:@""]; | 320 [sourceItem_ setKeyEquivalent:@""]; |
| 205 if (!resourceId_) | 321 if (!resourceId_) |
| 206 return; | 322 return; |
| 207 | 323 |
| 208 [menuItem_ setTitle:l10n_util::GetNSStringF(resourceId_, | 324 [menuItem_ setTitle:l10n_util::GetNSStringF(resourceId_, |
| 209 base::UTF8ToUTF16(app->name()))]; | 325 base::UTF8ToUTF16(app->name()))]; |
| 210 } | 326 } |
| 211 | 327 |
| 212 - (void)disable { | 328 - (void)disable { |
| 213 // Restore the keyboard shortcut to Chrome. This just needs to be set back to | 329 // Restore the keyboard shortcut to Chrome. This just needs to be set back to |
| 214 // the original keyboard shortcut, regardless of any overrides in OSX. The | 330 // the original keyboard shortcut, regardless of any overrides in OSX. The |
| 215 // overrides still work as they are based on the title of the menu item. | 331 // overrides still work as they are based on the title of the menu item. |
| 216 [sourceItem_ setKeyEquivalent:sourceKeyEquivalent_]; | 332 [sourceItem_ setKeyEquivalent:sourceKeyEquivalent_]; |
| 217 } | 333 } |
| 218 | 334 |
| 219 @end | 335 @end |
| 220 | 336 |
| 221 @interface AppShimMenuController () | 337 @interface AppShimMenuController () |
| 222 // Construct the NSMenuItems for apps. | 338 // Construct the NSMenuItems for apps. |
| 223 - (void)buildAppMenuItems; | 339 - (void)buildAppMenuItems; |
| 224 // Register for NSWindow notifications. | 340 // Register for NSWindow notifications. |
| 225 - (void)registerEventHandlers; | 341 - (void)registerEventHandlers; |
| 226 // If the window is an app window, add or remove menu items. | 342 // If the window is an app window, add or remove menu items. |
| 227 - (void)windowMainStatusChanged:(NSNotification*)notification; | 343 - (void)windowMainStatusChanged:(NSNotification*)notification; |
| 344 // Called when |app| becomes the main window in the Chrome process. | |
| 345 - (void)appBecameMain:(const Extension*)app; | |
| 346 // Called when there is no main window, or if the main window is not an app. | |
| 347 - (void)chromeBecameMain; | |
| 228 // Add menu items for an app and hide Chrome menu items. | 348 // Add menu items for an app and hide Chrome menu items. |
| 229 - (void)addMenuItems:(const extensions::Extension*)app; | 349 - (void)addMenuItems:(const Extension*)app; |
| 230 // If the window belongs to the currently focused app, remove the menu items and | 350 // If the window belongs to the currently focused app, remove the menu items and |
| 231 // unhide Chrome menu items. | 351 // unhide Chrome menu items. |
| 232 - (void)removeMenuItems; | 352 - (void)removeMenuItems; |
| 233 // If the currently focused window belongs to a platform app, quit the app. | 353 // If the currently focused window belongs to a platform app, quit the app. |
| 234 - (void)quitCurrentPlatformApp; | 354 - (void)quitCurrentPlatformApp; |
| 235 // If the currently focused window belongs to a platform app, hide the app. | 355 // If the currently focused window belongs to a platform app, hide the app. |
| 236 - (void)hideCurrentPlatformApp; | 356 - (void)hideCurrentPlatformApp; |
| 237 // If the currently focused window belongs to a platform app, focus the app. | 357 // If the currently focused window belongs to a platform app, focus the app. |
| 238 - (void)focusCurrentPlatformApp; | 358 - (void)focusCurrentPlatformApp; |
| 239 @end | 359 @end |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 369 // A Yosemite AppKit bug causes this notification to be sent during the | 489 // A Yosemite AppKit bug causes this notification to be sent during the |
| 370 // -dealloc for a specific NSWindow. Any autoreleases sent to that window | 490 // -dealloc for a specific NSWindow. Any autoreleases sent to that window |
| 371 // must be drained before the window finishes -dealloc. In this method, an | 491 // must be drained before the window finishes -dealloc. In this method, an |
| 372 // autorelease is sent by the invocation of [NSApp windows]. | 492 // autorelease is sent by the invocation of [NSApp windows]. |
| 373 // http://crbug.com/406944. | 493 // http://crbug.com/406944. |
| 374 base::mac::ScopedNSAutoreleasePool pool; | 494 base::mac::ScopedNSAutoreleasePool pool; |
| 375 | 495 |
| 376 NSString* name = [notification name]; | 496 NSString* name = [notification name]; |
| 377 if ([name isEqualToString:NSWindowDidBecomeMainNotification]) { | 497 if ([name isEqualToString:NSWindowDidBecomeMainNotification]) { |
| 378 id window = [notification object]; | 498 id window = [notification object]; |
| 379 extensions::AppWindow* appWindow = | 499 bool is_browser; |
| 380 AppWindowRegistryUtil::GetAppWindowForNativeWindowAnyProfile( | 500 const Extension* extension = GetExtensionForNSWindow(window, &is_browser); |
| 381 window); | 501 // Ignore is_browser: if a window becomes main that does not belong to an |
| 382 | 502 // extension or browser, treat it the same as switching to a browser. |
| 383 const extensions::Extension* extension = NULL; | 503 if (extension) |
| 384 // If there is no corresponding AppWindow, this could be a hosted app, so | 504 [self appBecameMain:extension]; |
| 385 // check for a browser. | |
| 386 if (appWindow) | |
| 387 extension = appWindow->GetExtension(); | |
| 388 else | 505 else |
| 389 extension = apps::ExtensionAppShimHandler::MaybeGetAppForBrowser( | 506 [self chromeBecameMain]; |
| 390 chrome::FindBrowserWithWindow(window)); | |
| 391 | |
| 392 if (extension) | |
| 393 [self addMenuItems:extension]; | |
| 394 else | |
| 395 [self removeMenuItems]; | |
| 396 } else if ([name isEqualToString:NSWindowDidResignMainNotification]) { | 507 } else if ([name isEqualToString:NSWindowDidResignMainNotification]) { |
| 397 // When a window resigns main status, reset back to the Chrome menu. | 508 // When a window resigns main status, reset back to the Chrome menu. |
| 398 // In the past we've tried: | 509 // In the past we've tried: |
| 399 // - Only doing this when a window closes, but this would not be triggered | 510 // - Only doing this when a window closes, but this would not be triggered |
| 400 // when an app becomes hidden (Cmd+h), and there are no Chrome windows to | 511 // when an app becomes hidden (Cmd+h), and there are no Chrome windows to |
| 401 // become main. | 512 // become main. |
| 402 // - Scanning [NSApp windows] to predict whether we could | 513 // - Scanning [NSApp windows] to predict whether we could |
| 403 // expect another Chrome window to become main, and skip the reset. However, | 514 // expect another Chrome window to become main, and skip the reset. However, |
| 404 // panels need to do strange things during window close to ensure panels | 515 // panels need to do strange things during window close to ensure panels |
| 405 // never get chosen for key status over a browser window (which is likely | 516 // never get chosen for key status over a browser window (which is likely |
| 406 // because they are given an elevated [NSWindow level]). Trying to handle | 517 // because they are given an elevated [NSWindow level]). Trying to handle |
| 407 // this case is not robust. | 518 // this case is not robust. |
| 408 // | 519 // |
| 409 // Unfortunately, resetting the menu to Chrome | 520 // Unfortunately, resetting the menu to Chrome |
| 410 // unconditionally means that if another packaged app window becomes key, | 521 // unconditionally means that if another packaged app window becomes key, |
| 411 // the menu will flicker. TODO(tapted): Investigate restoring the logic when | 522 // the menu will flicker. TODO(tapted): Investigate restoring the logic when |
| 412 // the panel code is removed. | 523 // the panel code is removed. |
| 413 [self removeMenuItems]; | 524 [self chromeBecameMain]; |
| 414 } else { | 525 } else { |
| 415 NOTREACHED(); | 526 NOTREACHED(); |
| 416 } | 527 } |
| 417 } | 528 } |
| 418 | 529 |
| 419 - (void)addMenuItems:(const extensions::Extension*)app { | 530 - (void)appBecameMain:(const Extension*)app { |
| 420 NSString* appId = base::SysUTF8ToNSString(app->id()); | 531 if (appId_ == app->id()) |
| 421 NSString* title = base::SysUTF8ToNSString(app->name()); | |
| 422 | |
| 423 if ([appId_ isEqualToString:appId]) | |
| 424 return; | 532 return; |
| 425 | 533 |
| 534 if (!appId_.empty()) | |
| 535 [self removeMenuItems]; | |
| 536 | |
| 537 appId_ = app->id(); | |
| 538 [self addMenuItems:app]; | |
| 539 if (IsAppWindowCyclingEnabled()) { | |
| 540 base::MessageLoop::current()->PostTask( | |
| 541 FROM_HERE, base::Bind(&SetAppCyclesWindows, appId_, | |
| 542 ++g_window_cycle_sequence_number)); | |
| 543 } | |
| 544 } | |
| 545 | |
| 546 - (void)chromeBecameMain { | |
| 547 if (appId_.empty()) | |
| 548 return; | |
| 549 | |
| 550 appId_.clear(); | |
| 426 [self removeMenuItems]; | 551 [self removeMenuItems]; |
| 427 appId_.reset([appId copy]); | 552 if (IsAppWindowCyclingEnabled()) { |
| 553 base::MessageLoop::current()->PostTask( | |
| 554 FROM_HERE, | |
| 555 base::Bind(&SetChromeCyclesWindows, ++g_window_cycle_sequence_number)); | |
| 556 } | |
| 557 } | |
| 558 | |
| 559 - (void)addMenuItems:(const Extension*)app { | |
| 560 DCHECK_EQ(appId_, app->id()); | |
| 561 NSString* title = base::SysUTF8ToNSString(app->name()); | |
| 428 | 562 |
| 429 // Hide Chrome menu items. | 563 // Hide Chrome menu items. |
| 430 NSMenu* mainMenu = [NSApp mainMenu]; | 564 NSMenu* mainMenu = [NSApp mainMenu]; |
| 431 for (NSMenuItem* item in [mainMenu itemArray]) | 565 for (NSMenuItem* item in [mainMenu itemArray]) |
| 432 [item setHidden:YES]; | 566 [item setHidden:YES]; |
| 433 | 567 |
| 434 [aboutDoppelganger_ enableForApp:app]; | 568 [aboutDoppelganger_ enableForApp:app]; |
| 435 [hideDoppelganger_ enableForApp:app]; | 569 [hideDoppelganger_ enableForApp:app]; |
| 436 [quitDoppelganger_ enableForApp:app]; | 570 [quitDoppelganger_ enableForApp:app]; |
| 437 [newDoppelganger_ enableForApp:app]; | 571 [newDoppelganger_ enableForApp:app]; |
| 438 [openDoppelganger_ enableForApp:app]; | 572 [openDoppelganger_ enableForApp:app]; |
| 439 [closeWindowDoppelganger_ enableForApp:app]; | 573 [closeWindowDoppelganger_ enableForApp:app]; |
| 440 | 574 |
| 441 [appMenuItem_ setTitle:appId]; | 575 [appMenuItem_ setTitle:base::SysUTF8ToNSString(appId_)]; |
| 442 [[appMenuItem_ submenu] setTitle:title]; | 576 [[appMenuItem_ submenu] setTitle:title]; |
| 443 | 577 |
| 444 [mainMenu addItem:appMenuItem_]; | 578 [mainMenu addItem:appMenuItem_]; |
| 445 [mainMenu addItem:fileMenuItem_]; | 579 [mainMenu addItem:fileMenuItem_]; |
| 446 | 580 |
| 447 SetItemWithTagVisible(editMenuItem_, | 581 SetItemWithTagVisible(editMenuItem_, |
| 448 IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE, | 582 IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE, |
| 449 app->is_hosted_app(), true); | 583 app->is_hosted_app(), true); |
| 450 SetItemWithTagVisible(editMenuItem_, IDC_FIND_MENU, app->is_hosted_app(), | 584 SetItemWithTagVisible(editMenuItem_, IDC_FIND_MENU, app->is_hosted_app(), |
| 451 false); | 585 false); |
| 452 [mainMenu addItem:editMenuItem_]; | 586 [mainMenu addItem:editMenuItem_]; |
| 453 | 587 |
| 454 if (app->is_hosted_app()) { | 588 if (app->is_hosted_app()) { |
| 455 [mainMenu addItem:viewMenuItem_]; | 589 [mainMenu addItem:viewMenuItem_]; |
| 456 [mainMenu addItem:historyMenuItem_]; | 590 [mainMenu addItem:historyMenuItem_]; |
| 457 } | 591 } |
| 458 [mainMenu addItem:windowMenuItem_]; | 592 [mainMenu addItem:windowMenuItem_]; |
| 459 } | 593 } |
| 460 | 594 |
| 461 - (void)removeMenuItems { | 595 - (void)removeMenuItems { |
| 462 if (!appId_) | |
| 463 return; | |
| 464 | |
| 465 appId_.reset(); | |
| 466 | |
| 467 NSMenu* mainMenu = [NSApp mainMenu]; | 596 NSMenu* mainMenu = [NSApp mainMenu]; |
| 468 [mainMenu removeItem:appMenuItem_]; | 597 [mainMenu removeItem:appMenuItem_]; |
| 469 [mainMenu removeItem:fileMenuItem_]; | 598 [mainMenu removeItem:fileMenuItem_]; |
| 470 if ([mainMenu indexOfItem:viewMenuItem_] >= 0) | 599 if ([mainMenu indexOfItem:viewMenuItem_] >= 0) |
| 471 [mainMenu removeItem:viewMenuItem_]; | 600 [mainMenu removeItem:viewMenuItem_]; |
| 472 if ([mainMenu indexOfItem:historyMenuItem_] >= 0) | 601 if ([mainMenu indexOfItem:historyMenuItem_] >= 0) |
| 473 [mainMenu removeItem:historyMenuItem_]; | 602 [mainMenu removeItem:historyMenuItem_]; |
| 474 [mainMenu removeItem:editMenuItem_]; | 603 [mainMenu removeItem:editMenuItem_]; |
| 475 [mainMenu removeItem:windowMenuItem_]; | 604 [mainMenu removeItem:windowMenuItem_]; |
| 476 | 605 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 487 } | 616 } |
| 488 | 617 |
| 489 - (void)quitCurrentPlatformApp { | 618 - (void)quitCurrentPlatformApp { |
| 490 extensions::AppWindow* appWindow = | 619 extensions::AppWindow* appWindow = |
| 491 AppWindowRegistryUtil::GetAppWindowForNativeWindowAnyProfile( | 620 AppWindowRegistryUtil::GetAppWindowForNativeWindowAnyProfile( |
| 492 [NSApp keyWindow]); | 621 [NSApp keyWindow]); |
| 493 if (appWindow) { | 622 if (appWindow) { |
| 494 apps::ExtensionAppShimHandler::QuitAppForWindow(appWindow); | 623 apps::ExtensionAppShimHandler::QuitAppForWindow(appWindow); |
| 495 } else { | 624 } else { |
| 496 Browser* browser = chrome::FindBrowserWithWindow([NSApp keyWindow]); | 625 Browser* browser = chrome::FindBrowserWithWindow([NSApp keyWindow]); |
| 497 const extensions::Extension* extension = | 626 const Extension* extension = |
| 498 apps::ExtensionAppShimHandler::MaybeGetAppForBrowser(browser); | 627 apps::ExtensionAppShimHandler::MaybeGetAppForBrowser(browser); |
| 499 if (extension) | 628 if (extension) |
| 500 apps::ExtensionAppShimHandler::QuitHostedAppForWindow(browser->profile(), | 629 apps::ExtensionAppShimHandler::QuitHostedAppForWindow(browser->profile(), |
| 501 extension->id()); | 630 extension->id()); |
| 502 } | 631 } |
| 503 } | 632 } |
| 504 | 633 |
| 505 - (void)hideCurrentPlatformApp { | 634 - (void)hideCurrentPlatformApp { |
| 506 extensions::AppWindow* appWindow = | 635 extensions::AppWindow* appWindow = |
| 507 AppWindowRegistryUtil::GetAppWindowForNativeWindowAnyProfile( | 636 AppWindowRegistryUtil::GetAppWindowForNativeWindowAnyProfile( |
| 508 [NSApp keyWindow]); | 637 [NSApp keyWindow]); |
| 509 if (appWindow) { | 638 if (appWindow) { |
| 510 apps::ExtensionAppShimHandler::HideAppForWindow(appWindow); | 639 apps::ExtensionAppShimHandler::HideAppForWindow(appWindow); |
| 511 } else { | 640 } else { |
| 512 Browser* browser = chrome::FindBrowserWithWindow([NSApp keyWindow]); | 641 Browser* browser = chrome::FindBrowserWithWindow([NSApp keyWindow]); |
| 513 const extensions::Extension* extension = | 642 const Extension* extension = |
| 514 apps::ExtensionAppShimHandler::MaybeGetAppForBrowser(browser); | 643 apps::ExtensionAppShimHandler::MaybeGetAppForBrowser(browser); |
| 515 if (extension) | 644 if (extension) |
| 516 apps::ExtensionAppShimHandler::HideHostedApp(browser->profile(), | 645 apps::ExtensionAppShimHandler::HideHostedApp(browser->profile(), |
| 517 extension->id()); | 646 extension->id()); |
| 518 } | 647 } |
| 519 } | 648 } |
| 520 | 649 |
| 521 - (void)focusCurrentPlatformApp { | 650 - (void)focusCurrentPlatformApp { |
| 522 extensions::AppWindow* appWindow = | 651 extensions::AppWindow* appWindow = |
| 523 AppWindowRegistryUtil::GetAppWindowForNativeWindowAnyProfile( | 652 AppWindowRegistryUtil::GetAppWindowForNativeWindowAnyProfile( |
| 524 [NSApp keyWindow]); | 653 [NSApp keyWindow]); |
| 525 if (appWindow) | 654 if (appWindow) |
| 526 apps::ExtensionAppShimHandler::FocusAppForWindow(appWindow); | 655 apps::ExtensionAppShimHandler::FocusAppForWindow(appWindow); |
| 527 } | 656 } |
| 528 | 657 |
| 529 @end | 658 @end |
| OLD | NEW |