| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/app_controller_mac.h" | 5 #import "chrome/browser/app_controller_mac.h" |
| 6 | 6 |
| 7 #include "base/auto_reset.h" | 7 #include "base/auto_reset.h" |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/file_path.h" | 9 #include "base/file_path.h" |
| 10 #include "base/mac/foundation_util.h" | 10 #include "base/mac/foundation_util.h" |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 202 addObserver:self | 202 addObserver:self |
| 203 selector:@selector(windowLayeringDidChange:) | 203 selector:@selector(windowLayeringDidChange:) |
| 204 name:NSWindowDidBecomeMainNotification | 204 name:NSWindowDidBecomeMainNotification |
| 205 object:nil]; | 205 object:nil]; |
| 206 [notificationCenter | 206 [notificationCenter |
| 207 addObserver:self | 207 addObserver:self |
| 208 selector:@selector(windowLayeringDidChange:) | 208 selector:@selector(windowLayeringDidChange:) |
| 209 name:NSWindowDidResignMainNotification | 209 name:NSWindowDidResignMainNotification |
| 210 object:nil]; | 210 object:nil]; |
| 211 | 211 |
| 212 // Register for a notification that the number of tabs changes in windows | |
| 213 // so we can adjust the close tab/window command keys. | |
| 214 [notificationCenter | |
| 215 addObserver:self | |
| 216 selector:@selector(tabsChanged:) | |
| 217 name:kTabStripNumberOfTabsChanged | |
| 218 object:nil]; | |
| 219 | |
| 220 // Set up the command updater for when there are no windows open | 212 // Set up the command updater for when there are no windows open |
| 221 [self initMenuState]; | 213 [self initMenuState]; |
| 222 | 214 |
| 223 // Activate (bring to foreground) if asked to do so. On | 215 // Activate (bring to foreground) if asked to do so. On |
| 224 // Windows this logic isn't necessary since | 216 // Windows this logic isn't necessary since |
| 225 // BrowserWindow::Activate() calls ::SetForegroundWindow() which is | 217 // BrowserWindow::Activate() calls ::SetForegroundWindow() which is |
| 226 // adequate. On Mac, BrowserWindow::Activate() calls -[NSWindow | 218 // adequate. On Mac, BrowserWindow::Activate() calls -[NSWindow |
| 227 // makeKeyAndOrderFront:] which does not activate the application | 219 // makeKeyAndOrderFront:] which does not activate the application |
| 228 // itself. | 220 // itself. |
| 229 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); | 221 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 352 // "preferences". | 344 // "preferences". |
| 353 - (TabWindowController*)mainWindowTabController { | 345 - (TabWindowController*)mainWindowTabController { |
| 354 NSWindowController* mainWindowController = | 346 NSWindowController* mainWindowController = |
| 355 [[NSApp mainWindow] windowController]; | 347 [[NSApp mainWindow] windowController]; |
| 356 if ([mainWindowController isKindOfClass:[TabWindowController class]]) | 348 if ([mainWindowController isKindOfClass:[TabWindowController class]]) |
| 357 return (TabWindowController*)mainWindowController; | 349 return (TabWindowController*)mainWindowController; |
| 358 | 350 |
| 359 return nil; | 351 return nil; |
| 360 } | 352 } |
| 361 | 353 |
| 362 // If the window has tabs, make "close window" be cmd-shift-w, otherwise leave | |
| 363 // it as the normal cmd-w. Capitalization of the key equivalent affects whether | |
| 364 // the shift modifer is used. | |
| 365 - (void)adjustCloseWindowMenuItemKeyEquivalent:(BOOL)inHaveTabs { | |
| 366 [closeWindowMenuItem_ setKeyEquivalent:(inHaveTabs ? @"W" : @"w")]; | |
| 367 [closeWindowMenuItem_ setKeyEquivalentModifierMask:NSCommandKeyMask]; | |
| 368 } | |
| 369 | |
| 370 // If the window has tabs, make "close tab" take over cmd-w, otherwise it | |
| 371 // shouldn't have any key-equivalent because it should be disabled. | |
| 372 - (void)adjustCloseTabMenuItemKeyEquivalent:(BOOL)hasTabs { | |
| 373 if (hasTabs) { | |
| 374 [closeTabMenuItem_ setKeyEquivalent:@"w"]; | |
| 375 [closeTabMenuItem_ setKeyEquivalentModifierMask:NSCommandKeyMask]; | |
| 376 } else { | |
| 377 [closeTabMenuItem_ setKeyEquivalent:@""]; | |
| 378 [closeTabMenuItem_ setKeyEquivalentModifierMask:0]; | |
| 379 } | |
| 380 } | |
| 381 | |
| 382 // Explicitly remove any command-key equivalents from the close tab/window | |
| 383 // menus so that nothing can go haywire if we get a user action during pending | |
| 384 // updates. | |
| 385 - (void)clearCloseMenuItemKeyEquivalents { | |
| 386 [closeTabMenuItem_ setKeyEquivalent:@""]; | |
| 387 [closeTabMenuItem_ setKeyEquivalentModifierMask:0]; | |
| 388 [closeWindowMenuItem_ setKeyEquivalent:@""]; | |
| 389 [closeWindowMenuItem_ setKeyEquivalentModifierMask:0]; | |
| 390 } | |
| 391 | |
| 392 // See if we have a window with tabs open, and adjust the key equivalents for | |
| 393 // Close Tab/Close Window accordingly. | |
| 394 - (void)fixCloseMenuItemKeyEquivalents { | |
| 395 fileMenuUpdatePending_ = NO; | |
| 396 TabWindowController* tabController = [self keyWindowTabController]; | |
| 397 if (!tabController && ![NSApp keyWindow]) { | |
| 398 // There might be a small amount of time where there is no key window, | |
| 399 // so just use our main browser window if there is one. | |
| 400 tabController = [self mainWindowTabController]; | |
| 401 } | |
| 402 BOOL windowWithMultipleTabs = | |
| 403 (tabController && [tabController numberOfTabs] > 1); | |
| 404 [self adjustCloseWindowMenuItemKeyEquivalent:windowWithMultipleTabs]; | |
| 405 [self adjustCloseTabMenuItemKeyEquivalent:windowWithMultipleTabs]; | |
| 406 } | |
| 407 | |
| 408 // Fix up the "close tab/close window" command-key equivalents. We do this | |
| 409 // after a delay to ensure that window layer state has been set by the time | |
| 410 // we do the enabling. This should only be called on the main thread, code that | |
| 411 // calls this (even as a side-effect) from other threads needs to be fixed. | |
| 412 - (void)delayedFixCloseMenuItemKeyEquivalents { | |
| 413 DCHECK([NSThread isMainThread]); | |
| 414 if (!fileMenuUpdatePending_) { | |
| 415 // The OS prefers keypresses to timers, so it's possible that a cmd-w | |
| 416 // can sneak in before this timer fires. In order to prevent that from | |
| 417 // having any bad consequences, just clear the keys combos altogether. They | |
| 418 // will be reset when the timer eventually fires. | |
| 419 if ([NSThread isMainThread]) { | |
| 420 fileMenuUpdatePending_ = YES; | |
| 421 [self clearCloseMenuItemKeyEquivalents]; | |
| 422 [self performSelector:@selector(fixCloseMenuItemKeyEquivalents) | |
| 423 withObject:nil | |
| 424 afterDelay:0]; | |
| 425 } else { | |
| 426 // This shouldn't be happening, but if it does, force it to the main | |
| 427 // thread to avoid dropping the update. Don't mess with | |
| 428 // |fileMenuUpdatePending_| as it's not expected to be threadsafe and | |
| 429 // there could be a race between the selector finishing and setting the | |
| 430 // flag. | |
| 431 [self | |
| 432 performSelectorOnMainThread:@selector(fixCloseMenuItemKeyEquivalents) | |
| 433 withObject:nil | |
| 434 waitUntilDone:NO]; | |
| 435 } | |
| 436 } | |
| 437 } | |
| 438 | |
| 439 // Called when we get a notification about the window layering changing to | 354 // Called when we get a notification about the window layering changing to |
| 440 // update the UI based on the new main window. | 355 // update the UI based on the new main window. |
| 441 - (void)windowLayeringDidChange:(NSNotification*)notify { | 356 - (void)windowLayeringDidChange:(NSNotification*)notify { |
| 442 [self delayedFixCloseMenuItemKeyEquivalents]; | |
| 443 | |
| 444 if ([notify name] == NSWindowDidResignKeyNotification) { | 357 if ([notify name] == NSWindowDidResignKeyNotification) { |
| 445 // If a window is closed, this notification is fired but |[NSApp keyWindow]| | 358 // If a window is closed, this notification is fired but |[NSApp keyWindow]| |
| 446 // returns nil regardless of whether any suitable candidates for the key | 359 // returns nil regardless of whether any suitable candidates for the key |
| 447 // window remain. It seems that the new key window for the app is not set | 360 // window remain. It seems that the new key window for the app is not set |
| 448 // until after this notification is fired, so a check is performed after the | 361 // until after this notification is fired, so a check is performed after the |
| 449 // run loop is allowed to spin. | 362 // run loop is allowed to spin. |
| 450 [self performSelector:@selector(checkForAnyKeyWindows) | 363 [self performSelector:@selector(checkForAnyKeyWindows) |
| 451 withObject:nil | 364 withObject:nil |
| 452 afterDelay:0.0]; | 365 afterDelay:0.0]; |
| 453 } | 366 } |
| 454 } | 367 } |
| 455 | 368 |
| 456 - (void)checkForAnyKeyWindows { | 369 - (void)checkForAnyKeyWindows { |
| 457 if ([NSApp keyWindow]) | 370 if ([NSApp keyWindow]) |
| 458 return; | 371 return; |
| 459 | 372 |
| 460 NotificationService::current()->Notify( | 373 NotificationService::current()->Notify( |
| 461 NotificationType::NO_KEY_WINDOW, | 374 NotificationType::NO_KEY_WINDOW, |
| 462 NotificationService::AllSources(), | 375 NotificationService::AllSources(), |
| 463 NotificationService::NoDetails()); | 376 NotificationService::NoDetails()); |
| 464 } | 377 } |
| 465 | 378 |
| 466 // Called when the number of tabs changes in one of the browser windows. The | |
| 467 // object is the tab strip controller, but we don't currently care. | |
| 468 - (void)tabsChanged:(NSNotification*)notify { | |
| 469 // We don't need to do this on a delay, as in the method above, because the | |
| 470 // window layering isn't changing. As a result, there's no chance that a | |
| 471 // different window will sneak in as the key window and cause the problems | |
| 472 // we hacked around above by clearing the key equivalents. | |
| 473 [self fixCloseMenuItemKeyEquivalents]; | |
| 474 } | |
| 475 | |
| 476 // If the auto-update interval is not set, make it 5 hours. | 379 // If the auto-update interval is not set, make it 5 hours. |
| 477 // This code is specific to Mac Chrome Dev Channel. | 380 // This code is specific to Mac Chrome Dev Channel. |
| 478 // Placed here for 2 reasons: | 381 // Placed here for 2 reasons: |
| 479 // 1) Same spot as other Pref stuff | 382 // 1) Same spot as other Pref stuff |
| 480 // 2) Try and be friendly by keeping this after app launch | 383 // 2) Try and be friendly by keeping this after app launch |
| 481 // TODO(jrg): remove once we go Beta. | 384 // TODO(jrg): remove once we go Beta. |
| 482 - (void)setUpdateCheckInterval { | 385 - (void)setUpdateCheckInterval { |
| 483 #if defined(GOOGLE_CHROME_BUILD) | 386 #if defined(GOOGLE_CHROME_BUILD) |
| 484 CFStringRef app = (CFStringRef)@"com.google.Keystone.Agent"; | 387 CFStringRef app = (CFStringRef)@"com.google.Keystone.Agent"; |
| 485 CFStringRef checkInterval = (CFStringRef)@"checkInterval"; | 388 CFStringRef checkInterval = (CFStringRef)@"checkInterval"; |
| (...skipping 704 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1190 | 1093 |
| 1191 } // namespace browser | 1094 } // namespace browser |
| 1192 | 1095 |
| 1193 namespace app_controller_mac { | 1096 namespace app_controller_mac { |
| 1194 | 1097 |
| 1195 bool IsOpeningNewWindow() { | 1098 bool IsOpeningNewWindow() { |
| 1196 return g_is_opening_new_window; | 1099 return g_is_opening_new_window; |
| 1197 } | 1100 } |
| 1198 | 1101 |
| 1199 } // namespace app_controller_mac | 1102 } // namespace app_controller_mac |
| OLD | NEW |