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 |