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 |