Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(662)

Side by Side Diff: chrome/browser/app_controller_mac.mm

Issue 4220005: [Mac] Add a confirm to quit experiment to about:flags. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address comments Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698