| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/mac_util.h" | 9 #include "base/mac_util.h" |
| 10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
| 11 #include "base/sys_string_conversions.h" | 11 #include "base/sys_string_conversions.h" |
| 12 #include "chrome/app/chrome_dll_resource.h" | 12 #include "chrome/app/chrome_dll_resource.h" |
| 13 #include "chrome/browser/browser.h" | 13 #include "chrome/browser/browser.h" |
| 14 #include "chrome/browser/browser_init.h" | 14 #include "chrome/browser/browser_init.h" |
| 15 #include "chrome/browser/browser_list.h" | 15 #include "chrome/browser/browser_list.h" |
| 16 #include "chrome/browser/browser_process.h" | 16 #include "chrome/browser/browser_process.h" |
| 17 #include "chrome/browser/browser_shutdown.h" | 17 #include "chrome/browser/browser_shutdown.h" |
| 18 #include "chrome/browser/browser_window.h" | 18 #include "chrome/browser/browser_window.h" |
| 19 #import "chrome/browser/chrome_application_mac.h" |
| 19 #import "chrome/browser/cocoa/about_window_controller.h" | 20 #import "chrome/browser/cocoa/about_window_controller.h" |
| 20 #import "chrome/browser/cocoa/bookmark_menu_bridge.h" | 21 #import "chrome/browser/cocoa/bookmark_menu_bridge.h" |
| 21 #import "chrome/browser/cocoa/browser_window_cocoa.h" | 22 #import "chrome/browser/cocoa/browser_window_cocoa.h" |
| 22 #import "chrome/browser/cocoa/browser_window_controller.h" | 23 #import "chrome/browser/cocoa/browser_window_controller.h" |
| 23 #import "chrome/browser/cocoa/history_menu_bridge.h" | 24 #import "chrome/browser/cocoa/history_menu_bridge.h" |
| 24 #import "chrome/browser/cocoa/clear_browsing_data_controller.h" | 25 #import "chrome/browser/cocoa/clear_browsing_data_controller.h" |
| 25 #import "chrome/browser/cocoa/encoding_menu_controller_delegate_mac.h" | 26 #import "chrome/browser/cocoa/encoding_menu_controller_delegate_mac.h" |
| 26 #import "chrome/browser/cocoa/preferences_window_controller.h" | 27 #import "chrome/browser/cocoa/preferences_window_controller.h" |
| 27 #import "chrome/browser/cocoa/tab_strip_controller.h" | 28 #import "chrome/browser/cocoa/tab_strip_controller.h" |
| 28 #import "chrome/browser/cocoa/tab_window_controller.h" | 29 #import "chrome/browser/cocoa/tab_window_controller.h" |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 137 BrowserWindowController* controller = | 138 BrowserWindowController* controller = |
| 138 (BrowserWindowController*)[window->GetNativeHandle() windowController]; | 139 (BrowserWindowController*)[window->GetNativeHandle() windowController]; |
| 139 | 140 |
| 140 if (![controller shouldCloseWithOpenPerTabSheets]) | 141 if (![controller shouldCloseWithOpenPerTabSheets]) |
| 141 return NO; | 142 return NO; |
| 142 } | 143 } |
| 143 | 144 |
| 144 return YES; | 145 return YES; |
| 145 } | 146 } |
| 146 | 147 |
| 147 // We do not use the normal application teardown process -- this function is | |
| 148 // not called by the system but by us in |quit:|. |NSTerminateLater| is not a | |
| 149 // return value that is supported by |quit:|. | |
| 150 - (NSApplicationTerminateReply)applicationShouldTerminate: | 148 - (NSApplicationTerminateReply)applicationShouldTerminate: |
| 151 (NSApplication *)sender { | 149 (NSApplication *)sender { |
| 152 // Do not quit if any per-tab sheets are open, as required by | 150 // Do not quit if any per-tab sheets are open, as required by |
| 153 // GTMWindowSheetController. | 151 // GTMWindowSheetController. |
| 154 if (![self shouldQuitWithOpenPerTabSheets]) | 152 if (![self shouldQuitWithOpenPerTabSheets]) |
| 155 return NSTerminateCancel; | 153 return NSTerminateCancel; |
| 156 | 154 |
| 157 // Check for in-progress downloads, and prompt the user if they really want to | 155 // Check for in-progress downloads, and prompt the user if they really want to |
| 158 // quit (and thus cancel the downloads). | 156 // quit (and thus cancel the downloads). |
| 159 if (![self shouldQuitWithInProgressDownloads]) | 157 if (![self shouldQuitWithInProgressDownloads]) |
| 160 return NSTerminateCancel; | 158 return NSTerminateCancel; |
| 161 | 159 |
| 162 return NSTerminateNow; | 160 return NSTerminateNow; |
| 163 } | 161 } |
| 164 | 162 |
| 165 // Called when the app is shutting down. Clean-up as appropriate. | 163 // Called when the app is shutting down. Clean-up as appropriate. |
| 166 - (void)applicationWillTerminate:(NSNotification *)aNotification { | 164 - (void)applicationWillTerminate:(NSNotification *)aNotification { |
| 167 DCHECK(!BrowserList::HasBrowserWithProfile([self defaultProfile])); | 165 NSAppleEventManager* em = [NSAppleEventManager sharedAppleEventManager]; |
| 168 if (!BrowserList::HasBrowserWithProfile([self defaultProfile])) { | 166 [em removeEventHandlerForEventClass:kInternetEventClass |
| 169 // As we're shutting down, we need to nuke the TabRestoreService, which will | 167 andEventID:kAEGetURL]; |
| 170 // start the shutdown of the NavigationControllers and allow for proper | 168 [em removeEventHandlerForEventClass:'WWW!' |
| 171 // shutdown. If we don't do this chrome won't shutdown cleanly, and may end | 169 andEventID:'OURL']; |
| 172 // up crashing when some thread tries to use the IO thread (or another | 170 [em removeEventHandlerForEventClass:kCoreEventClass |
| 173 // thread) that is no longer valid. | 171 andEventID:kAEOpenDocuments]; |
| 174 [self defaultProfile]->ResetTabRestoreService(); | 172 |
| 175 } | 173 // Close all the windows. |
| 174 BrowserList::CloseAllBrowsers(true); |
| 175 |
| 176 // On Windows, this is done in Browser::OnWindowClosing, but that's not |
| 177 // appropriate on Mac since we don't shut down when we reach zero windows. |
| 178 browser_shutdown::OnShutdownStarting(browser_shutdown::BROWSER_EXIT); |
| 179 |
| 180 // Release the reference to the browser process. Once all the browsers get |
| 181 // dealloc'd, it will stop the RunLoop and fall back into main(). |
| 182 g_browser_process->ReleaseModule(); |
| 176 | 183 |
| 177 [[NSNotificationCenter defaultCenter] removeObserver:self]; | 184 [[NSNotificationCenter defaultCenter] removeObserver:self]; |
| 178 } | 185 } |
| 179 | 186 |
| 187 - (void)didEndMainMessageLoop { |
| 188 DCHECK(!BrowserList::HasBrowserWithProfile([self defaultProfile])); |
| 189 if (!BrowserList::HasBrowserWithProfile([self defaultProfile])) { |
| 190 // As we're shutting down, we need to nuke the TabRestoreService, which |
| 191 // will start the shutdown of the NavigationControllers and allow for |
| 192 // proper shutdown. If we don't do this, Chrome won't shut down cleanly, |
| 193 // and may end up crashing when some thread tries to use the IO thread (or |
| 194 // another thread) that is no longer valid. |
| 195 [self defaultProfile]->ResetTabRestoreService(); |
| 196 } |
| 197 } |
| 198 |
| 180 // Helper routine to get the window controller if the key window is a tabbed | 199 // Helper routine to get the window controller if the key window is a tabbed |
| 181 // window, or nil if not. Examples of non-tabbed windows are "about" or | 200 // window, or nil if not. Examples of non-tabbed windows are "about" or |
| 182 // "preferences". | 201 // "preferences". |
| 183 - (TabWindowController*)keyWindowTabController { | 202 - (TabWindowController*)keyWindowTabController { |
| 184 NSWindowController* keyWindowController = | 203 NSWindowController* keyWindowController = |
| 185 [[[NSApplication sharedApplication] keyWindow] windowController]; | 204 [[[NSApplication sharedApplication] keyWindow] windowController]; |
| 186 if ([keyWindowController isKindOfClass:[TabWindowController class]]) | 205 if ([keyWindowController isKindOfClass:[TabWindowController class]]) |
| 187 return (TabWindowController*)keyWindowController; | 206 return (TabWindowController*)keyWindowController; |
| 188 | 207 |
| 189 return nil; | 208 return nil; |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 373 | 392 |
| 374 // User wants to exit. | 393 // User wants to exit. |
| 375 return YES; | 394 return YES; |
| 376 } | 395 } |
| 377 } | 396 } |
| 378 | 397 |
| 379 // No profiles or active downloads found, okay to exit. | 398 // No profiles or active downloads found, okay to exit. |
| 380 return YES; | 399 return YES; |
| 381 } | 400 } |
| 382 | 401 |
| 383 // We can't use the standard terminate: method because it will abruptly exit | |
| 384 // the app and leave things on the stack in an unfinalized state. We need to | |
| 385 // post a quit message to our run loop so the stack can gracefully unwind. | |
| 386 - (IBAction)quit:(id)sender { | |
| 387 if ([self applicationShouldTerminate:NSApp] == NSTerminateCancel) | |
| 388 return; | |
| 389 | |
| 390 // TODO(pinkerton): | |
| 391 // since we have to roll it ourselves, ask the delegate (ourselves, really) | |
| 392 // if we should terminate. For example, we might not want to if the user | |
| 393 // has ongoing downloads or multiple windows/tabs open. However, this would | |
| 394 // require posting UI and may require spinning up another run loop to | |
| 395 // handle it. If it says to continue, post the quit message, otherwise | |
| 396 // go back to normal. | |
| 397 | |
| 398 NSAppleEventManager* em = [NSAppleEventManager sharedAppleEventManager]; | |
| 399 [em removeEventHandlerForEventClass:kInternetEventClass | |
| 400 andEventID:kAEGetURL]; | |
| 401 [em removeEventHandlerForEventClass:'WWW!' | |
| 402 andEventID:'OURL']; | |
| 403 [em removeEventHandlerForEventClass:kCoreEventClass | |
| 404 andEventID:kAEOpenDocuments]; | |
| 405 | |
| 406 // TODO(pinkerton): Not sure where this should live, including it here | |
| 407 // causes all sorts of asserts from the open renderers. On Windows, it | |
| 408 // lives in Browser::OnWindowClosing, but that's not appropriate on Mac | |
| 409 // since we don't shut down when we reach zero windows. | |
| 410 // browser_shutdown::OnShutdownStarting(browser_shutdown::WINDOW_CLOSE); | |
| 411 | |
| 412 // Close all the windows. | |
| 413 BrowserList::CloseAllBrowsers(true); | |
| 414 | |
| 415 // Release the reference to the browser process. Once all the browsers get | |
| 416 // dealloc'd, it will stop the RunLoop and fall back into main(). | |
| 417 g_browser_process->ReleaseModule(); | |
| 418 } | |
| 419 | |
| 420 // Called to determine if we should enable the "restore tab" menu item. | 402 // Called to determine if we should enable the "restore tab" menu item. |
| 421 // Checks with the TabRestoreService to see if there's anything there to | 403 // Checks with the TabRestoreService to see if there's anything there to |
| 422 // restore and returns YES if so. | 404 // restore and returns YES if so. |
| 423 - (BOOL)canRestoreTab { | 405 - (BOOL)canRestoreTab { |
| 424 TabRestoreService* service = [self defaultProfile]->GetTabRestoreService(); | 406 TabRestoreService* service = [self defaultProfile]->GetTabRestoreService(); |
| 425 return service && !service->entries().empty(); | 407 return service && !service->entries().empty(); |
| 426 } | 408 } |
| 427 | 409 |
| 428 // Called to validate menu items when there are no key windows. All the | 410 // Called to validate menu items when there are no key windows. All the |
| 429 // items we care about have been set with the |commandDispatch:| action and | 411 // items we care about have been set with the |commandDispatch:| action and |
| 430 // a target of FirstResponder in IB. If it's not one of those, let it | 412 // a target of FirstResponder in IB. If it's not one of those, let it |
| 431 // continue up the responder chain to be handled elsewhere. We pull out the | 413 // continue up the responder chain to be handled elsewhere. We pull out the |
| 432 // tag as the cross-platform constant to differentiate and dispatch the | 414 // tag as the cross-platform constant to differentiate and dispatch the |
| 433 // various commands. | 415 // various commands. |
| 434 - (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item { | 416 - (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item { |
| 435 SEL action = [item action]; | 417 SEL action = [item action]; |
| 436 BOOL enable = NO; | 418 BOOL enable = NO; |
| 437 if (action == @selector(commandDispatch:)) { | 419 if (action == @selector(commandDispatch:)) { |
| 438 NSInteger tag = [item tag]; | 420 NSInteger tag = [item tag]; |
| 439 if (menuState_->SupportsCommand(tag)) { | 421 if (menuState_->SupportsCommand(tag)) { |
| 440 switch (tag) { | 422 switch (tag) { |
| 441 case IDC_RESTORE_TAB: | 423 case IDC_RESTORE_TAB: |
| 442 enable = [self canRestoreTab]; | 424 enable = [self canRestoreTab]; |
| 443 break; | 425 break; |
| 444 default: | 426 default: |
| 445 enable = menuState_->IsCommandEnabled(tag) ? YES : NO; | 427 enable = menuState_->IsCommandEnabled(tag) ? YES : NO; |
| 446 } | 428 } |
| 447 } | 429 } |
| 448 } else if (action == @selector(quit:)) { | 430 } else if (action == @selector(terminate:)) { |
| 449 enable = YES; | 431 enable = YES; |
| 450 } else if (action == @selector(showPreferences:)) { | 432 } else if (action == @selector(showPreferences:)) { |
| 451 enable = YES; | 433 enable = YES; |
| 452 } else if (action == @selector(orderFrontStandardAboutPanel:)) { | 434 } else if (action == @selector(orderFrontStandardAboutPanel:)) { |
| 453 enable = YES; | 435 enable = YES; |
| 454 } | 436 } |
| 455 return enable; | 437 return enable; |
| 456 } | 438 } |
| 457 | 439 |
| 458 // Called when the user picks a menu item when there are no key windows. Calls | 440 // Called when the user picks a menu item when there are no key windows. Calls |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 688 action:@selector(commandDispatch:) | 670 action:@selector(commandDispatch:) |
| 689 keyEquivalent:@""] autorelease]; | 671 keyEquivalent:@""] autorelease]; |
| 690 [item setTarget:self]; | 672 [item setTarget:self]; |
| 691 [item setTag:IDC_NEW_INCOGNITO_WINDOW]; | 673 [item setTag:IDC_NEW_INCOGNITO_WINDOW]; |
| 692 [result addItem:item]; | 674 [result addItem:item]; |
| 693 | 675 |
| 694 return result; | 676 return result; |
| 695 } | 677 } |
| 696 | 678 |
| 697 @end | 679 @end |
| OLD | NEW |