diff options
author | mark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-15 21:36:11 +0000 |
---|---|---|
committer | mark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-15 21:36:11 +0000 |
commit | 3b6aa8b6ca80f33b3a5af490dc29e65f6d9a6dc4 (patch) | |
tree | cb3a85d96d53560f62c0b094ebbc02c97a07fc81 | |
parent | 262c3f2ea113d3fb4ffe535226cf172a6a108e82 (diff) | |
download | chromium_src-3b6aa8b6ca80f33b3a5af490dc29e65f6d9a6dc4.zip chromium_src-3b6aa8b6ca80f33b3a5af490dc29e65f6d9a6dc4.tar.gz chromium_src-3b6aa8b6ca80f33b3a5af490dc29e65f6d9a6dc4.tar.bz2 |
Chrome should shut down cleanly when quit from the Dock icon menu, during
user logout, and during system restart and shutdown.
MainMenu.xib changes (because you're not expected to parse nibs yourself):
- The quit menu item's action is changed from the AppController object's
-quit: method (which no longer exists) to the application object's
-terminate: method (the Cocoa standard).
- The application and owner object types are changed from NSApplication to
CrApplication.
- The application menu name is changed from Chromium to
^IDS_SHORT_PRODUCT_NAME. Cocoa doesn't use this anyway, it gets replaced
at runtime with the localized value of CFBundleName, but we shouldn't have
branding-specific strings in our nibs.
BUG=18078
TEST=Use Chrome for a while, quit it from the Dock icon menu, and relaunch.
You should NOT see the "Google Chrome didn't shut down correctly" info bar.
Review URL: http://codereview.chromium.org/201121
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@26269 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/app/app-Info.plist | 2 | ||||
-rw-r--r-- | chrome/app/nibs/MainMenu.xib | 60 | ||||
-rw-r--r-- | chrome/browser/app_controller_mac.h | 3 | ||||
-rw-r--r-- | chrome/browser/app_controller_mac.mm | 78 | ||||
-rw-r--r-- | chrome/browser/automation/automation_provider_list_mac.mm | 4 | ||||
-rw-r--r-- | chrome/browser/browser_main.cc | 2 | ||||
-rw-r--r-- | chrome/browser/browser_main.h | 2 | ||||
-rw-r--r-- | chrome/browser/browser_main_gtk.cc | 2 | ||||
-rw-r--r-- | chrome/browser/browser_main_mac.mm | 38 | ||||
-rw-r--r-- | chrome/browser/browser_main_win.cc | 2 | ||||
-rw-r--r-- | chrome/browser/chrome_application_mac.h | 13 | ||||
-rw-r--r-- | chrome/browser/chrome_application_mac.mm | 61 | ||||
-rw-r--r-- | chrome/chrome.gyp | 2 |
13 files changed, 169 insertions, 100 deletions
diff --git a/chrome/app/app-Info.plist b/chrome/app/app-Info.plist index 7ca9989..5390a70 100644 --- a/chrome/app/app-Info.plist +++ b/chrome/app/app-Info.plist @@ -187,7 +187,7 @@ <key>NSMainNibFile</key> <string>MainMenu</string> <key>NSPrincipalClass</key> - <string>NSApplication</string> + <string>CrApplication</string> <key>UTExportedTypeDeclarations</key> <array> <dict> diff --git a/chrome/app/nibs/MainMenu.xib b/chrome/app/nibs/MainMenu.xib index dbc39c5..55d33e2 100644 --- a/chrome/app/nibs/MainMenu.xib +++ b/chrome/app/nibs/MainMenu.xib @@ -8,7 +8,7 @@ <string key="IBDocument.HIToolboxVersion">353.00</string> <object class="NSMutableArray" key="IBDocument.EditedObjectIDs"> <bool key="EncodedWithXMLCoder">YES</bool> - <integer value="81"/> + <integer value="29"/> </object> <object class="NSArray" key="IBDocument.PluginDependencies"> <bool key="EncodedWithXMLCoder">YES</bool> @@ -26,13 +26,13 @@ <object class="NSMutableArray" key="IBDocument.RootObjects" id="1048"> <bool key="EncodedWithXMLCoder">YES</bool> <object class="NSCustomObject" id="1021"> - <string key="NSClassName">NSApplication</string> + <string key="NSClassName">CrApplication</string> </object> <object class="NSCustomObject" id="1014"> <string key="NSClassName">FirstResponder</string> </object> <object class="NSCustomObject" id="1050"> - <string key="NSClassName">NSApplication</string> + <string key="NSClassName">CrApplication</string> </object> <object class="NSCustomObject" id="163992474"> <string key="NSClassName">NSFontManager</string> @@ -43,7 +43,7 @@ <bool key="EncodedWithXMLCoder">YES</bool> <object class="NSMenuItem" id="694149608"> <reference key="NSMenu" ref="649796088"/> - <string key="NSTitle">Chromium</string> + <string key="NSTitle">^IDS_SHORT_PRODUCT_NAME</string> <string key="NSKeyEquiv"/> <int key="NSMnemonicLoc">2147483647</int> <object class="NSCustomResource" key="NSOnImage" id="353210768"> @@ -56,7 +56,7 @@ </object> <string key="NSAction">submenuAction:</string> <object class="NSMenu" key="NSSubmenu" id="110575045"> - <string key="NSTitle">Chromium</string> + <string key="NSTitle">^IDS_SHORT_PRODUCT_NAME</string> <object class="NSMutableArray" key="NSMenuItems"> <bool key="EncodedWithXMLCoder">YES</bool> <object class="NSMenuItem" id="238522557"> @@ -1232,14 +1232,6 @@ </object> <object class="IBConnectionRecord"> <object class="IBActionConnection" key="connection"> - <string key="label">quit:</string> - <reference key="source" ref="168151378"/> - <reference key="destination" ref="632727374"/> - </object> - <int key="connectionID">489</int> - </object> - <object class="IBConnectionRecord"> - <object class="IBActionConnection" key="connection"> <string key="label">commandDispatch:</string> <reference key="source" ref="1014"/> <reference key="destination" ref="705341025"/> @@ -1534,13 +1526,21 @@ </object> <int key="connectionID">646</int> </object> + <object class="IBConnectionRecord"> + <object class="IBActionConnection" key="connection"> + <string key="label">terminate:</string> + <reference key="source" ref="1050"/> + <reference key="destination" ref="632727374"/> + </object> + <int key="connectionID">647</int> + </object> </object> <object class="IBMutableOrderedSet" key="objectRecords"> <object class="NSArray" key="orderedObjects"> <bool key="EncodedWithXMLCoder">YES</bool> <object class="IBObjectRecord"> <int key="objectID">0</int> - <object class="NSArray" key="object" id="276974574"> + <object class="NSArray" key="object" id="470821800"> <bool key="EncodedWithXMLCoder">YES</bool> </object> <reference key="children" ref="1048"/> @@ -1549,19 +1549,19 @@ <object class="IBObjectRecord"> <int key="objectID">-2</int> <reference key="object" ref="1021"/> - <reference key="parent" ref="276974574"/> + <reference key="parent" ref="470821800"/> <string type="base64-UTF8" key="objectName">RmlsZSdzIE93bmVyA</string> </object> <object class="IBObjectRecord"> <int key="objectID">-1</int> <reference key="object" ref="1014"/> - <reference key="parent" ref="276974574"/> + <reference key="parent" ref="470821800"/> <string key="objectName">First Responder</string> </object> <object class="IBObjectRecord"> <int key="objectID">-3</int> <reference key="object" ref="1050"/> - <reference key="parent" ref="276974574"/> + <reference key="parent" ref="470821800"/> <string key="objectName">Application</string> </object> <object class="IBObjectRecord"> @@ -1578,7 +1578,7 @@ <reference ref="586577488"/> <reference ref="445514911"/> </object> - <reference key="parent" ref="276974574"/> + <reference key="parent" ref="470821800"/> <string key="objectName">Main Menu</string> </object> <object class="IBObjectRecord"> @@ -2013,7 +2013,7 @@ <object class="IBObjectRecord"> <int key="objectID">373</int> <reference key="object" ref="163992474"/> - <reference key="parent" ref="276974574"/> + <reference key="parent" ref="470821800"/> </object> <object class="IBObjectRecord"> <int key="objectID">449</int> @@ -2104,7 +2104,7 @@ <object class="IBObjectRecord"> <int key="objectID">483</int> <reference key="object" ref="168151378"/> - <reference key="parent" ref="276974574"/> + <reference key="parent" ref="470821800"/> </object> <object class="IBObjectRecord"> <int key="objectID">492</int> @@ -2315,7 +2315,7 @@ <object class="IBObjectRecord"> <int key="objectID">641</int> <reference key="object" ref="979722531"/> - <reference key="parent" ref="276974574"/> + <reference key="parent" ref="470821800"/> </object> </object> </object> @@ -2622,7 +2622,7 @@ <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <reference ref="9"/> <string>{{525, 802}, {197, 73}}</string> - <string>{{0, 482}, {1437, 20}}</string> + <string>{{0, 337}, {1578, 20}}</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <reference ref="9"/> <string>{74, 862}</string> @@ -2687,7 +2687,7 @@ <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <reference ref="9"/> - <string>{{222, 551}, {385, 213}}</string> + <string>{{12, 124}, {385, 213}}</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <reference ref="9"/> <string>{{23, 794}, {245, 183}}</string> @@ -2714,7 +2714,7 @@ <reference ref="9"/> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <reference ref="9"/> - <string>{{106, 179}, {353, 303}}</string> + <string>{{106, 34}, {350, 303}}</string> <string>com.apple.InterfaceBuilder.CocoaPlugin</string> <reference ref="9"/> <string>{{323, 672}, {199, 203}}</string> @@ -2746,7 +2746,7 @@ </object> </object> <nil key="sourceID"/> - <int key="maxID">646</int> + <int key="maxID">647</int> </object> <object class="IBClassDescriber" key="IBDocument.Classes"> <object class="NSMutableArray" key="referencedPartialClassDescriptions"> @@ -2759,14 +2759,12 @@ <object class="NSMutableArray" key="dict.sortedKeys"> <bool key="EncodedWithXMLCoder">YES</bool> <string>orderFrontStandardAboutPanel:</string> - <string>quit:</string> <string>showPreferences:</string> </object> <object class="NSMutableArray" key="dict.values"> <bool key="EncodedWithXMLCoder">YES</bool> <string>id</string> <string>id</string> - <string>id</string> </object> </object> <object class="NSMutableDictionary" key="outlets"> @@ -2796,6 +2794,14 @@ </object> </object> <object class="IBPartialClassDescription"> + <string key="className">CrApplication</string> + <string key="superclassName">NSApplication</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBProjectSource</string> + <string key="minorKey">browser/chrome_application_mac.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> <string key="className">DownloadShelfController</string> <string key="superclassName">NSViewController</string> <object class="NSMutableDictionary" key="actions"> diff --git a/chrome/browser/app_controller_mac.h b/chrome/browser/app_controller_mac.h index 091891c..cb3785f 100644 --- a/chrome/browser/app_controller_mac.h +++ b/chrome/browser/app_controller_mac.h @@ -14,6 +14,7 @@ @class AboutWindowController; class BookmarkMenuBridge; class CommandUpdater; +@class CrApplication; class GURL; class HistoryMenuBridge; @class PreferencesWindowController; @@ -45,7 +46,7 @@ class Profile; BOOL fileMenuUpdatePending_; // ensure we only do this once per notificaion. } -- (IBAction)quit:(id)sender; +- (void)didEndMainMessageLoop; - (Profile*)defaultProfile; // Show the preferences window, or bring it to the front if it's already diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm index b7a062f..ccfb0eb 100644 --- a/chrome/browser/app_controller_mac.mm +++ b/chrome/browser/app_controller_mac.mm @@ -16,6 +16,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_shutdown.h" #include "chrome/browser/browser_window.h" +#import "chrome/browser/chrome_application_mac.h" #import "chrome/browser/cocoa/about_window_controller.h" #import "chrome/browser/cocoa/bookmark_menu_bridge.h" #import "chrome/browser/cocoa/browser_window_cocoa.h" @@ -144,9 +145,6 @@ return YES; } -// We do not use the normal application teardown process -- this function is -// not called by the system but by us in |quit:|. |NSTerminateLater| is not a -// return value that is supported by |quit:|. - (NSApplicationTerminateReply)applicationShouldTerminate: (NSApplication *)sender { // Do not quit if any per-tab sheets are open, as required by @@ -164,17 +162,38 @@ // Called when the app is shutting down. Clean-up as appropriate. - (void)applicationWillTerminate:(NSNotification *)aNotification { + NSAppleEventManager* em = [NSAppleEventManager sharedAppleEventManager]; + [em removeEventHandlerForEventClass:kInternetEventClass + andEventID:kAEGetURL]; + [em removeEventHandlerForEventClass:'WWW!' + andEventID:'OURL']; + [em removeEventHandlerForEventClass:kCoreEventClass + andEventID:kAEOpenDocuments]; + + // Close all the windows. + BrowserList::CloseAllBrowsers(true); + + // On Windows, this is done in Browser::OnWindowClosing, but that's not + // appropriate on Mac since we don't shut down when we reach zero windows. + browser_shutdown::OnShutdownStarting(browser_shutdown::BROWSER_EXIT); + + // Release the reference to the browser process. Once all the browsers get + // dealloc'd, it will stop the RunLoop and fall back into main(). + g_browser_process->ReleaseModule(); + + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)didEndMainMessageLoop { DCHECK(!BrowserList::HasBrowserWithProfile([self defaultProfile])); if (!BrowserList::HasBrowserWithProfile([self defaultProfile])) { - // As we're shutting down, we need to nuke the TabRestoreService, which will - // start the shutdown of the NavigationControllers and allow for proper - // shutdown. If we don't do this chrome won't shutdown cleanly, and may end - // up crashing when some thread tries to use the IO thread (or another - // thread) that is no longer valid. + // As we're shutting down, we need to nuke the TabRestoreService, which + // will start the shutdown of the NavigationControllers and allow for + // proper shutdown. If we don't do this, Chrome won't shut down cleanly, + // and may end up crashing when some thread tries to use the IO thread (or + // another thread) that is no longer valid. [self defaultProfile]->ResetTabRestoreService(); } - - [[NSNotificationCenter defaultCenter] removeObserver:self]; } // Helper routine to get the window controller if the key window is a tabbed @@ -380,43 +399,6 @@ return YES; } -// We can't use the standard terminate: method because it will abruptly exit -// the app and leave things on the stack in an unfinalized state. We need to -// post a quit message to our run loop so the stack can gracefully unwind. -- (IBAction)quit:(id)sender { - if ([self applicationShouldTerminate:NSApp] == NSTerminateCancel) - return; - - // TODO(pinkerton): - // since we have to roll it ourselves, ask the delegate (ourselves, really) - // if we should terminate. For example, we might not want to if the user - // has ongoing downloads or multiple windows/tabs open. However, this would - // require posting UI and may require spinning up another run loop to - // handle it. If it says to continue, post the quit message, otherwise - // go back to normal. - - NSAppleEventManager* em = [NSAppleEventManager sharedAppleEventManager]; - [em removeEventHandlerForEventClass:kInternetEventClass - andEventID:kAEGetURL]; - [em removeEventHandlerForEventClass:'WWW!' - andEventID:'OURL']; - [em removeEventHandlerForEventClass:kCoreEventClass - andEventID:kAEOpenDocuments]; - - // TODO(pinkerton): Not sure where this should live, including it here - // causes all sorts of asserts from the open renderers. On Windows, it - // lives in Browser::OnWindowClosing, but that's not appropriate on Mac - // since we don't shut down when we reach zero windows. - // browser_shutdown::OnShutdownStarting(browser_shutdown::WINDOW_CLOSE); - - // Close all the windows. - BrowserList::CloseAllBrowsers(true); - - // Release the reference to the browser process. Once all the browsers get - // dealloc'd, it will stop the RunLoop and fall back into main(). - g_browser_process->ReleaseModule(); -} - // Called to determine if we should enable the "restore tab" menu item. // Checks with the TabRestoreService to see if there's anything there to // restore and returns YES if so. @@ -445,7 +427,7 @@ enable = menuState_->IsCommandEnabled(tag) ? YES : NO; } } - } else if (action == @selector(quit:)) { + } else if (action == @selector(terminate:)) { enable = YES; } else if (action == @selector(showPreferences:)) { enable = YES; diff --git a/chrome/browser/automation/automation_provider_list_mac.mm b/chrome/browser/automation/automation_provider_list_mac.mm index 4d408fd..2cfdb3f 100644 --- a/chrome/browser/automation/automation_provider_list_mac.mm +++ b/chrome/browser/automation/automation_provider_list_mac.mm @@ -4,10 +4,10 @@ #include "chrome/browser/automation/automation_provider_list.h" -#import "chrome/browser/app_controller_mac.h" +#import <AppKit/AppKit.h> void AutomationProviderList::OnLastProviderRemoved() { // We need to explicitly quit the application here because on Mac // the controller holds an additional reference to g_browser_process. - [[NSApp delegate] quit:nil]; + [NSApp terminate:nil]; } diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc index c20c7a3..97b589a 100644 --- a/chrome/browser/browser_main.cc +++ b/chrome/browser/browser_main.cc @@ -836,7 +836,7 @@ int BrowserMain(const MainFunctionParams& parameters) { process_singleton.Cleanup(); - Platform::WillTerminate(); + Platform::DidEndMainMessageLoop(); if (metrics) metrics->Stop(); diff --git a/chrome/browser/browser_main.h b/chrome/browser/browser_main.h index 2044670..44bc6ab 100644 --- a/chrome/browser/browser_main.h +++ b/chrome/browser/browser_main.h @@ -18,7 +18,7 @@ void WillInitializeMainMessageLoop(const MainFunctionParams& parameters); // Perform platform-specific work that needs to be done after the main event // loop has ended. -void WillTerminate(); +void DidEndMainMessageLoop(); // Records the conditions that can prevent Breakpad from generating and // sending crash reports. The presence of a Breakpad handler (after diff --git a/chrome/browser/browser_main_gtk.cc b/chrome/browser/browser_main_gtk.cc index 6bfa6de..beeb702 100644 --- a/chrome/browser/browser_main_gtk.cc +++ b/chrome/browser/browser_main_gtk.cc @@ -13,7 +13,7 @@ namespace Platform { void WillInitializeMainMessageLoop(const MainFunctionParams& parameters) { } -void WillTerminate() { +void DidEndMainMessageLoop() { } void RecordBreakpadStatusUMA(MetricsService* metrics) { diff --git a/chrome/browser/browser_main_mac.mm b/chrome/browser/browser_main_mac.mm index ca6d346..8ed837f 100644 --- a/chrome/browser/browser_main_mac.mm +++ b/chrome/browser/browser_main_mac.mm @@ -11,25 +11,33 @@ #include "base/debug_util.h" #include "chrome/app/breakpad_mac.h" #import "chrome/app/keystone_glue.h" +#import "chrome/browser/app_controller_mac.h" #include "chrome/browser/browser_main_win.h" +#import "chrome/browser/chrome_application_mac.h" #include "chrome/browser/metrics/metrics_service.h" #include "chrome/common/main_function_params.h" #include "chrome/common/result_codes.h" namespace Platform { -// Perform any platform-specific work that needs to be done before the main -// message loop is created and initialized. -// -// For Mac, this involves telling Cooca to finish its initalization, which we -// want to do manually instead of calling NSApplicationMain(). The primary -// reason is that NSAM() never returns, which would leave all the objects -// currently on the stack in scoped_ptrs hanging and never cleaned up. We then -// load the main nib directly. The main event loop is run from common code using -// the MessageLoop API, which works out ok for us because it's a wrapper around +// Tell Cooca to finish its initalization, which we want to do manually +// instead of calling NSApplicationMain(). The primary reason is that NSAM() +// never returns, which would leave all the objects currently on the stack +// in scoped_ptrs hanging and never cleaned up. We then load the main nib +// directly. The main event loop is run from common code using the +// MessageLoop API, which works out ok for us because it's a wrapper around // CFRunLoop. void WillInitializeMainMessageLoop(const MainFunctionParams& parameters) { - [NSApplication sharedApplication]; + // Initialize NSApplication using the custom subclass. Check whether NSApp + // was already initialized using another class, because that would break + // some things. + [CrApplication sharedApplication]; + if (![NSApp isKindOfClass:[CrApplication class]]) { + LOG(ERROR) << "NSApp should be of type CrApplication, not " + << [[NSApp className] UTF8String]; + DCHECK(false) << "NSApp is of wrong type"; + } + // Before we load the nib, we need to start up the resource bundle so we have // the strings avaiable for localization. if (!parameters.ui_task) { @@ -46,13 +54,9 @@ void WillInitializeMainMessageLoop(const MainFunctionParams& parameters) { [[KeystoneGlue defaultKeystoneGlue] registerWithKeystone]; } -// Perform platform-specific work that needs to be done after the main event -// loop has ended. We need to send the notifications that Cooca normally would -// telling everyone the app is about to end. -void WillTerminate() { - [[NSNotificationCenter defaultCenter] - postNotificationName:NSApplicationWillTerminateNotification - object:NSApp]; +void DidEndMainMessageLoop() { + AppController* appController = [NSApp delegate]; + [appController didEndMainMessageLoop]; } void RecordBreakpadStatusUMA(MetricsService* metrics) { diff --git a/chrome/browser/browser_main_win.cc b/chrome/browser/browser_main_win.cc index b59572f..dca1bba 100644 --- a/chrome/browser/browser_main_win.cc +++ b/chrome/browser/browser_main_win.cc @@ -33,7 +33,7 @@ namespace Platform { void WillInitializeMainMessageLoop(const MainFunctionParams& parameters) { } -void WillTerminate() { +void DidEndMainMessageLoop() { } void RecordBreakpadStatusUMA(MetricsService* metrics) { diff --git a/chrome/browser/chrome_application_mac.h b/chrome/browser/chrome_application_mac.h new file mode 100644 index 0000000..b09af38 --- /dev/null +++ b/chrome/browser/chrome_application_mac.h @@ -0,0 +1,13 @@ +// Copyright (c) 2009 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. + +#ifndef CHROME_BROWSER_CHROME_APPLICATION_MAC_H_ +#define CHROME_BROWSER_CHROME_APPLICATION_MAC_H_ + +#import <AppKit/AppKit.h> + +@interface CrApplication : NSApplication +@end + +#endif // CHROME_BROWSER_CHROME_APPLICATION_MAC_H_ diff --git a/chrome/browser/chrome_application_mac.mm b/chrome/browser/chrome_application_mac.mm new file mode 100644 index 0000000..8c7d860 --- /dev/null +++ b/chrome/browser/chrome_application_mac.mm @@ -0,0 +1,61 @@ +// Copyright (c) 2009 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. + +#import "chrome/browser/chrome_application_mac.h" + +@implementation CrApplication + +// -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 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. +// +// 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(). +// +// 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. +- (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. +} + +@end diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 5066b65..a9fce17 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -845,6 +845,8 @@ 'browser/character_encoding.h', 'browser/child_process_security_policy.cc', 'browser/child_process_security_policy.h', + 'browser/chrome_application_mac.h', + 'browser/chrome_application_mac.mm', 'browser/chrome_plugin_browsing_context.cc', 'browser/chrome_plugin_browsing_context.h', 'browser/chrome_plugin_host.cc', |