diff options
-rw-r--r-- | chrome/browser/app_controller_mac.mm | 148 |
1 files changed, 82 insertions, 66 deletions
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm index 3b43753..184b196 100644 --- a/chrome/browser/app_controller_mac.mm +++ b/chrome/browser/app_controller_mac.mm @@ -293,76 +293,92 @@ void RecordLastRunAppBundlePath() { // 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) { - // Show the info panel that explains what the user must to do confirm quit. - [[ConfirmQuitPanelController sharedController] 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]; - } + + // 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; + + // This logic is only for keyboard-initiated quits. + if ([[app currentEvent] type] != NSKeyDown) + return NSTerminateNow; + + // 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. + static NSDate* lastQuitAttempt; // Initially nil, as it's static. + NSDate* timeNow = [NSDate date]; + if (lastQuitAttempt && + [timeNow timeIntervalSinceDate:lastQuitAttempt] < kTimeDeltaFuzzFactor) { + return NSTerminateNow; + } else { + [lastQuitAttempt release]; // Harmless if already nil. + lastQuitAttempt = [timeNow retain]; // Record this attempt for next time. + } + + // Show the info panel that explains what the user must to do confirm quit. + [[ConfirmQuitPanelController sharedController] showWindow:self]; + + // 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]; } + [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. - [[ConfirmQuitPanelController sharedController] dismissPanel]; - return NSTerminateCancel; } - } // if event type is KeyDown + } 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. + [[ConfirmQuitPanelController sharedController] dismissPanel]; + return NSTerminateCancel; + } // Default case: terminate. return NSTerminateNow; |