Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 "app/l10n_util.h" | 7 #include "app/l10n_util.h" |
| 8 #include "app/l10n_util_mac.h" | 8 #include "app/l10n_util_mac.h" |
| 9 #include "base/auto_reset.h" | 9 #include "base/auto_reset.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| 11 #include "base/file_path.h" | 11 #include "base/file_path.h" |
| 12 #include "base/mac_util.h" | 12 #include "base/mac_util.h" |
| 13 #include "base/message_loop.h" | 13 #include "base/message_loop.h" |
| 14 #include "base/string_number_conversions.h" | 14 #include "base/string_number_conversions.h" |
| 15 #include "base/sys_string_conversions.h" | 15 #include "base/sys_string_conversions.h" |
| 16 #include "chrome/app/chrome_dll_resource.h" | 16 #include "chrome/app/chrome_dll_resource.h" |
| 17 #include "chrome/browser/browser.h" | 17 #include "chrome/browser/browser.h" |
| 18 #include "chrome/browser/browser_init.h" | 18 #include "chrome/browser/browser_init.h" |
| 19 #include "chrome/browser/browser_list.h" | 19 #include "chrome/browser/browser_list.h" |
| 20 #include "chrome/browser/browser_process.h" | 20 #include "chrome/browser/browser_process.h" |
| 21 #include "chrome/browser/browser_shutdown.h" | 21 #include "chrome/browser/browser_shutdown.h" |
| 22 #include "chrome/browser/browser_thread.h" | 22 #include "chrome/browser/browser_thread.h" |
| 23 #include "chrome/browser/browser_window.h" | 23 #include "chrome/browser/browser_window.h" |
| 24 #import "chrome/browser/cocoa/about_window_controller.h" | 24 #import "chrome/browser/cocoa/about_window_controller.h" |
| 25 #import "chrome/browser/cocoa/bookmarks/bookmark_menu_bridge.h" | 25 #import "chrome/browser/cocoa/bookmarks/bookmark_menu_bridge.h" |
| 26 #import "chrome/browser/cocoa/browser_window_cocoa.h" | 26 #import "chrome/browser/cocoa/browser_window_cocoa.h" |
| 27 #import "chrome/browser/cocoa/browser_window_controller.h" | 27 #import "chrome/browser/cocoa/browser_window_controller.h" |
| 28 #import "chrome/browser/cocoa/bug_report_window_controller.h" | 28 #import "chrome/browser/cocoa/bug_report_window_controller.h" |
| 29 #import "chrome/browser/cocoa/clear_browsing_data_controller.h" | 29 #import "chrome/browser/cocoa/clear_browsing_data_controller.h" |
| 30 #import "chrome/browser/cocoa/confirm_quit_panel_controller.h" | |
| 30 #import "chrome/browser/cocoa/encoding_menu_controller_delegate_mac.h" | 31 #import "chrome/browser/cocoa/encoding_menu_controller_delegate_mac.h" |
| 31 #import "chrome/browser/cocoa/history_menu_bridge.h" | 32 #import "chrome/browser/cocoa/history_menu_bridge.h" |
| 32 #import "chrome/browser/cocoa/import_settings_dialog.h" | 33 #import "chrome/browser/cocoa/import_settings_dialog.h" |
| 33 #import "chrome/browser/cocoa/preferences_window_controller.h" | 34 #import "chrome/browser/cocoa/preferences_window_controller.h" |
| 34 #import "chrome/browser/cocoa/tab_strip_controller.h" | 35 #import "chrome/browser/cocoa/tab_strip_controller.h" |
| 35 #import "chrome/browser/cocoa/tab_window_controller.h" | 36 #import "chrome/browser/cocoa/tab_window_controller.h" |
| 36 #include "chrome/browser/cocoa/task_manager_mac.h" | 37 #include "chrome/browser/cocoa/task_manager_mac.h" |
| 37 #include "chrome/browser/command_updater.h" | 38 #include "chrome/browser/command_updater.h" |
| 38 #include "chrome/browser/download/download_manager.h" | 39 #include "chrome/browser/download/download_manager.h" |
| 39 #include "chrome/browser/metrics/user_metrics.h" | 40 #include "chrome/browser/metrics/user_metrics.h" |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 235 // shutting down, else the user might be prompted multiple times if the | 236 // shutting down, else the user might be prompted multiple times if the |
| 236 // download isn't stopped before terminate is called again. | 237 // download isn't stopped before terminate is called again. |
| 237 if (!browser_shutdown::IsTryingToQuit() && | 238 if (!browser_shutdown::IsTryingToQuit() && |
| 238 ![self shouldQuitWithInProgressDownloads]) | 239 ![self shouldQuitWithInProgressDownloads]) |
| 239 return NO; | 240 return NO; |
| 240 | 241 |
| 241 // TODO(viettrungluu): Remove Apple Event handlers here? (It's safe to leave | 242 // TODO(viettrungluu): Remove Apple Event handlers here? (It's safe to leave |
| 242 // them in, but I'm not sure about UX; we'd also want to disable other things | 243 // them in, but I'm not sure about UX; we'd also want to disable other things |
| 243 // though.) http://crbug.com/40861 | 244 // though.) http://crbug.com/40861 |
| 244 | 245 |
| 246 // Check if the user really wants to quit by employing the confirm-to-quit | |
| 247 // mechanism. | |
| 248 if (!browser_shutdown::IsTryingToQuit() && | |
| 249 [self applicationShouldTerminate:app] != NSTerminateNow) | |
| 250 return NO; | |
| 251 | |
| 245 size_t num_browsers = BrowserList::size(); | 252 size_t num_browsers = BrowserList::size(); |
| 246 | 253 |
| 247 // Give any print jobs in progress time to finish. | 254 // Give any print jobs in progress time to finish. |
| 248 if (!browser_shutdown::IsTryingToQuit()) | 255 if (!browser_shutdown::IsTryingToQuit()) |
| 249 g_browser_process->print_job_manager()->StopJobs(true); | 256 g_browser_process->print_job_manager()->StopJobs(true); |
| 250 | 257 |
| 251 // Initiate a shutdown (via BrowserList::CloseAllBrowsers()) if we aren't | 258 // Initiate a shutdown (via BrowserList::CloseAllBrowsers()) if we aren't |
| 252 // already shutting down. | 259 // already shutting down. |
| 253 if (!browser_shutdown::IsTryingToQuit()) | 260 if (!browser_shutdown::IsTryingToQuit()) |
| 254 BrowserList::CloseAllBrowsers(); | 261 BrowserList::CloseAllBrowsers(); |
| 255 | 262 |
| 256 return num_browsers == 0 ? YES : NO; | 263 return num_browsers == 0 ? YES : NO; |
| 257 } | 264 } |
| 258 | 265 |
| 259 - (void)stopTryingToTerminateApplication:(NSApplication*)app { | 266 - (void)stopTryingToTerminateApplication:(NSApplication*)app { |
| 260 if (browser_shutdown::IsTryingToQuit()) { | 267 if (browser_shutdown::IsTryingToQuit()) { |
| 261 // Reset the "trying to quit" state, so that closing all browser windows | 268 // Reset the "trying to quit" state, so that closing all browser windows |
| 262 // will no longer lead to termination. | 269 // will no longer lead to termination. |
| 263 browser_shutdown::SetTryingToQuit(false); | 270 browser_shutdown::SetTryingToQuit(false); |
| 264 | 271 |
| 265 // TODO(viettrungluu): Were we to remove Apple Event handlers above, we | 272 // TODO(viettrungluu): Were we to remove Apple Event handlers above, we |
| 266 // would have to reinstall them here. http://crbug.com/40861 | 273 // would have to reinstall them here. http://crbug.com/40861 |
| 267 } | 274 } |
| 268 } | 275 } |
| 269 | 276 |
| 277 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)app { | |
| 278 // Check if the experiment is enabled. | |
|
viettrungluu
2010/11/02 17:28:13
Probably you should say which experiment.
| |
| 279 const CommandLine* commandLine(CommandLine::ForCurrentProcess()); | |
| 280 if (!commandLine->HasSwitch(switches::kEnableConfirmToQuit)) | |
| 281 return NSTerminateNow; | |
| 282 | |
| 283 // If the application is going to terminate as the result of a Cmd+Q | |
| 284 // invocation, use the special sauce to prevent accidental quitting. | |
| 285 // http://dev.chromium.org/developers/design-documents/confirm-to-quit-experim ent | |
| 286 NSEvent* currentEvent = [app currentEvent]; | |
| 287 if ([currentEvent type] == NSKeyDown) { | |
| 288 ConfirmQuitPanelController* quitPanel = | |
| 289 [[ConfirmQuitPanelController alloc] init]; // Releases self. | |
| 290 // Show the info panel that explains what the user must to do confirm quit. | |
| 291 [quitPanel showWindow:self]; | |
| 292 | |
| 293 // How long the user must hold down Cmd+Q to confirm the quit. | |
| 294 const NSTimeInterval kTimeToConfirmQuit = 1.5; | |
| 295 // Leeway between the |targetDate| and the current time that will confirm a | |
| 296 // quit. | |
| 297 const NSTimeInterval kTimeDeltaFuzzFactor = 1.0; | |
| 298 // Duration of the window fade out animation. | |
| 299 const NSTimeInterval kWindowFadeAnimationDuration = 0.2; | |
| 300 | |
| 301 // Spin a nested run loop until the |targetDate| is reached or a KeyUp event | |
| 302 // is sent. | |
| 303 NSDate* targetDate = | |
| 304 [NSDate dateWithTimeIntervalSinceNow:kTimeToConfirmQuit]; | |
| 305 BOOL willQuit = NO; | |
| 306 NSEvent* nextEvent = nil; | |
| 307 do { | |
|
viettrungluu
2010/11/02 17:28:13
Generically, I'm kind of scared of this, though I
Robert Sesek
2010/11/02 20:05:58
Open new window: OK
Extension close window: OK
JS
| |
| 308 // Dequeue events until a key up is received. | |
| 309 nextEvent = [app nextEventMatchingMask:NSKeyUpMask | |
| 310 untilDate:nil | |
| 311 inMode:NSEventTrackingRunLoopMode | |
| 312 dequeue:YES]; | |
| 313 | |
| 314 // Wait for the time expiry to happen. Once past the hold threshold, | |
| 315 // commit to quitting and hide all the open windows. | |
| 316 if (!willQuit) { | |
| 317 NSDate* now = [NSDate date]; | |
| 318 NSTimeInterval difference = [targetDate timeIntervalSinceDate:now]; | |
| 319 if (difference < kTimeDeltaFuzzFactor) { | |
| 320 willQuit = YES; | |
| 321 | |
| 322 // At this point, the quit has been confirmed and windows should all | |
| 323 // fade out to convince the user to release the key combo to finalize | |
| 324 // the quit. | |
| 325 [NSAnimationContext beginGrouping]; | |
| 326 [[NSAnimationContext currentContext] setDuration: | |
| 327 kWindowFadeAnimationDuration]; | |
| 328 for (NSWindow* aWindow in [app windows]) { | |
| 329 // Windows that are set to animate and have a delegate do not | |
| 330 // expect to be animated by other things and could result in an | |
| 331 // invalid state. If a window is set up like so, just force the | |
| 332 // alpha value to 0. Otherwise, animate all pretty and stuff. | |
| 333 if (![[aWindow animationForKey:@"alphaValue"] delegate]) { | |
| 334 [[aWindow animator] setAlphaValue:0.0]; | |
| 335 } else { | |
| 336 [aWindow setAlphaValue:0.0]; | |
| 337 } | |
| 338 } | |
| 339 [NSAnimationContext endGrouping]; | |
| 340 } | |
| 341 } | |
| 342 } while (!nextEvent); | |
| 343 | |
| 344 // The user has released the key combo. Discard any events (i.e. the | |
| 345 // repeated KeyDown Cmd+Q). | |
| 346 [app discardEventsMatchingMask:NSAnyEventMask beforeEvent:nextEvent]; | |
| 347 if (willQuit) { | |
| 348 // The user held down the combination long enough that quitting should | |
| 349 // happen. | |
| 350 return NSTerminateNow; | |
| 351 } else { | |
| 352 // Slowly fade the confirm window out in case the user doesn't | |
| 353 // understand what they have to do to quit. | |
| 354 [quitPanel dismissPanel]; | |
| 355 return NSTerminateCancel; | |
| 356 } | |
| 357 } // if event type is KeyDown | |
| 358 | |
| 359 // Default case: terminate. | |
| 360 return NSTerminateNow; | |
| 361 } | |
| 362 | |
| 270 // Called when the app is shutting down. Clean-up as appropriate. | 363 // Called when the app is shutting down. Clean-up as appropriate. |
| 271 - (void)applicationWillTerminate:(NSNotification*)aNotification { | 364 - (void)applicationWillTerminate:(NSNotification*)aNotification { |
| 272 NSAppleEventManager* em = [NSAppleEventManager sharedAppleEventManager]; | 365 NSAppleEventManager* em = [NSAppleEventManager sharedAppleEventManager]; |
| 273 [em removeEventHandlerForEventClass:kInternetEventClass | 366 [em removeEventHandlerForEventClass:kInternetEventClass |
| 274 andEventID:kAEGetURL]; | 367 andEventID:kAEGetURL]; |
| 275 [em removeEventHandlerForEventClass:'WWW!' | 368 [em removeEventHandlerForEventClass:'WWW!' |
| 276 andEventID:'OURL']; | 369 andEventID:'OURL']; |
| 277 | 370 |
| 278 // There better be no browser windows left at this point. | 371 // There better be no browser windows left at this point. |
| 279 CHECK_EQ(BrowserList::size(), 0u); | 372 CHECK_EQ(BrowserList::size(), 0u); |
| (...skipping 822 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1102 [appController showPreferencesWindow:nil page:page profile:profile]; | 1195 [appController showPreferencesWindow:nil page:page profile:profile]; |
| 1103 } | 1196 } |
| 1104 | 1197 |
| 1105 namespace app_controller_mac { | 1198 namespace app_controller_mac { |
| 1106 | 1199 |
| 1107 bool IsOpeningNewWindow() { | 1200 bool IsOpeningNewWindow() { |
| 1108 return g_is_opening_new_window; | 1201 return g_is_opening_new_window; |
| 1109 } | 1202 } |
| 1110 | 1203 |
| 1111 } // namespace app_controller_mac | 1204 } // namespace app_controller_mac |
| OLD | NEW |