Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(178)

Side by Side Diff: chrome/browser/app_controller_mac.mm

Issue 201121: Chrome should shut down cleanly when quit from the Dock icon menu, during... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 11 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « chrome/browser/app_controller_mac.h ('k') | chrome/browser/automation/automation_provider_list_mac.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698