diff options
-rw-r--r-- | chrome/app/generated_resources.grd | 10 | ||||
-rw-r--r-- | chrome/app/nibs/ConfirmQuitPanel.xib | 333 | ||||
-rw-r--r-- | chrome/browser/about_flags.cc | 7 | ||||
-rw-r--r-- | chrome/browser/app_controller_mac.mm | 93 | ||||
-rw-r--r-- | chrome/browser/cocoa/confirm_quit_panel_controller.h | 24 | ||||
-rw-r--r-- | chrome/browser/cocoa/confirm_quit_panel_controller.mm | 69 | ||||
-rw-r--r-- | chrome/browser/cocoa/confirm_quit_panel_controller_unittest.mm | 26 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 3 | ||||
-rw-r--r-- | chrome/chrome_dll.gypi | 1 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 1 | ||||
-rw-r--r-- | chrome/common/chrome_switches.cc | 3 | ||||
-rw-r--r-- | chrome/common/chrome_switches.h | 1 |
12 files changed, 571 insertions, 0 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 1981024..90bb121 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -4100,6 +4100,12 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_FLAGS_DNS_SERVER_DESCRIPTION" desc=""> User specified DNS server, which Chrome will use for DNS resolutions rather than the system defaults. </message> + <message name="IDS_FLAGS_CONFIRM_TO_QUIT_NAME" desc="Name of the 'Confirm to Quit' lab."> + Confirm to Quit + </message> + <message name="IDS_FLAGS_CONFIRM_TO_QUIT_DESCRIPTION" desc="Description of the 'Confirm to Quit' lab."> + Receive a prompt before quitting to confirm the action. + </message> <!-- Instant --> <message name="IDS_INSTANT_OPT_IN_ENABLE" desc="Button shown in the omnibox dropdown for enabling instant"> @@ -4629,6 +4635,10 @@ Keep your key file in a safe place. You will need it to create new versions of y Cancel Anyway </message> + <!-- Confirm to quit panel --> + <message name="IDS_CONFIRM_TO_QUIT_DESCRIPTION" desc="Instructions for how the user should confirm quitting."> + Hold ⌘Q to Quit. + </message> <!-- Importer Lock Dialog --> <message name="IDS_IMPORTER_LOCK_TITLE" desc="Dialog title for importer lock dialog"> diff --git a/chrome/app/nibs/ConfirmQuitPanel.xib b/chrome/app/nibs/ConfirmQuitPanel.xib new file mode 100644 index 0000000..e98882f --- /dev/null +++ b/chrome/app/nibs/ConfirmQuitPanel.xib @@ -0,0 +1,333 @@ +<?xml version="1.0" encoding="UTF-8"?> +<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10"> + <data> + <int key="IBDocument.SystemTarget">1060</int> + <string key="IBDocument.SystemVersion">10F569</string> + <string key="IBDocument.InterfaceBuilderVersion">804</string> + <string key="IBDocument.AppKitVersion">1038.29</string> + <string key="IBDocument.HIToolboxVersion">461.00</string> + <object class="NSMutableDictionary" key="IBDocument.PluginVersions"> + <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string> + <string key="NS.object.0">804</string> + </object> + <object class="NSMutableArray" key="IBDocument.EditedObjectIDs"> + <bool key="EncodedWithXMLCoder">YES</bool> + <integer value="2"/> + </object> + <object class="NSArray" key="IBDocument.PluginDependencies"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + </object> + <object class="NSMutableDictionary" key="IBDocument.Metadata"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys" id="0"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + </object> + <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSCustomObject" id="1001"> + <string key="NSClassName">ConfirmQuitPanelController</string> + </object> + <object class="NSCustomObject" id="1003"> + <string key="NSClassName">FirstResponder</string> + </object> + <object class="NSCustomObject" id="1004"> + <string key="NSClassName">NSApplication</string> + </object> + <object class="NSWindowTemplate" id="417776770"> + <int key="NSWindowStyleMask">8337</int> + <int key="NSWindowBacking">2</int> + <string key="NSWindowRect">{{235, 336}, {365, 69}}</string> + <int key="NSWTFlags">611844096</int> + <string key="NSWindowTitle">^IDS_PRODUCT_NAME</string> + <string key="NSWindowClass">NSPanel</string> + <nil key="NSViewClass"/> + <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string> + <object class="NSView" key="NSWindowView" id="632563843"> + <reference key="NSNextResponder"/> + <int key="NSvFlags">256</int> + <object class="NSMutableArray" key="NSSubviews"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSTextField" id="369287154"> + <reference key="NSNextResponder" ref="632563843"/> + <int key="NSvFlags">298</int> + <string key="NSFrame">{{17, 20}, {331, 29}}</string> + <reference key="NSSuperview" ref="632563843"/> + <bool key="NSEnabled">YES</bool> + <object class="NSTextFieldCell" key="NSCell" id="354055869"> + <int key="NSCellFlags">68288064</int> + <int key="NSCellFlags2">138413056</int> + <string key="NSContents">^IDS_CONFIRM_TO_QUIT_DESCRIPTION</string> + <object class="NSFont" key="NSSupport"> + <string key="NSName">LucidaGrande-Bold</string> + <double key="NSSize">24</double> + <int key="NSfFlags">16</int> + </object> + <reference key="NSControlView" ref="369287154"/> + <object class="NSColor" key="NSBackgroundColor"> + <int key="NSColorSpace">6</int> + <string key="NSCatalogName">System</string> + <string key="NSColorName">controlColor</string> + <object class="NSColor" key="NSColor"> + <int key="NSColorSpace">3</int> + <bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes> + </object> + </object> + <object class="NSColor" key="NSTextColor"> + <int key="NSColorSpace">1</int> + <bytes key="NSRGB">MSAxIDEAA</bytes> + </object> + </object> + </object> + </object> + <string key="NSFrameSize">{365, 69}</string> + <reference key="NSSuperview"/> + </object> + <string key="NSScreenRect">{{0, 0}, {1920, 1178}}</string> + <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string> + </object> + <object class="NSCustomObject" id="421673775"> + <string key="NSClassName">ChromeUILocalizer</string> + </object> + </object> + <object class="IBObjectContainer" key="IBDocument.Objects"> + <object class="NSMutableArray" key="connectionRecords"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">window</string> + <reference key="source" ref="1001"/> + <reference key="destination" ref="417776770"/> + </object> + <int key="connectionID">8</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">delegate</string> + <reference key="source" ref="417776770"/> + <reference key="destination" ref="1001"/> + </object> + <int key="connectionID">9</int> + </object> + <object class="IBConnectionRecord"> + <object class="IBOutletConnection" key="connection"> + <string key="label">owner_</string> + <reference key="source" ref="421673775"/> + <reference key="destination" ref="1001"/> + </object> + <int key="connectionID">11</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> + <reference key="object" ref="0"/> + <reference key="children" ref="1000"/> + <nil key="parent"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">-2</int> + <reference key="object" ref="1001"/> + <reference key="parent" ref="0"/> + <string key="objectName">File's Owner</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">-1</int> + <reference key="object" ref="1003"/> + <reference key="parent" ref="0"/> + <string key="objectName">First Responder</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">-3</int> + <reference key="object" ref="1004"/> + <reference key="parent" ref="0"/> + <string key="objectName">Application</string> + </object> + <object class="IBObjectRecord"> + <int key="objectID">1</int> + <reference key="object" ref="417776770"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="632563843"/> + </object> + <reference key="parent" ref="0"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">2</int> + <reference key="object" ref="632563843"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="369287154"/> + </object> + <reference key="parent" ref="417776770"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">3</int> + <reference key="object" ref="369287154"/> + <object class="NSMutableArray" key="children"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference ref="354055869"/> + </object> + <reference key="parent" ref="632563843"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">6</int> + <reference key="object" ref="354055869"/> + <reference key="parent" ref="369287154"/> + </object> + <object class="IBObjectRecord"> + <int key="objectID">10</int> + <reference key="object" ref="421673775"/> + <reference key="parent" ref="0"/> + </object> + </object> + </object> + <object class="NSMutableDictionary" key="flattenedProperties"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>-1.IBPluginDependency</string> + <string>-2.IBPluginDependency</string> + <string>-3.IBPluginDependency</string> + <string>1.IBEditorWindowLastContentRect</string> + <string>1.IBPluginDependency</string> + <string>1.IBWindowTemplateEditedContentRect</string> + <string>1.NSWindowTemplate.visibleAtLaunch</string> + <string>10.IBPluginDependency</string> + <string>2.IBPluginDependency</string> + <string>3.IBPluginDependency</string> + <string>3.IBViewBoundsToFrameTransform</string> + <string>6.IBPluginDependency</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>{{787, 702}, {365, 69}}</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>{{787, 702}, {365, 69}}</string> + <boolean value="NO"/> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + <object class="NSAffineTransform"> + <bytes key="NSTransformStruct">P4AAAL+AAABA4AAAwhgAAA</bytes> + </object> + <string>com.apple.InterfaceBuilder.CocoaPlugin</string> + </object> + </object> + <object class="NSMutableDictionary" key="unlocalizedProperties"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference key="dict.sortedKeys" ref="0"/> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + </object> + <nil key="activeLocalization"/> + <object class="NSMutableDictionary" key="localizations"> + <bool key="EncodedWithXMLCoder">YES</bool> + <reference key="dict.sortedKeys" ref="0"/> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + </object> + </object> + <nil key="sourceID"/> + <int key="maxID">11</int> + </object> + <object class="IBClassDescriber" key="IBDocument.Classes"> + <object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.1+"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBPartialClassDescription"> + <string key="className">ChromeUILocalizer</string> + <string key="superclassName">GTMUILocalizer</string> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBDocumentRelativeSource</string> + <string key="minorKey">../../browser/cocoa/ui_localizer.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">ConfirmQuitPanelController</string> + <string key="superclassName">NSWindowController</string> + <object class="NSMutableDictionary" key="outlets"> + <string key="NS.key.0">infoField_</string> + <string key="NS.object.0">NSTextField</string> + </object> + <object class="NSMutableDictionary" key="toOneOutletInfosByName"> + <string key="NS.key.0">infoField_</string> + <object class="IBToOneOutletInfo" key="NS.object.0"> + <string key="name">infoField_</string> + <string key="candidateClassName">NSTextField</string> + </object> + </object> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBDocumentRelativeSource</string> + <string key="minorKey">../../browser/cocoa/confirm_quit_panel_controller.h</string> + </object> + </object> + <object class="IBPartialClassDescription"> + <string key="className">GTMUILocalizer</string> + <string key="superclassName">NSObject</string> + <object class="NSMutableDictionary" key="outlets"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>otherObjectToLocalize_</string> + <string>owner_</string> + <string>yetAnotherObjectToLocalize_</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="toOneOutletInfosByName"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="NSArray" key="dict.sortedKeys"> + <bool key="EncodedWithXMLCoder">YES</bool> + <string>otherObjectToLocalize_</string> + <string>owner_</string> + <string>yetAnotherObjectToLocalize_</string> + </object> + <object class="NSMutableArray" key="dict.values"> + <bool key="EncodedWithXMLCoder">YES</bool> + <object class="IBToOneOutletInfo"> + <string key="name">otherObjectToLocalize_</string> + <string key="candidateClassName">id</string> + </object> + <object class="IBToOneOutletInfo"> + <string key="name">owner_</string> + <string key="candidateClassName">id</string> + </object> + <object class="IBToOneOutletInfo"> + <string key="name">yetAnotherObjectToLocalize_</string> + <string key="candidateClassName">id</string> + </object> + </object> + </object> + <object class="IBClassDescriptionSource" key="sourceIdentifier"> + <string key="majorKey">IBDocumentRelativeSource</string> + <string key="minorKey">../../../third_party/GTM/AppKit/GTMUILocalizer.h</string> + </object> + </object> + </object> + </object> + <int key="IBDocument.localizationMode">0</int> + <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string> + <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies"> + <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string> + <integer value="3000" key="NS.object.0"/> + </object> + <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool> + <nil key="IBDocument.LastKnownRelativeProjectPath"/> + <int key="IBDocument.defaultPropertyAccessControl">3</int> + </data> +</archive> diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 8f552e5..5b5fd7ce 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc @@ -150,6 +150,13 @@ const Experiment kExperiments[] = { kOsLinux, switches::kDnsServer }, + { + "confirm-to-quit", // Do not change; see above. + IDS_FLAGS_CONFIRM_TO_QUIT_NAME, + IDS_FLAGS_CONFIRM_TO_QUIT_DESCRIPTION, + kOsMac, + switches::kEnableConfirmToQuit + }, }; const Experiment* experiments = kExperiments; diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm index 22de42f..aa5af1f 100644 --- a/chrome/browser/app_controller_mac.mm +++ b/chrome/browser/app_controller_mac.mm @@ -27,6 +27,7 @@ #import "chrome/browser/cocoa/browser_window_controller.h" #import "chrome/browser/cocoa/bug_report_window_controller.h" #import "chrome/browser/cocoa/clear_browsing_data_controller.h" +#import "chrome/browser/cocoa/confirm_quit_panel_controller.h" #import "chrome/browser/cocoa/encoding_menu_controller_delegate_mac.h" #import "chrome/browser/cocoa/history_menu_bridge.h" #import "chrome/browser/cocoa/import_settings_dialog.h" @@ -242,6 +243,12 @@ void RecordLastRunAppBundlePath() { // them in, but I'm not sure about UX; we'd also want to disable other things // though.) http://crbug.com/40861 + // Check if the user really wants to quit by employing the confirm-to-quit + // mechanism. + if (!browser_shutdown::IsTryingToQuit() && + [self applicationShouldTerminate:app] != NSTerminateNow) + return NO; + size_t num_browsers = BrowserList::size(); // Give any print jobs in progress time to finish. @@ -267,6 +274,92 @@ void RecordLastRunAppBundlePath() { } } +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)app { + // Check if the experiment is enabled. + const CommandLine* commandLine(CommandLine::ForCurrentProcess()); + if (!commandLine->HasSwitch(switches::kEnableConfirmToQuit)) + return NSTerminateNow; + + // If the application is going to terminate as the result of a Cmd+Q + // invocation, use the special sauce to prevent accidental quitting. + // http://dev.chromium.org/developers/design-documents/confirm-to-quit-experiment + NSEvent* currentEvent = [app currentEvent]; + if ([currentEvent type] == NSKeyDown) { + ConfirmQuitPanelController* quitPanel = + [[ConfirmQuitPanelController alloc] init]; // Releases self. + // Show the info panel that explains what the user must to do confirm quit. + [quitPanel showWindow:self]; + + // How long the user must hold down Cmd+Q to confirm the quit. + const NSTimeInterval kTimeToConfirmQuit = 1.5; + // Leeway between the |targetDate| and the current time that will confirm a + // quit. + const NSTimeInterval kTimeDeltaFuzzFactor = 1.0; + // Duration of the window fade out animation. + const NSTimeInterval kWindowFadeAnimationDuration = 0.2; + + // Spin a nested run loop until the |targetDate| is reached or a KeyUp event + // is sent. + NSDate* targetDate = + [NSDate dateWithTimeIntervalSinceNow:kTimeToConfirmQuit]; + BOOL willQuit = NO; + NSEvent* nextEvent = nil; + do { + // Dequeue events until a key up is received. + nextEvent = [app nextEventMatchingMask:NSKeyUpMask + untilDate:nil + inMode:NSEventTrackingRunLoopMode + dequeue:YES]; + + // Wait for the time expiry to happen. Once past the hold threshold, + // commit to quitting and hide all the open windows. + if (!willQuit) { + NSDate* now = [NSDate date]; + NSTimeInterval difference = [targetDate timeIntervalSinceDate:now]; + if (difference < kTimeDeltaFuzzFactor) { + willQuit = YES; + + // At this point, the quit has been confirmed and windows should all + // fade out to convince the user to release the key combo to finalize + // the quit. + [NSAnimationContext beginGrouping]; + [[NSAnimationContext currentContext] setDuration: + kWindowFadeAnimationDuration]; + for (NSWindow* aWindow in [app windows]) { + // Windows that are set to animate and have a delegate do not + // expect to be animated by other things and could result in an + // invalid state. If a window is set up like so, just force the + // alpha value to 0. Otherwise, animate all pretty and stuff. + if (![[aWindow animationForKey:@"alphaValue"] delegate]) { + [[aWindow animator] setAlphaValue:0.0]; + } else { + [aWindow setAlphaValue:0.0]; + } + } + [NSAnimationContext endGrouping]; + } + } + } while (!nextEvent); + + // The user has released the key combo. Discard any events (i.e. the + // repeated KeyDown Cmd+Q). + [app discardEventsMatchingMask:NSAnyEventMask beforeEvent:nextEvent]; + if (willQuit) { + // The user held down the combination long enough that quitting should + // happen. + return NSTerminateNow; + } else { + // Slowly fade the confirm window out in case the user doesn't + // understand what they have to do to quit. + [quitPanel dismissPanel]; + return NSTerminateCancel; + } + } // if event type is KeyDown + + // Default case: terminate. + return NSTerminateNow; +} + // Called when the app is shutting down. Clean-up as appropriate. - (void)applicationWillTerminate:(NSNotification*)aNotification { NSAppleEventManager* em = [NSAppleEventManager sharedAppleEventManager]; diff --git a/chrome/browser/cocoa/confirm_quit_panel_controller.h b/chrome/browser/cocoa/confirm_quit_panel_controller.h new file mode 100644 index 0000000..c518222 --- /dev/null +++ b/chrome/browser/cocoa/confirm_quit_panel_controller.h @@ -0,0 +1,24 @@ +// 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. + +#import <Cocoa/Cocoa.h> + +#include "base/cocoa_protocols_mac.h" + +// The ConfirmQuitPanelController manages the black HUD window that tells users +// to "Hold Cmd+Q to Quit". +@interface ConfirmQuitPanelController : NSWindowController<NSWindowDelegate> { +} + +// Designated initializer. Loads window from NIB but does not show it. +- (id)init; + +// Shows the window. +- (void)showWindow:(id)sender; + +// If the user did not confirm quit, send this message to give the user +// instructions on how to quit. +- (void)dismissPanel; + +@end diff --git a/chrome/browser/cocoa/confirm_quit_panel_controller.mm b/chrome/browser/cocoa/confirm_quit_panel_controller.mm new file mode 100644 index 0000000..5b624dd --- /dev/null +++ b/chrome/browser/cocoa/confirm_quit_panel_controller.mm @@ -0,0 +1,69 @@ +// 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. + +#import <Cocoa/Cocoa.h> +#import <QuartzCore/QuartzCore.h> + +#include "base/logging.h" +#include "base/mac_util.h" +#include "base/scoped_nsobject.h" +#import "chrome/browser/cocoa/confirm_quit_panel_controller.h" + +@interface ConfirmQuitPanelController (Private) +- (void)animateFadeOut; +@end + +@implementation ConfirmQuitPanelController + +- (id)init { + NSString* nibPath = + [mac_util::MainAppBundle() pathForResource:@"ConfirmQuitPanel" + ofType:@"nib"]; + if ((self = [super initWithWindowNibPath:nibPath owner:self])) { + } + return self; +} + +- (void)awakeFromNib { + DCHECK([self window]); + DCHECK_EQ(self, [[self window] delegate]); +} + +- (void)windowWillClose:(NSNotification*)notif { + // Release all animations because CAAnimation retains its delegate (self), + // which will cause a retain cycle. Break it! + [[self window] setAnimations:[NSDictionary dictionary]]; + [self autorelease]; +} + +- (void)showWindow:(id)sender { + [[self window] center]; + [[self window] setAlphaValue:1.0]; + [super showWindow:sender]; +} + +- (void)dismissPanel { + [self performSelector:@selector(animateFadeOut) + withObject:nil + afterDelay:1.0]; +} + +- (void)animateFadeOut { + NSWindow* window = [self window]; + scoped_nsobject<CAAnimation> animation( + [[window animationForKey:@"alphaValue"] copy]); + [animation setDelegate:self]; + [animation setDuration:0.2]; + NSMutableDictionary* dictionary = + [NSMutableDictionary dictionaryWithDictionary:[window animations]]; + [dictionary setObject:animation forKey:@"alphaValue"]; + [window setAnimations:dictionary]; + [[window animator] setAlphaValue:0.0]; +} + +- (void)animationDidStop:(CAAnimation*)theAnimation finished:(BOOL)flag { + [self close]; +} + +@end diff --git a/chrome/browser/cocoa/confirm_quit_panel_controller_unittest.mm b/chrome/browser/cocoa/confirm_quit_panel_controller_unittest.mm new file mode 100644 index 0000000..fddf164 --- /dev/null +++ b/chrome/browser/cocoa/confirm_quit_panel_controller_unittest.mm @@ -0,0 +1,26 @@ +// 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. + +#include "chrome/browser/cocoa/confirm_quit_panel_controller.h" + +#import "chrome/browser/cocoa/cocoa_test_helper.h" + +namespace { + +class ConfirmQuitPanelControllerTest : public CocoaTest { + public: + ConfirmQuitPanelControllerTest() : controller_(nil) { + } + + ConfirmQuitPanelController* controller_; // Weak, owns self. +}; + + +TEST_F(ConfirmQuitPanelControllerTest, ShowAndDismiss) { + controller_ = [[ConfirmQuitPanelController alloc] init]; + [controller_ showWindow:nil]; + [controller_ dismissPanel]; // Releases self. +} + +} // namespace diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 98afc2d..8797a88 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -904,6 +904,8 @@ 'browser/cocoa/collected_cookies_mac.mm', 'browser/cocoa/command_observer_bridge.h', 'browser/cocoa/command_observer_bridge.mm', + 'browser/cocoa/confirm_quit_panel_controller.h', + 'browser/cocoa/confirm_quit_panel_controller.mm', 'browser/cocoa/constrained_html_delegate_mac.mm', 'browser/cocoa/constrained_window_mac.h', 'browser/cocoa/constrained_window_mac.mm', @@ -3618,6 +3620,7 @@ 'app/nibs/CollectedCookies.xib', 'app/nibs/Cookies.xib', 'app/nibs/CookieDetailsView.xib', + 'app/nibs/ConfirmQuitPanel.xib', 'app/nibs/ContentBlockedCookies.xib', 'app/nibs/ContentBlockedImages.xib', 'app/nibs/ContentBlockedJavaScript.xib', diff --git a/chrome/chrome_dll.gypi b/chrome/chrome_dll.gypi index 0a08369..6149a39 100644 --- a/chrome/chrome_dll.gypi +++ b/chrome/chrome_dll.gypi @@ -207,6 +207,7 @@ 'app/nibs/CollectedCookies.xib', 'app/nibs/Cookies.xib', 'app/nibs/CookieDetailsView.xib', + 'app/nibs/ConfirmQuitPanel.xib', 'app/nibs/ContentBlockedCookies.xib', 'app/nibs/ContentBlockedImages.xib', 'app/nibs/ContentBlockedJavaScript.xib', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 6b2c4e9..bcc0f91 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1138,6 +1138,7 @@ 'browser/cocoa/cocoa_test_helper.mm', 'browser/cocoa/collected_cookies_mac_unittest.mm', 'browser/cocoa/command_observer_bridge_unittest.mm', + 'browser/cocoa/confirm_quit_panel_controller_unittest.mm', 'browser/cocoa/content_exceptions_window_controller_unittest.mm', 'browser/cocoa/content_setting_bubble_cocoa_unittest.mm', 'browser/cocoa/content_settings_dialog_controller_unittest.mm', diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index ccbba43..8f0e242 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -387,6 +387,9 @@ const char kEnableCloudPrintProxy[] = "enable-cloud-print-proxy"; // Enables the Cloud Print dialog hosting code. const char kEnableCloudPrint[] = "enable-cloud-print"; +// Enable the Confirm to Quit experiment. +const char kEnableConfirmToQuit[] = "enable-confirm-to-quit"; + // Enables establishing a backup TCP connection if a specified timeout is // exceeded. const char kEnableConnectBackupJobs[] = "enable-connect-backup-jobs"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 5b3c984..5e63f1b 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -121,6 +121,7 @@ extern const char kEnableBenchmarking[]; extern const char kEnableClearServerData[]; extern const char kEnableCloudPrintProxy[]; extern const char kEnableCloudPrint[]; +extern const char kEnableConfirmToQuit[]; extern const char kEnableConnectBackupJobs[]; extern const char kEnableContentPrefetch[]; extern const char kEnableDefaultApps[]; |