| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "chrome/browser/app_controller_mac.h" | 5 #import "chrome/browser/app_controller_mac.h" |
| 6 | 6 |
| 7 #include "base/auto_reset.h" | 7 #include "base/auto_reset.h" |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/file_path.h" | 9 #include "base/file_path.h" |
| 10 #include "base/mac/mac_util.h" | 10 #include "base/mac/mac_util.h" |
| (...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 278 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)app { | 278 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)app { |
| 279 // Check if the experiment is enabled. | 279 // Check if the experiment is enabled. |
| 280 const CommandLine* commandLine(CommandLine::ForCurrentProcess()); | 280 const CommandLine* commandLine(CommandLine::ForCurrentProcess()); |
| 281 if (commandLine->HasSwitch(switches::kDisableConfirmToQuit)) | 281 if (commandLine->HasSwitch(switches::kDisableConfirmToQuit)) |
| 282 return NSTerminateNow; | 282 return NSTerminateNow; |
| 283 | 283 |
| 284 // If the application is going to terminate as the result of a Cmd+Q | 284 // If the application is going to terminate as the result of a Cmd+Q |
| 285 // invocation, use the special sauce to prevent accidental quitting. | 285 // invocation, use the special sauce to prevent accidental quitting. |
| 286 // http://dev.chromium.org/developers/design-documents/confirm-to-quit-experim
ent | 286 // http://dev.chromium.org/developers/design-documents/confirm-to-quit-experim
ent |
| 287 | 287 |
| 288 // How long the user must hold down Cmd+Q to confirm the quit. | |
| 289 const NSTimeInterval kTimeToConfirmQuit = 1.5; | |
| 290 // Leeway between the |targetDate| and the current time that will confirm a | |
| 291 // quit. | |
| 292 const NSTimeInterval kTimeDeltaFuzzFactor = 1.0; | |
| 293 // Duration of the window fade out animation. | |
| 294 const NSTimeInterval kWindowFadeAnimationDuration = 0.2; | |
| 295 | |
| 296 // This logic is only for keyboard-initiated quits. | 288 // This logic is only for keyboard-initiated quits. |
| 297 NSEvent* currentEvent = [app currentEvent]; | 289 if (![ConfirmQuitPanelController eventTriggersFeature:[app currentEvent]]) |
| 298 if ([currentEvent type] != NSKeyDown) | |
| 299 return NSTerminateNow; | |
| 300 ui::AcceleratorCocoa currentEventAccelerator([currentEvent characters], | |
| 301 [currentEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask); | |
| 302 if ([ConfirmQuitPanelController quitAccelerator] != currentEventAccelerator) | |
| 303 return NSTerminateNow; | 290 return NSTerminateNow; |
| 304 | 291 |
| 305 // If this is the second of two such attempts to quit within a certain time | 292 return [[ConfirmQuitPanelController sharedController] |
| 306 // interval, then just quit. | 293 runModalLoopForApplication:app]; |
| 307 // Time of last quit attempt, if any. | |
| 308 static NSDate* lastQuitAttempt; // Initially nil, as it's static. | |
| 309 NSDate* timeNow = [NSDate date]; | |
| 310 if (lastQuitAttempt && | |
| 311 [timeNow timeIntervalSinceDate:lastQuitAttempt] < kTimeDeltaFuzzFactor) { | |
| 312 return NSTerminateNow; | |
| 313 } else { | |
| 314 [lastQuitAttempt release]; // Harmless if already nil. | |
| 315 lastQuitAttempt = [timeNow retain]; // Record this attempt for next time. | |
| 316 } | |
| 317 | |
| 318 // Show the info panel that explains what the user must to do confirm quit. | |
| 319 [[ConfirmQuitPanelController sharedController] showWindow:self]; | |
| 320 | |
| 321 // Spin a nested run loop until the |targetDate| is reached or a KeyUp event | |
| 322 // is sent. | |
| 323 NSDate* targetDate = | |
| 324 [NSDate dateWithTimeIntervalSinceNow:kTimeToConfirmQuit]; | |
| 325 BOOL willQuit = NO; | |
| 326 NSEvent* nextEvent = nil; | |
| 327 do { | |
| 328 // Dequeue events until a key up is received. | |
| 329 nextEvent = [app nextEventMatchingMask:NSKeyUpMask | |
| 330 untilDate:nil | |
| 331 inMode:NSEventTrackingRunLoopMode | |
| 332 dequeue:YES]; | |
| 333 | |
| 334 // Wait for the time expiry to happen. Once past the hold threshold, | |
| 335 // commit to quitting and hide all the open windows. | |
| 336 if (!willQuit) { | |
| 337 NSDate* now = [NSDate date]; | |
| 338 NSTimeInterval difference = [targetDate timeIntervalSinceDate:now]; | |
| 339 if (difference < kTimeDeltaFuzzFactor) { | |
| 340 willQuit = YES; | |
| 341 | |
| 342 // At this point, the quit has been confirmed and windows should all | |
| 343 // fade out to convince the user to release the key combo to finalize | |
| 344 // the quit. | |
| 345 [NSAnimationContext beginGrouping]; | |
| 346 [[NSAnimationContext currentContext] setDuration: | |
| 347 kWindowFadeAnimationDuration]; | |
| 348 for (NSWindow* aWindow in [app windows]) { | |
| 349 // Windows that are set to animate and have a delegate do not | |
| 350 // expect to be animated by other things and could result in an | |
| 351 // invalid state. If a window is set up like so, just force the | |
| 352 // alpha value to 0. Otherwise, animate all pretty and stuff. | |
| 353 if (![[aWindow animationForKey:@"alphaValue"] delegate]) { | |
| 354 [[aWindow animator] setAlphaValue:0.0]; | |
| 355 } else { | |
| 356 [aWindow setAlphaValue:0.0]; | |
| 357 } | |
| 358 } | |
| 359 [NSAnimationContext endGrouping]; | |
| 360 } | |
| 361 } | |
| 362 } while (!nextEvent); | |
| 363 | |
| 364 // The user has released the key combo. Discard any events (i.e. the | |
| 365 // repeated KeyDown Cmd+Q). | |
| 366 [app discardEventsMatchingMask:NSAnyEventMask beforeEvent:nextEvent]; | |
| 367 | |
| 368 if (willQuit) { | |
| 369 // The user held down the combination long enough that quitting should | |
| 370 // happen. | |
| 371 return NSTerminateNow; | |
| 372 } else { | |
| 373 // Slowly fade the confirm window out in case the user doesn't | |
| 374 // understand what they have to do to quit. | |
| 375 [[ConfirmQuitPanelController sharedController] dismissPanel]; | |
| 376 return NSTerminateCancel; | |
| 377 } | |
| 378 | |
| 379 // Default case: terminate. | |
| 380 return NSTerminateNow; | |
| 381 } | 294 } |
| 382 | 295 |
| 383 // Called when the app is shutting down. Clean-up as appropriate. | 296 // Called when the app is shutting down. Clean-up as appropriate. |
| 384 - (void)applicationWillTerminate:(NSNotification*)aNotification { | 297 - (void)applicationWillTerminate:(NSNotification*)aNotification { |
| 385 NSAppleEventManager* em = [NSAppleEventManager sharedAppleEventManager]; | 298 NSAppleEventManager* em = [NSAppleEventManager sharedAppleEventManager]; |
| 386 [em removeEventHandlerForEventClass:kInternetEventClass | 299 [em removeEventHandlerForEventClass:kInternetEventClass |
| 387 andEventID:kAEGetURL]; | 300 andEventID:kAEGetURL]; |
| 388 [em removeEventHandlerForEventClass:'WWW!' | 301 [em removeEventHandlerForEventClass:'WWW!' |
| 389 andEventID:'OURL']; | 302 andEventID:'OURL']; |
| 390 | 303 |
| (...skipping 899 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1290 [appController showPreferencesWindow:nil page:page profile:profile]; | 1203 [appController showPreferencesWindow:nil page:page profile:profile]; |
| 1291 } | 1204 } |
| 1292 | 1205 |
| 1293 namespace app_controller_mac { | 1206 namespace app_controller_mac { |
| 1294 | 1207 |
| 1295 bool IsOpeningNewWindow() { | 1208 bool IsOpeningNewWindow() { |
| 1296 return g_is_opening_new_window; | 1209 return g_is_opening_new_window; |
| 1297 } | 1210 } |
| 1298 | 1211 |
| 1299 } // namespace app_controller_mac | 1212 } // namespace app_controller_mac |
| OLD | NEW |