| Index: chrome/browser/chrome_browser_application_mac.mm
|
| diff --git a/chrome/browser/chrome_browser_application_mac.mm b/chrome/browser/chrome_browser_application_mac.mm
|
| index f373e11d3cfe1edcfd86876d212299444711e517..07aac53f61336ed25515423373492810fa6012f3 100644
|
| --- a/chrome/browser/chrome_browser_application_mac.mm
|
| +++ b/chrome/browser/chrome_browser_application_mac.mm
|
| @@ -1,4 +1,4 @@
|
| -// Copyright (c) 2009 The Chromium Authors. All rights reserved.
|
| +// Copyright (c) 2010 The Chromium Authors. All rights reserved.
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| @@ -9,6 +9,7 @@
|
| #import "base/scoped_nsobject.h"
|
| #import "base/sys_string_conversions.h"
|
| #import "chrome/app/breakpad_mac.h"
|
| +#import "chrome/browser/app_controller_mac.h"
|
| #import "chrome/browser/cocoa/objc_method_swizzle.h"
|
|
|
| // The implementation of NSExceptions break various assumptions in the
|
| @@ -120,6 +121,10 @@ void Terminate() {
|
| [NSApp terminate:nil];
|
| }
|
|
|
| +void CancelTerminate() {
|
| + [NSApp cancelTerminate:nil];
|
| +}
|
| +
|
| } // namespace chrome_browser_application_mac
|
|
|
| namespace {
|
| @@ -161,56 +166,80 @@ BOOL SwizzleNSExceptionInit() {
|
| return [super init];
|
| }
|
|
|
| -// -terminate: is the entry point for orderly "quit" operations in Cocoa.
|
| -// This includes the application menu's quit menu item and keyboard
|
| -// equivalent, the application's dock icon menu's quit menu item, "quit" (not
|
| -// "force quit") in the Activity Monitor, and quits triggered by user logout
|
| -// and system restart and shutdown.
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +// HISTORICAL COMMENT (by viettrungluu, from
|
| +// http://codereview.chromium.org/1520006 with mild editing):
|
| +//
|
| +// A quick summary of the state of things (before the changes to shutdown):
|
| +//
|
| +// Currently, we are totally hosed (put in a bad state in which Cmd-W does the
|
| +// wrong thing, and which will probably eventually lead to a crash) if we begin
|
| +// quitting but termination is aborted for some reason.
|
| +//
|
| +// I currently know of two ways in which termination can be aborted:
|
| +// (1) Common case: a window has an onbeforeunload handler which pops up a
|
| +// "leave web page" dialog, and the user answers "no, don't leave".
|
| +// (2) Uncommon case: popups are enabled (in Content Settings, i.e., the popup
|
| +// blocker is disabled), and some nasty web page pops up a new window on
|
| +// closure.
|
| +//
|
| +// I don't know of other ways in which termination can be aborted, but they may
|
| +// exist (or may be added in the future, for that matter).
|
| //
|
| -// The default NSApplication -terminate: implementation will end the process
|
| -// by calling exit(), and thus never leave the main run loop. This is
|
| -// unsuitable for Chrome's purposes. Chrome depends on leaving the main
|
| -// run loop to perform a proper orderly shutdown. This design is ingrained
|
| -// in the application and the assumptions that its code makes, and is
|
| -// entirely reasonable and works well on other platforms, but it's not
|
| -// compatible with the standard Cocoa quit sequence. Quits originated from
|
| -// within the application can be redirected to not use -terminate:, but
|
| -// quits from elsewhere cannot be.
|
| +// My CL [see above] does the following:
|
| +// a. Should prevent being put in a bad state (which breaks Cmd-W and leads to
|
| +// crash) under all circumstances.
|
| +// b. Should completely handle (1) properly.
|
| +// c. Doesn't (yet) handle (2) properly and puts it in a weird state (but not
|
| +// that bad).
|
| +// d. Any other ways of aborting termination would put it in that weird state.
|
| //
|
| -// To allow the Cocoa-based Chrome to support the standard Cocoa -terminate:
|
| -// interface, and allow all quits to cause Chrome to shut down properly
|
| -// regardless of their origin, -terminate: is overriden. The custom
|
| -// -terminate: does not end the application with exit(). Instead, it simply
|
| -// returns after posting the normal NSApplicationWillTerminateNotification
|
| -// notification. The application is responsible for exiting on its own in
|
| -// whatever way it deems appropriate. In Chrome's case, the main run loop will
|
| -// end and the applicaton will exit by returning from main().
|
| +// c. can be fixed by having the global flag reset on browser creation or
|
| +// similar (and doing so might also fix some possible d.'s as well). I haven't
|
| +// done this yet since I haven't thought about it carefully and since it's a
|
| +// corner case.
|
| //
|
| -// This implementation of -terminate: is scaled back and is not as
|
| -// fully-featured as the implementation in NSApplication, nor is it a direct
|
| -// drop-in replacement -terminate: in most applications. It is
|
| -// purpose-specific to Chrome.
|
| +// The weird state: a state in which closing the last window quits the browser.
|
| +// This might be a bit annoying, but it's not dangerous in any way.
|
| +////////////////////////////////////////////////////////////////////////////////
|
| +
|
| +// |-terminate:| is the entry point for orderly "quit" operations in Cocoa. This
|
| +// includes the application menu's quit menu item and keyboard equivalent, the
|
| +// application's dock icon menu's quit menu item, "quit" (not "force quit") in
|
| +// the Activity Monitor, and quits triggered by user logout and system restart
|
| +// and shutdown.
|
| +//
|
| +// The default |-terminate:| implementation ends the process by calling exit(),
|
| +// and thus never leaves the main run loop. This is unsuitable for Chrome since
|
| +// Chrome depends on leaving the main run loop to perform an orderly shutdown.
|
| +// We support the normal |-terminate:| interface by overriding the default
|
| +// implementation. Our implementation, which is very specific to the needs of
|
| +// Chrome, works by asking the application delegate to terminate using its
|
| +// |-tryToTerminateApplication:| method.
|
| +//
|
| +// |-tryToTerminateApplication:| differs from the standard
|
| +// |-applicationShouldTerminate:| in that no special event loop is run in the
|
| +// case that immediate termination is not possible (e.g., if dialog boxes
|
| +// allowing the user to cancel have to be shown). Instead, this method sets a
|
| +// flag and tries to close all browsers. This flag causes the closure of the
|
| +// final browser window to begin actual tear-down of the application.
|
| +// Termination is cancelled by resetting this flag. The standard
|
| +// |-applicationShouldTerminate:| is not supported, and code paths leading to it
|
| +// must be redirected.
|
| - (void)terminate:(id)sender {
|
| - NSApplicationTerminateReply shouldTerminate = NSTerminateNow;
|
| - SEL selector = @selector(applicationShouldTerminate:);
|
| - if ([[self delegate] respondsToSelector:selector])
|
| - shouldTerminate = [[self delegate] applicationShouldTerminate:self];
|
| -
|
| - // If shouldTerminate is NSTerminateLater, the application is expected to
|
| - // call -replyToApplicationShouldTerminate: when it knows whether or not it
|
| - // should terminate. If the argument is YES,
|
| - // -replyToApplicationShouldTerminate: will call -terminate:. This will
|
| - // result in another call to the delegate's -applicationShouldTerminate:,
|
| - // which would be expected to return NSTerminateNow at that point.
|
| - if (shouldTerminate != NSTerminateNow)
|
| - return;
|
| -
|
| - [[NSNotificationCenter defaultCenter]
|
| - postNotificationName:NSApplicationWillTerminateNotification
|
| - object:self];
|
| -
|
| - // Return, don't exit. The application is responsible for exiting on its
|
| - // own.
|
| + AppController* appController = static_cast<AppController*>([NSApp delegate]);
|
| + if ([appController tryToTerminateApplication:self]) {
|
| + [[NSNotificationCenter defaultCenter]
|
| + postNotificationName:NSApplicationWillTerminateNotification
|
| + object:self];
|
| + }
|
| +
|
| + // Return, don't exit. The application is responsible for exiting on its own.
|
| +}
|
| +
|
| +- (void)cancelTerminate:(id)sender {
|
| + AppController* appController = static_cast<AppController*>([NSApp delegate]);
|
| + [appController stopTryingToTerminateApplication:self];
|
| }
|
|
|
| - (BOOL)sendAction:(SEL)anAction to:(id)aTarget from:(id)sender {
|
|
|