| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "app/l10n_util_mac.h" | 7 #include "app/l10n_util_mac.h" |
| 8 #include "base/auto_reset.h" | 8 #include "base/auto_reset.h" |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/mac_util.h" | 10 #include "base/mac_util.h" |
| 11 #include "base/message_loop.h" | 11 #include "base/message_loop.h" |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 131 | 131 |
| 132 // Sync after a delay avoid I/O contention on startup; 1500 ms is plenty. | 132 // Sync after a delay avoid I/O contention on startup; 1500 ms is plenty. |
| 133 ChromeThread::PostDelayedTask(ChromeThread::FILE, FROM_HERE, | 133 ChromeThread::PostDelayedTask(ChromeThread::FILE, FROM_HERE, |
| 134 new PrefsSyncTask(), 1500); | 134 new PrefsSyncTask(), 1500); |
| 135 } | 135 } |
| 136 | 136 |
| 137 } // anonymous namespace | 137 } // anonymous namespace |
| 138 | 138 |
| 139 @interface AppController(Private) | 139 @interface AppController(Private) |
| 140 - (void)initMenuState; | 140 - (void)initMenuState; |
| 141 - (void)handleQuitEvent:(NSAppleEventDescriptor*)event |
| 142 withReply:(NSAppleEventDescriptor*)reply; |
| 141 - (void)openUrls:(const std::vector<GURL>&)urls; | 143 - (void)openUrls:(const std::vector<GURL>&)urls; |
| 142 - (void)getUrl:(NSAppleEventDescriptor*)event | 144 - (void)getUrl:(NSAppleEventDescriptor*)event |
| 143 withReply:(NSAppleEventDescriptor*)reply; | 145 withReply:(NSAppleEventDescriptor*)reply; |
| 144 - (void)windowLayeringDidChange:(NSNotification*)inNotification; | 146 - (void)windowLayeringDidChange:(NSNotification*)inNotification; |
| 145 - (BOOL)userWillWaitForInProgressDownloads:(int)downloadCount; | 147 - (BOOL)userWillWaitForInProgressDownloads:(int)downloadCount; |
| 146 - (BOOL)shouldQuitWithInProgressDownloads; | 148 - (BOOL)shouldQuitWithInProgressDownloads; |
| 147 - (void)showPreferencesWindow:(id)sender | 149 - (void)showPreferencesWindow:(id)sender |
| 148 page:(OptionsPage)page | 150 page:(OptionsPage)page |
| 149 profile:(Profile*)profile; | 151 profile:(Profile*)profile; |
| 150 @end | 152 @end |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 210 // BrowserWindow::Activate() calls ::SetForegroundWindow() which is | 212 // BrowserWindow::Activate() calls ::SetForegroundWindow() which is |
| 211 // adequate. On Mac, BrowserWindow::Activate() calls -[NSWindow | 213 // adequate. On Mac, BrowserWindow::Activate() calls -[NSWindow |
| 212 // makeKeyAndOrderFront:] which does not activate the application | 214 // makeKeyAndOrderFront:] which does not activate the application |
| 213 // itself. | 215 // itself. |
| 214 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); | 216 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); |
| 215 if (parsed_command_line.HasSwitch(switches::kActivateOnLaunch)) { | 217 if (parsed_command_line.HasSwitch(switches::kActivateOnLaunch)) { |
| 216 [NSApp activateIgnoringOtherApps:YES]; | 218 [NSApp activateIgnoringOtherApps:YES]; |
| 217 } | 219 } |
| 218 } | 220 } |
| 219 | 221 |
| 222 // (NSApplicationDelegate protocol) This is the Apple-approved place to override |
| 223 // the default handlers. |
| 224 - (void)applicationWillFinishLaunching:(NSNotification*)notification { |
| 225 NSAppleEventManager* em = [NSAppleEventManager sharedAppleEventManager]; |
| 226 [em setEventHandler:self |
| 227 andSelector:@selector(handleQuitEvent:withReply:) |
| 228 forEventClass:kCoreEventClass |
| 229 andEventID:kAEQuitApplication]; |
| 230 } |
| 231 |
| 232 // (NSApplicationDelegate protocol) Our mechanism for application termination |
| 233 // does not go through |-applicationShouldTerminate:|, so it should not be |
| 234 // called. In a release build, cancelling termination will prevent a crash (but |
| 235 // if things go really wrong, the user may have to force-terminate the |
| 236 // application). |
| 220 - (NSApplicationTerminateReply)applicationShouldTerminate: | 237 - (NSApplicationTerminateReply)applicationShouldTerminate: |
| 221 (NSApplication *)sender { | 238 (NSApplication*)sender { |
| 222 // Check for in-progress downloads, and prompt the user if they really want to | 239 NOTREACHED(); |
| 223 // quit (and thus cancel the downloads). | 240 return NSTerminateCancel; |
| 224 if (![self shouldQuitWithInProgressDownloads]) | 241 } |
| 225 return NSTerminateCancel; | |
| 226 | 242 |
| 227 return NSTerminateNow; | 243 - (BOOL)tryToTerminateApplication:(NSApplication*)app { |
| 244 // Set the state to "trying to quit", so that closing all browser windows will |
| 245 // lead to termination. |
| 246 browser_shutdown::SetTryingToQuit(true); |
| 247 |
| 248 // TODO(viettrungluu): Remove Apple Event handlers here? (It's safe to leave |
| 249 // them in, but I'm not sure about UX; we'd also want to disable other things |
| 250 // though.) http://crbug.com/40861 |
| 251 |
| 252 if (!BrowserList::size()) |
| 253 return YES; |
| 254 |
| 255 // Try to close all the windows. |
| 256 BrowserList::CloseAllBrowsers(true); |
| 257 |
| 258 return NO; |
| 259 } |
| 260 |
| 261 - (void)stopTryingToTerminateApplication:(NSApplication*)app { |
| 262 if (browser_shutdown::IsTryingToQuit()) { |
| 263 // Reset the "trying to quit" state, so that closing all browser windows |
| 264 // will no longer lead to termination. |
| 265 browser_shutdown::SetTryingToQuit(false); |
| 266 |
| 267 // TODO(viettrungluu): Were we to remove Apple Event handlers above, we |
| 268 // would have to reinstall them here. http://crbug.com/40861 |
| 269 } |
| 228 } | 270 } |
| 229 | 271 |
| 230 // Called when the app is shutting down. Clean-up as appropriate. | 272 // Called when the app is shutting down. Clean-up as appropriate. |
| 231 - (void)applicationWillTerminate:(NSNotification *)aNotification { | 273 - (void)applicationWillTerminate:(NSNotification*)aNotification { |
| 232 NSAppleEventManager* em = [NSAppleEventManager sharedAppleEventManager]; | 274 NSAppleEventManager* em = [NSAppleEventManager sharedAppleEventManager]; |
| 233 [em removeEventHandlerForEventClass:kInternetEventClass | 275 [em removeEventHandlerForEventClass:kInternetEventClass |
| 234 andEventID:kAEGetURL]; | 276 andEventID:kAEGetURL]; |
| 235 [em removeEventHandlerForEventClass:'WWW!' | 277 [em removeEventHandlerForEventClass:'WWW!' |
| 236 andEventID:'OURL']; | 278 andEventID:'OURL']; |
| 237 | 279 |
| 238 // Close all the windows. | 280 // There better be no browser windows left at this point. |
| 239 BrowserList::CloseAllBrowsers(true); | 281 CHECK_EQ(BrowserList::size(), 0u); |
| 240 | |
| 241 // On Windows, this is done in Browser::OnWindowClosing, but that's not | |
| 242 // appropriate on Mac since we don't shut down when we reach zero windows. | |
| 243 browser_shutdown::OnShutdownStarting(browser_shutdown::BROWSER_EXIT); | |
| 244 | 282 |
| 245 // Release the reference to the browser process. Once all the browsers get | 283 // Release the reference to the browser process. Once all the browsers get |
| 246 // dealloc'd, it will stop the RunLoop and fall back into main(). | 284 // dealloc'd, it will stop the RunLoop and fall back into main(). |
| 247 g_browser_process->ReleaseModule(); | 285 g_browser_process->ReleaseModule(); |
| 248 | 286 |
| 249 // Close these off if they have open windows. | 287 // Close these off if they have open windows. |
| 250 [prefsController_ close]; | 288 [prefsController_ close]; |
| 251 [aboutController_ close]; | 289 [aboutController_ close]; |
| 252 | 290 |
| 253 [[NSNotificationCenter defaultCenter] removeObserver:self]; | 291 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 388 // 1) Same spot as other Pref stuff | 426 // 1) Same spot as other Pref stuff |
| 389 // 2) Try and be friendly by keeping this after app launch | 427 // 2) Try and be friendly by keeping this after app launch |
| 390 // TODO(jrg): remove once we go Beta. | 428 // TODO(jrg): remove once we go Beta. |
| 391 - (void)setUpdateCheckInterval { | 429 - (void)setUpdateCheckInterval { |
| 392 #if defined(GOOGLE_CHROME_BUILD) | 430 #if defined(GOOGLE_CHROME_BUILD) |
| 393 CFStringRef app = (CFStringRef)@"com.google.Keystone.Agent"; | 431 CFStringRef app = (CFStringRef)@"com.google.Keystone.Agent"; |
| 394 CFStringRef checkInterval = (CFStringRef)@"checkInterval"; | 432 CFStringRef checkInterval = (CFStringRef)@"checkInterval"; |
| 395 CFPropertyListRef plist = CFPreferencesCopyAppValue(checkInterval, app); | 433 CFPropertyListRef plist = CFPreferencesCopyAppValue(checkInterval, app); |
| 396 if (!plist) { | 434 if (!plist) { |
| 397 const float fiveHoursInSeconds = 5.0 * 60.0 * 60.0; | 435 const float fiveHoursInSeconds = 5.0 * 60.0 * 60.0; |
| 398 NSNumber *value = [NSNumber numberWithFloat:fiveHoursInSeconds]; | 436 NSNumber* value = [NSNumber numberWithFloat:fiveHoursInSeconds]; |
| 399 CFPreferencesSetAppValue(checkInterval, value, app); | 437 CFPreferencesSetAppValue(checkInterval, value, app); |
| 400 CFPreferencesAppSynchronize(app); | 438 CFPreferencesAppSynchronize(app); |
| 401 } | 439 } |
| 402 #endif | 440 #endif |
| 403 } | 441 } |
| 404 | 442 |
| 405 // This is called after profiles have been loaded and preferences registered. | 443 // This is called after profiles have been loaded and preferences registered. |
| 406 // It is safe to access the default profile here. | 444 // It is safe to access the default profile here. |
| 407 - (void)applicationDidFinishLaunching:(NSNotification*)notify { | 445 - (void)applicationDidFinishLaunching:(NSNotification*)notify { |
| 408 // Hold an extra ref to the BrowserProcess singleton so it doesn't go away | 446 // Hold an extra ref to the BrowserProcess singleton so it doesn't go away |
| 409 // when all the browser windows get closed. We'll release it on quit which | 447 // when all the browser windows get closed. We'll release it on quit which |
| 410 // will be the signal to exit. | 448 // will be the signal to exit. |
| 411 DCHECK(g_browser_process); | 449 DCHECK(g_browser_process); |
| 412 g_browser_process->AddRefModule(); | 450 g_browser_process->AddRefModule(); |
| 413 | 451 |
| 414 bookmarkMenuBridge_.reset(new BookmarkMenuBridge([self defaultProfile])); | 452 bookmarkMenuBridge_.reset(new BookmarkMenuBridge([self defaultProfile])); |
| 415 historyMenuBridge_.reset(new HistoryMenuBridge([self defaultProfile])); | 453 historyMenuBridge_.reset(new HistoryMenuBridge([self defaultProfile])); |
| 416 | 454 |
| 417 [self setUpdateCheckInterval]; | 455 [self setUpdateCheckInterval]; |
| 418 | 456 |
| 419 // Build up the encoding menu, the order of the items differs based on the | 457 // Build up the encoding menu, the order of the items differs based on the |
| 420 // current locale (see http://crbug.com/7647 for details). | 458 // current locale (see http://crbug.com/7647 for details). |
| 421 // We need a valid g_browser_process to get the profile which is why we can't | 459 // We need a valid g_browser_process to get the profile which is why we can't |
| 422 // call this from awakeFromNib. | 460 // call this from awakeFromNib. |
| 423 NSMenu* view_menu = [[[NSApp mainMenu] itemWithTag:IDC_VIEW_MENU] submenu]; | 461 NSMenu* view_menu = [[[NSApp mainMenu] itemWithTag:IDC_VIEW_MENU] submenu]; |
| 424 NSMenuItem* encoding_menu_item = [view_menu itemWithTag:IDC_ENCODING_MENU]; | 462 NSMenuItem* encoding_menu_item = [view_menu itemWithTag:IDC_ENCODING_MENU]; |
| 425 NSMenu *encoding_menu = [encoding_menu_item submenu]; | 463 NSMenu* encoding_menu = [encoding_menu_item submenu]; |
| 426 EncodingMenuControllerDelegate::BuildEncodingMenu([self defaultProfile], | 464 EncodingMenuControllerDelegate::BuildEncodingMenu([self defaultProfile], |
| 427 encoding_menu); | 465 encoding_menu); |
| 428 | 466 |
| 429 // Since Chrome is localized to more languages than the OS, tell Cocoa which | 467 // Since Chrome is localized to more languages than the OS, tell Cocoa which |
| 430 // menu is the Help so it can add the search item to it. | 468 // menu is the Help so it can add the search item to it. |
| 431 if (helpMenu_ && [NSApp respondsToSelector:@selector(setHelpMenu:)]) | 469 if (helpMenu_ && [NSApp respondsToSelector:@selector(setHelpMenu:)]) |
| 432 [NSApp setHelpMenu:helpMenu_]; | 470 [NSApp setHelpMenu:helpMenu_]; |
| 433 | 471 |
| 434 // Record the path to the (browser) app bundle; this is used by the app mode | 472 // Record the path to the (browser) app bundle; this is used by the app mode |
| 435 // shim. | 473 // shim. |
| (...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 795 } | 833 } |
| 796 | 834 |
| 797 - (Profile*)defaultProfile { | 835 - (Profile*)defaultProfile { |
| 798 // TODO(jrg): Find a better way to get the "default" profile. | 836 // TODO(jrg): Find a better way to get the "default" profile. |
| 799 if (g_browser_process->profile_manager()) | 837 if (g_browser_process->profile_manager()) |
| 800 return *g_browser_process->profile_manager()->begin(); | 838 return *g_browser_process->profile_manager()->begin(); |
| 801 | 839 |
| 802 return NULL; | 840 return NULL; |
| 803 } | 841 } |
| 804 | 842 |
| 843 // (Private) Never call |-applicationShouldTerminate:|; just make everything go |
| 844 // through |-terminate:|. |
| 845 - (void)handleQuitEvent:(NSAppleEventDescriptor*)event |
| 846 withReply:(NSAppleEventDescriptor*)reply { |
| 847 [NSApp terminate:nil]; |
| 848 } |
| 849 |
| 805 // Various methods to open URLs that we get in a native fashion. We use | 850 // Various methods to open URLs that we get in a native fashion. We use |
| 806 // BrowserInit here because on the other platforms, URLs to open come through | 851 // BrowserInit here because on the other platforms, URLs to open come through |
| 807 // the ProcessSingleton, and it calls BrowserInit. It's best to bottleneck the | 852 // the ProcessSingleton, and it calls BrowserInit. It's best to bottleneck the |
| 808 // openings through that for uniform handling. | 853 // openings through that for uniform handling. |
| 809 | 854 |
| 810 - (void)openUrls:(const std::vector<GURL>&)urls { | 855 - (void)openUrls:(const std::vector<GURL>&)urls { |
| 811 // If the browser hasn't started yet, just queue up the URLs. | 856 // If the browser hasn't started yet, just queue up the URLs. |
| 812 if (!startupComplete_) { | 857 if (!startupComplete_) { |
| 813 startupUrls_.insert(startupUrls_.end(), urls.begin(), urls.end()); | 858 startupUrls_.insert(startupUrls_.end(), urls.begin(), urls.end()); |
| 814 return; | 859 return; |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 974 [appController showPreferencesWindow:nil page:page profile:profile]; | 1019 [appController showPreferencesWindow:nil page:page profile:profile]; |
| 975 } | 1020 } |
| 976 | 1021 |
| 977 namespace app_controller_mac { | 1022 namespace app_controller_mac { |
| 978 | 1023 |
| 979 bool IsOpeningNewWindow() { | 1024 bool IsOpeningNewWindow() { |
| 980 return g_is_opening_new_window; | 1025 return g_is_opening_new_window; |
| 981 } | 1026 } |
| 982 | 1027 |
| 983 } // namespace app_controller_mac | 1028 } // namespace app_controller_mac |
| OLD | NEW |