| 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); |
| 190 else if (extension || is_browser) |
| 191 any_change |= SetWindowParticipatesInCycle(window, false); |
| 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 |= SetWindowParticipatesInCycle(window, is_browser); |
| 225 } |
| 226 if (any_change) |
| 227 [[NSApp keyWindow] makeKeyAndOrderFront:nil]; |
| 228 } |
| 229 |
| 116 } // namespace | 230 } // namespace |
| 117 | 231 |
| 118 // Used by AppShimMenuController to manage menu items that are a copy of a | 232 // 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 | 233 // 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 | 234 // 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_| | 235 // 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. | 236 // 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 | 237 // 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 | 238 // 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. | 239 // doppelganger just copies the item and sets a new action. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 142 keyEquivalent:(NSString*)keyEquivalent; | 256 keyEquivalent:(NSString*)keyEquivalent; |
| 143 // Retain the source item given |menuTag| and |sourceItemTag|. Copy | 257 // Retain the source item given |menuTag| and |sourceItemTag|. Copy |
| 144 // the menu item given |menuTag| and |targetItemTag|. | 258 // the menu item given |menuTag| and |targetItemTag|. |
| 145 // This is useful when we want a doppelganger with a different source item. | 259 // This is useful when we want a doppelganger with a different source item. |
| 146 // For example, if there are conflicting key equivalents. | 260 // For example, if there are conflicting key equivalents. |
| 147 - (id)initWithMenuTag:(NSInteger)menuTag | 261 - (id)initWithMenuTag:(NSInteger)menuTag |
| 148 sourceItemTag:(NSInteger)sourceItemTag | 262 sourceItemTag:(NSInteger)sourceItemTag |
| 149 targetItemTag:(NSInteger)targetItemTag | 263 targetItemTag:(NSInteger)targetItemTag |
| 150 keyEquivalent:(NSString*)keyEquivalent; | 264 keyEquivalent:(NSString*)keyEquivalent; |
| 151 // Set the title using |resourceId_| and unset the source item's key equivalent. | 265 // Set the title using |resourceId_| and unset the source item's key equivalent. |
| 152 - (void)enableForApp:(const extensions::Extension*)app; | 266 - (void)enableForApp:(const Extension*)app; |
| 153 // Restore the source item's key equivalent. | 267 // Restore the source item's key equivalent. |
| 154 - (void)disable; | 268 - (void)disable; |
| 155 @end | 269 @end |
| 156 | 270 |
| 157 @implementation DoppelgangerMenuItem | 271 @implementation DoppelgangerMenuItem |
| 158 | 272 |
| 159 - (NSMenuItem*)menuItem { | 273 - (NSMenuItem*)menuItem { |
| 160 return menuItem_; | 274 return menuItem_; |
| 161 } | 275 } |
| 162 | 276 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 188 if ((self = [super init])) { | 302 if ((self = [super init])) { |
| 189 menuItem_.reset([GetItemByTag(menuTag, targetItemTag) copy]); | 303 menuItem_.reset([GetItemByTag(menuTag, targetItemTag) copy]); |
| 190 sourceItem_.reset([GetItemByTag(menuTag, sourceItemTag) retain]); | 304 sourceItem_.reset([GetItemByTag(menuTag, sourceItemTag) retain]); |
| 191 DCHECK(menuItem_); | 305 DCHECK(menuItem_); |
| 192 DCHECK(sourceItem_); | 306 DCHECK(sourceItem_); |
| 193 sourceKeyEquivalent_.reset([[sourceItem_ keyEquivalent] copy]); | 307 sourceKeyEquivalent_.reset([[sourceItem_ keyEquivalent] copy]); |
| 194 } | 308 } |
| 195 return self; | 309 return self; |
| 196 } | 310 } |
| 197 | 311 |
| 198 - (void)enableForApp:(const extensions::Extension*)app { | 312 - (void)enableForApp:(const Extension*)app { |
| 199 // It seems that two menu items that have the same key equivalent must also | 313 // 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 | 314 // 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). | 315 // 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 | 316 // 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. | 317 // key equivalent of the original items and restore them later. |
| 204 [sourceItem_ setKeyEquivalent:@""]; | 318 [sourceItem_ setKeyEquivalent:@""]; |
| 205 if (!resourceId_) | 319 if (!resourceId_) |
| 206 return; | 320 return; |
| 207 | 321 |
| 208 [menuItem_ setTitle:l10n_util::GetNSStringF(resourceId_, | 322 [menuItem_ setTitle:l10n_util::GetNSStringF(resourceId_, |
| 209 base::UTF8ToUTF16(app->name()))]; | 323 base::UTF8ToUTF16(app->name()))]; |
| 210 } | 324 } |
| 211 | 325 |
| 212 - (void)disable { | 326 - (void)disable { |
| 213 // Restore the keyboard shortcut to Chrome. This just needs to be set back to | 327 // 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 | 328 // 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. | 329 // overrides still work as they are based on the title of the menu item. |
| 216 [sourceItem_ setKeyEquivalent:sourceKeyEquivalent_]; | 330 [sourceItem_ setKeyEquivalent:sourceKeyEquivalent_]; |
| 217 } | 331 } |
| 218 | 332 |
| 219 @end | 333 @end |
| 220 | 334 |
| 221 @interface AppShimMenuController () | 335 @interface AppShimMenuController () |
| 222 // Construct the NSMenuItems for apps. | 336 // Construct the NSMenuItems for apps. |
| 223 - (void)buildAppMenuItems; | 337 - (void)buildAppMenuItems; |
| 224 // Register for NSWindow notifications. | 338 // Register for NSWindow notifications. |
| 225 - (void)registerEventHandlers; | 339 - (void)registerEventHandlers; |
| 226 // If the window is an app window, add or remove menu items. | 340 // If the window is an app window, add or remove menu items. |
| 227 - (void)windowMainStatusChanged:(NSNotification*)notification; | 341 - (void)windowMainStatusChanged:(NSNotification*)notification; |
| 342 // Called when |app| becomes the main window in the Chrome process. |
| 343 - (void)appBecameMain:(const Extension*)app; |
| 344 // Called when there is no main window, or if the main window is not an app. |
| 345 - (void)chromeBecameMain; |
| 228 // Add menu items for an app and hide Chrome menu items. | 346 // Add menu items for an app and hide Chrome menu items. |
| 229 - (void)addMenuItems:(const extensions::Extension*)app; | 347 - (void)addMenuItems:(const Extension*)app; |
| 230 // If the window belongs to the currently focused app, remove the menu items and | 348 // If the window belongs to the currently focused app, remove the menu items and |
| 231 // unhide Chrome menu items. | 349 // unhide Chrome menu items. |
| 232 - (void)removeMenuItems; | 350 - (void)removeMenuItems; |
| 233 // If the currently focused window belongs to a platform app, quit the app. | 351 // If the currently focused window belongs to a platform app, quit the app. |
| 234 - (void)quitCurrentPlatformApp; | 352 - (void)quitCurrentPlatformApp; |
| 235 // If the currently focused window belongs to a platform app, hide the app. | 353 // If the currently focused window belongs to a platform app, hide the app. |
| 236 - (void)hideCurrentPlatformApp; | 354 - (void)hideCurrentPlatformApp; |
| 237 // If the currently focused window belongs to a platform app, focus the app. | 355 // If the currently focused window belongs to a platform app, focus the app. |
| 238 - (void)focusCurrentPlatformApp; | 356 - (void)focusCurrentPlatformApp; |
| 239 @end | 357 @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 | 487 // A Yosemite AppKit bug causes this notification to be sent during the |
| 370 // -dealloc for a specific NSWindow. Any autoreleases sent to that window | 488 // -dealloc for a specific NSWindow. Any autoreleases sent to that window |
| 371 // must be drained before the window finishes -dealloc. In this method, an | 489 // must be drained before the window finishes -dealloc. In this method, an |
| 372 // autorelease is sent by the invocation of [NSApp windows]. | 490 // autorelease is sent by the invocation of [NSApp windows]. |
| 373 // http://crbug.com/406944. | 491 // http://crbug.com/406944. |
| 374 base::mac::ScopedNSAutoreleasePool pool; | 492 base::mac::ScopedNSAutoreleasePool pool; |
| 375 | 493 |
| 376 NSString* name = [notification name]; | 494 NSString* name = [notification name]; |
| 377 if ([name isEqualToString:NSWindowDidBecomeMainNotification]) { | 495 if ([name isEqualToString:NSWindowDidBecomeMainNotification]) { |
| 378 id window = [notification object]; | 496 id window = [notification object]; |
| 379 extensions::AppWindow* appWindow = | 497 bool is_browser; |
| 380 AppWindowRegistryUtil::GetAppWindowForNativeWindowAnyProfile( | 498 const Extension* extension = GetExtensionForNSWindow(window, &is_browser); |
| 381 window); | 499 // Ignore is_browser: if a window becomes main that does not belong to an |
| 382 | 500 // extension or browser, treat it the same as switching to a browser. |
| 383 const extensions::Extension* extension = NULL; | 501 if (extension) |
| 384 // If there is no corresponding AppWindow, this could be a hosted app, so | 502 [self appBecameMain:extension]; |
| 385 // check for a browser. | |
| 386 if (appWindow) | |
| 387 extension = appWindow->GetExtension(); | |
| 388 else | 503 else |
| 389 extension = apps::ExtensionAppShimHandler::MaybeGetAppForBrowser( | 504 [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]) { | 505 } else if ([name isEqualToString:NSWindowDidResignMainNotification]) { |
| 397 // When a window resigns main status, reset back to the Chrome menu. | 506 // When a window resigns main status, reset back to the Chrome menu. |
| 398 // In the past we've tried: | 507 // In the past we've tried: |
| 399 // - Only doing this when a window closes, but this would not be triggered | 508 // - 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 | 509 // when an app becomes hidden (Cmd+h), and there are no Chrome windows to |
| 401 // become main. | 510 // become main. |
| 402 // - Scanning [NSApp windows] to predict whether we could | 511 // - Scanning [NSApp windows] to predict whether we could |
| 403 // expect another Chrome window to become main, and skip the reset. However, | 512 // 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 | 513 // 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 | 514 // 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 | 515 // because they are given an elevated [NSWindow level]). Trying to handle |
| 407 // this case is not robust. | 516 // this case is not robust. |
| 408 // | 517 // |
| 409 // Unfortunately, resetting the menu to Chrome | 518 // Unfortunately, resetting the menu to Chrome |
| 410 // unconditionally means that if another packaged app window becomes key, | 519 // unconditionally means that if another packaged app window becomes key, |
| 411 // the menu will flicker. TODO(tapted): Investigate restoring the logic when | 520 // the menu will flicker. TODO(tapted): Investigate restoring the logic when |
| 412 // the panel code is removed. | 521 // the panel code is removed. |
| 413 [self removeMenuItems]; | 522 [self chromeBecameMain]; |
| 414 } else { | 523 } else { |
| 415 NOTREACHED(); | 524 NOTREACHED(); |
| 416 } | 525 } |
| 417 } | 526 } |
| 418 | 527 |
| 419 - (void)addMenuItems:(const extensions::Extension*)app { | 528 - (void)appBecameMain:(const Extension*)app { |
| 420 NSString* appId = base::SysUTF8ToNSString(app->id()); | 529 if (appId_ == app->id()) |
| 421 NSString* title = base::SysUTF8ToNSString(app->name()); | |
| 422 | |
| 423 if ([appId_ isEqualToString:appId]) | |
| 424 return; | 530 return; |
| 425 | 531 |
| 532 if (!appId_.empty()) |
| 533 [self removeMenuItems]; |
| 534 |
| 535 appId_ = app->id(); |
| 536 [self addMenuItems:app]; |
| 537 if (IsAppWindowCyclingEnabled()) { |
| 538 base::MessageLoop::current()->PostTask( |
| 539 FROM_HERE, base::Bind(&SetAppCyclesWindows, appId_, |
| 540 ++g_window_cycle_sequence_number)); |
| 541 } |
| 542 } |
| 543 |
| 544 - (void)chromeBecameMain { |
| 545 if (appId_.empty()) |
| 546 return; |
| 547 |
| 548 appId_.clear(); |
| 426 [self removeMenuItems]; | 549 [self removeMenuItems]; |
| 427 appId_.reset([appId copy]); | 550 if (IsAppWindowCyclingEnabled()) { |
| 551 base::MessageLoop::current()->PostTask( |
| 552 FROM_HERE, |
| 553 base::Bind(&SetChromeCyclesWindows, ++g_window_cycle_sequence_number)); |
| 554 } |
| 555 } |
| 556 |
| 557 - (void)addMenuItems:(const Extension*)app { |
| 558 DCHECK_EQ(appId_, app->id()); |
| 559 NSString* title = base::SysUTF8ToNSString(app->name()); |
| 428 | 560 |
| 429 // Hide Chrome menu items. | 561 // Hide Chrome menu items. |
| 430 NSMenu* mainMenu = [NSApp mainMenu]; | 562 NSMenu* mainMenu = [NSApp mainMenu]; |
| 431 for (NSMenuItem* item in [mainMenu itemArray]) | 563 for (NSMenuItem* item in [mainMenu itemArray]) |
| 432 [item setHidden:YES]; | 564 [item setHidden:YES]; |
| 433 | 565 |
| 434 [aboutDoppelganger_ enableForApp:app]; | 566 [aboutDoppelganger_ enableForApp:app]; |
| 435 [hideDoppelganger_ enableForApp:app]; | 567 [hideDoppelganger_ enableForApp:app]; |
| 436 [quitDoppelganger_ enableForApp:app]; | 568 [quitDoppelganger_ enableForApp:app]; |
| 437 [newDoppelganger_ enableForApp:app]; | 569 [newDoppelganger_ enableForApp:app]; |
| 438 [openDoppelganger_ enableForApp:app]; | 570 [openDoppelganger_ enableForApp:app]; |
| 439 [closeWindowDoppelganger_ enableForApp:app]; | 571 [closeWindowDoppelganger_ enableForApp:app]; |
| 440 | 572 |
| 441 [appMenuItem_ setTitle:appId]; | 573 [appMenuItem_ setTitle:base::SysUTF8ToNSString(appId_)]; |
| 442 [[appMenuItem_ submenu] setTitle:title]; | 574 [[appMenuItem_ submenu] setTitle:title]; |
| 443 | 575 |
| 444 [mainMenu addItem:appMenuItem_]; | 576 [mainMenu addItem:appMenuItem_]; |
| 445 [mainMenu addItem:fileMenuItem_]; | 577 [mainMenu addItem:fileMenuItem_]; |
| 446 | 578 |
| 447 SetItemWithTagVisible(editMenuItem_, | 579 SetItemWithTagVisible(editMenuItem_, |
| 448 IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE, | 580 IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE, |
| 449 app->is_hosted_app(), true); | 581 app->is_hosted_app(), true); |
| 450 SetItemWithTagVisible(editMenuItem_, IDC_FIND_MENU, app->is_hosted_app(), | 582 SetItemWithTagVisible(editMenuItem_, IDC_FIND_MENU, app->is_hosted_app(), |
| 451 false); | 583 false); |
| 452 [mainMenu addItem:editMenuItem_]; | 584 [mainMenu addItem:editMenuItem_]; |
| 453 | 585 |
| 454 if (app->is_hosted_app()) { | 586 if (app->is_hosted_app()) { |
| 455 [mainMenu addItem:viewMenuItem_]; | 587 [mainMenu addItem:viewMenuItem_]; |
| 456 [mainMenu addItem:historyMenuItem_]; | 588 [mainMenu addItem:historyMenuItem_]; |
| 457 } | 589 } |
| 458 [mainMenu addItem:windowMenuItem_]; | 590 [mainMenu addItem:windowMenuItem_]; |
| 459 } | 591 } |
| 460 | 592 |
| 461 - (void)removeMenuItems { | 593 - (void)removeMenuItems { |
| 462 if (!appId_) | |
| 463 return; | |
| 464 | |
| 465 appId_.reset(); | |
| 466 | |
| 467 NSMenu* mainMenu = [NSApp mainMenu]; | 594 NSMenu* mainMenu = [NSApp mainMenu]; |
| 468 [mainMenu removeItem:appMenuItem_]; | 595 [mainMenu removeItem:appMenuItem_]; |
| 469 [mainMenu removeItem:fileMenuItem_]; | 596 [mainMenu removeItem:fileMenuItem_]; |
| 470 if ([mainMenu indexOfItem:viewMenuItem_] >= 0) | 597 if ([mainMenu indexOfItem:viewMenuItem_] >= 0) |
| 471 [mainMenu removeItem:viewMenuItem_]; | 598 [mainMenu removeItem:viewMenuItem_]; |
| 472 if ([mainMenu indexOfItem:historyMenuItem_] >= 0) | 599 if ([mainMenu indexOfItem:historyMenuItem_] >= 0) |
| 473 [mainMenu removeItem:historyMenuItem_]; | 600 [mainMenu removeItem:historyMenuItem_]; |
| 474 [mainMenu removeItem:editMenuItem_]; | 601 [mainMenu removeItem:editMenuItem_]; |
| 475 [mainMenu removeItem:windowMenuItem_]; | 602 [mainMenu removeItem:windowMenuItem_]; |
| 476 | 603 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 487 } | 614 } |
| 488 | 615 |
| 489 - (void)quitCurrentPlatformApp { | 616 - (void)quitCurrentPlatformApp { |
| 490 extensions::AppWindow* appWindow = | 617 extensions::AppWindow* appWindow = |
| 491 AppWindowRegistryUtil::GetAppWindowForNativeWindowAnyProfile( | 618 AppWindowRegistryUtil::GetAppWindowForNativeWindowAnyProfile( |
| 492 [NSApp keyWindow]); | 619 [NSApp keyWindow]); |
| 493 if (appWindow) { | 620 if (appWindow) { |
| 494 apps::ExtensionAppShimHandler::QuitAppForWindow(appWindow); | 621 apps::ExtensionAppShimHandler::QuitAppForWindow(appWindow); |
| 495 } else { | 622 } else { |
| 496 Browser* browser = chrome::FindBrowserWithWindow([NSApp keyWindow]); | 623 Browser* browser = chrome::FindBrowserWithWindow([NSApp keyWindow]); |
| 497 const extensions::Extension* extension = | 624 const Extension* extension = |
| 498 apps::ExtensionAppShimHandler::MaybeGetAppForBrowser(browser); | 625 apps::ExtensionAppShimHandler::MaybeGetAppForBrowser(browser); |
| 499 if (extension) | 626 if (extension) |
| 500 apps::ExtensionAppShimHandler::QuitHostedAppForWindow(browser->profile(), | 627 apps::ExtensionAppShimHandler::QuitHostedAppForWindow(browser->profile(), |
| 501 extension->id()); | 628 extension->id()); |
| 502 } | 629 } |
| 503 } | 630 } |
| 504 | 631 |
| 505 - (void)hideCurrentPlatformApp { | 632 - (void)hideCurrentPlatformApp { |
| 506 extensions::AppWindow* appWindow = | 633 extensions::AppWindow* appWindow = |
| 507 AppWindowRegistryUtil::GetAppWindowForNativeWindowAnyProfile( | 634 AppWindowRegistryUtil::GetAppWindowForNativeWindowAnyProfile( |
| 508 [NSApp keyWindow]); | 635 [NSApp keyWindow]); |
| 509 if (appWindow) { | 636 if (appWindow) { |
| 510 apps::ExtensionAppShimHandler::HideAppForWindow(appWindow); | 637 apps::ExtensionAppShimHandler::HideAppForWindow(appWindow); |
| 511 } else { | 638 } else { |
| 512 Browser* browser = chrome::FindBrowserWithWindow([NSApp keyWindow]); | 639 Browser* browser = chrome::FindBrowserWithWindow([NSApp keyWindow]); |
| 513 const extensions::Extension* extension = | 640 const Extension* extension = |
| 514 apps::ExtensionAppShimHandler::MaybeGetAppForBrowser(browser); | 641 apps::ExtensionAppShimHandler::MaybeGetAppForBrowser(browser); |
| 515 if (extension) | 642 if (extension) |
| 516 apps::ExtensionAppShimHandler::HideHostedApp(browser->profile(), | 643 apps::ExtensionAppShimHandler::HideHostedApp(browser->profile(), |
| 517 extension->id()); | 644 extension->id()); |
| 518 } | 645 } |
| 519 } | 646 } |
| 520 | 647 |
| 521 - (void)focusCurrentPlatformApp { | 648 - (void)focusCurrentPlatformApp { |
| 522 extensions::AppWindow* appWindow = | 649 extensions::AppWindow* appWindow = |
| 523 AppWindowRegistryUtil::GetAppWindowForNativeWindowAnyProfile( | 650 AppWindowRegistryUtil::GetAppWindowForNativeWindowAnyProfile( |
| 524 [NSApp keyWindow]); | 651 [NSApp keyWindow]); |
| 525 if (appWindow) | 652 if (appWindow) |
| 526 apps::ExtensionAppShimHandler::FocusAppForWindow(appWindow); | 653 apps::ExtensionAppShimHandler::FocusAppForWindow(appWindow); |
| 527 } | 654 } |
| 528 | 655 |
| 529 @end | 656 @end |
| OLD | NEW |