summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui/cocoa/confirm_quit_panel_controller.mm
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/ui/cocoa/confirm_quit_panel_controller.mm')
-rw-r--r--chrome/browser/ui/cocoa/confirm_quit_panel_controller.mm113
1 files changed, 85 insertions, 28 deletions
diff --git a/chrome/browser/ui/cocoa/confirm_quit_panel_controller.mm b/chrome/browser/ui/cocoa/confirm_quit_panel_controller.mm
index c4cb727..4b44d4d 100644
--- a/chrome/browser/ui/cocoa/confirm_quit_panel_controller.mm
+++ b/chrome/browser/ui/cocoa/confirm_quit_panel_controller.mm
@@ -6,7 +6,8 @@
#import <QuartzCore/QuartzCore.h>
#include "base/logging.h"
-#include "base/scoped_nsobject.h"
+#include "base/memory/scoped_nsobject.h"
+#include "base/metrics/histogram.h"
#include "base/sys_string_conversions.h"
#import "chrome/browser/ui/cocoa/confirm_quit_panel_controller.h"
#include "grit/generated_resources.h"
@@ -24,6 +25,20 @@ const NSTimeInterval kTimeDeltaFuzzFactor = 1.0;
// Duration of the window fade out animation.
const NSTimeInterval kWindowFadeAnimationDuration = 0.2;
+// For metrics recording only: How long the user must hold the keys to
+// differentitate kDoubleTap from kTapHold.
+const NSTimeInterval kDoubleTapTimeDelta = 0.32;
+
+// Functions ///////////////////////////////////////////////////////////////////
+
+namespace confirm_quit {
+
+void RecordHistogram(ConfirmQuitMetric sample) {
+ HISTOGRAM_ENUMERATION("ConfirmToQuit", sample, kSampleCount);
+}
+
+} // namespace confirm_quit
+
// Custom Content View /////////////////////////////////////////////////////////
// The content view of the window that draws a custom frame.
@@ -71,8 +86,9 @@ const NSTimeInterval kWindowFadeAnimationDuration = 0.2;
scoped_nsobject<NSMutableAttributedString> attrString(
[[NSMutableAttributedString alloc] initWithString:text]);
scoped_nsobject<NSShadow> textShadow([[NSShadow alloc] init]);
- [textShadow setShadowColor:[NSColor colorWithCalibratedWhite:0 alpha:0.6]];
- [textShadow setShadowOffset:NSMakeSize(0, -1)];
+ [textShadow.get() setShadowColor:[NSColor colorWithCalibratedWhite:0
+ alpha:0.6]];
+ [textShadow.get() setShadowOffset:NSMakeSize(0, -1)];
[textShadow setShadowBlurRadius:1.0];
[attrString addAttribute:NSShadowAttributeName
value:textShadow
@@ -96,11 +112,49 @@ const NSTimeInterval kWindowFadeAnimationDuration = 0.2;
@end
+// Animation ///////////////////////////////////////////////////////////////////
+
+// This animation will run through all the windows of the passed-in
+// NSApplication and will fade their alpha value to 0.0. When the animation is
+// complete, this will release itself.
+@interface FadeAllWindowsAnimation : NSAnimation<NSAnimationDelegate> {
+ @private
+ NSApplication* application_;
+}
+- (id)initWithApplication:(NSApplication*)app
+ animationDuration:(NSTimeInterval)duration;
+@end
+
+
+@implementation FadeAllWindowsAnimation
+
+- (id)initWithApplication:(NSApplication*)app
+ animationDuration:(NSTimeInterval)duration {
+ if ((self = [super initWithDuration:duration
+ animationCurve:NSAnimationLinear])) {
+ application_ = app;
+ [self setDelegate:self];
+ }
+ return self;
+}
+
+- (void)setCurrentProgress:(NSAnimationProgress)progress {
+ for (NSWindow* window in [application_ windows]) {
+ [window setAlphaValue:1.0 - progress];
+ }
+}
+
+- (void)animationDidStop:(NSAnimation*)anim {
+ DCHECK_EQ(self, anim);
+ [self autorelease];
+}
+
+@end
+
// Private Interface ///////////////////////////////////////////////////////////
@interface ConfirmQuitPanelController (Private)
- (void)animateFadeOut;
-- (NSString*)keyCommandString;
- (NSEvent*)pumpEventQueueForKeyUp:(NSApplication*)app untilDate:(NSDate*)date;
- (void)hideAllWindowsForApplication:(NSApplication*)app
withDuration:(NSTimeInterval)duration;
@@ -117,7 +171,7 @@ ConfirmQuitPanelController* g_confirmQuitPanelController = nil;
g_confirmQuitPanelController =
[[ConfirmQuitPanelController alloc] init];
}
- return g_confirmQuitPanelController;
+ return [[g_confirmQuitPanelController retain] autorelease];
}
- (id)init {
@@ -142,7 +196,7 @@ ConfirmQuitPanelController* g_confirmQuitPanelController = nil;
// Set the proper string.
NSString* message = l10n_util::GetNSStringF(IDS_CONFIRM_TO_QUIT_DESCRIPTION,
- base::SysNSStringToUTF16([self keyCommandString]));
+ base::SysNSStringToUTF16([[self class] keyCommandString]));
[contentView_ setMessageText:message];
}
return self;
@@ -151,12 +205,14 @@ ConfirmQuitPanelController* g_confirmQuitPanelController = nil;
+ (BOOL)eventTriggersFeature:(NSEvent*)event {
if ([event type] != NSKeyDown)
return NO;
- ui::AcceleratorCocoa eventAccelerator([event characters],
+ ui::AcceleratorCocoa eventAccelerator([event charactersIgnoringModifiers],
[event modifierFlags] & NSDeviceIndependentModifierFlagsMask);
return [self quitAccelerator] == eventAccelerator;
}
- (NSApplicationTerminateReply)runModalLoopForApplication:(NSApplication*)app {
+ scoped_nsobject<ConfirmQuitPanelController> keepAlive([self retain]);
+
// If this is the second of two such attempts to quit within a certain time
// interval, then just quit.
// Time of last quit attempt, if any.
@@ -176,6 +232,12 @@ ConfirmQuitPanelController* g_confirmQuitPanelController = nil;
NSEvent* nextEvent = [self pumpEventQueueForKeyUp:app
untilDate:[NSDate distantFuture]];
[app discardEventsMatchingMask:NSAnyEventMask beforeEvent:nextEvent];
+
+ // Based on how long the user held the keys, record the metric.
+ if ([[NSDate date] timeIntervalSinceDate:timeNow] < kDoubleTapTimeDelta)
+ confirm_quit::RecordHistogram(confirm_quit::kDoubleTap);
+ else
+ confirm_quit::RecordHistogram(confirm_quit::kTapHold);
return NSTerminateNow;
} else {
[lastQuitAttempt release]; // Harmless if already nil.
@@ -191,9 +253,12 @@ ConfirmQuitPanelController* g_confirmQuitPanelController = nil;
BOOL willQuit = NO;
NSEvent* nextEvent = nil;
do {
- // Dequeue events until a key up is received.
- // TODO(rsesek): Explore using |untilDate| with |targetDate|.
- nextEvent = [self pumpEventQueueForKeyUp:app untilDate:nil];
+ // Dequeue events until a key up is received. To avoid busy waiting, figure
+ // out the amount of time that the thread can sleep before taking further
+ // action.
+ NSDate* waitDate = [NSDate dateWithTimeIntervalSinceNow:
+ kTimeToConfirmQuit - kTimeDeltaFuzzFactor];
+ nextEvent = [self pumpEventQueueForKeyUp:app untilDate:waitDate];
// Wait for the time expiry to happen. Once past the hold threshold,
// commit to quitting and hide all the open windows.
@@ -219,6 +284,7 @@ ConfirmQuitPanelController* g_confirmQuitPanelController = nil;
if (willQuit) {
// The user held down the combination long enough that quitting should
// happen.
+ confirm_quit::RecordHistogram(confirm_quit::kHoldDuration);
return NSTerminateNow;
} else {
// Slowly fade the confirm window out in case the user doesn't
@@ -242,7 +308,7 @@ ConfirmQuitPanelController* g_confirmQuitPanelController = nil;
- (void)showWindow:(id)sender {
// If a panel that is fading out is going to be reused here, make sure it
// does not get released when the animation finishes.
- scoped_nsobject<ConfirmQuitPanelController> stayAlive([self retain]);
+ scoped_nsobject<ConfirmQuitPanelController> keepAlive([self retain]);
[[self window] setAnimations:[NSDictionary dictionary]];
[[self window] center];
[[self window] setAlphaValue:1.0];
@@ -293,9 +359,9 @@ ConfirmQuitPanelController* g_confirmQuitPanelController = nil;
// This looks at the Main Menu and determines what the user has set as the
// key combination for quit. It then gets the modifiers and builds a string
// to display them.
-- (NSString*)keyCommandString {
++ (NSString*)keyCommandString {
ui::AcceleratorCocoa accelerator = [[self class] quitAccelerator];
- return [self keyCombinationForAccelerator:accelerator];
+ return [[self class] keyCombinationForAccelerator:accelerator];
}
// Runs a nested loop that pumps the event queue until the next KeyUp event.
@@ -309,23 +375,14 @@ ConfirmQuitPanelController* g_confirmQuitPanelController = nil;
// Iterates through the list of open windows and hides them all.
- (void)hideAllWindowsForApplication:(NSApplication*)app
withDuration:(NSTimeInterval)duration {
- [NSAnimationContext beginGrouping];
- [[NSAnimationContext currentContext] setDuration:duration];
- for (NSWindow* window in [app windows]) {
- // Windows that are set to animate and have a delegate do no 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 (duration > 0 && ![[window animationForKey:@"alphaValue"] delegate]) {
- [[window animator] setAlphaValue:0.0];
- } else {
- [window setAlphaValue:0.0];
- }
- }
- [NSAnimationContext endGrouping];
+ FadeAllWindowsAnimation* animation =
+ [[FadeAllWindowsAnimation alloc] initWithApplication:app
+ animationDuration:duration];
+ // Releases itself when the animation stops.
+ [animation startAnimation];
}
-- (NSString*)keyCombinationForAccelerator:(const ui::AcceleratorCocoa&)item {
++ (NSString*)keyCombinationForAccelerator:(const ui::AcceleratorCocoa&)item {
NSMutableString* string = [NSMutableString string];
NSUInteger modifiers = item.modifiers();