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

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

Issue 8302021: Prevent extension and bookmark popups from interfering with close window/tab shortcuts. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Check for child windows Created 9 years, 2 months 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) 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/foundation_util.h" 10 #include "base/mac/foundation_util.h"
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 // Sync after a delay avoid I/O contention on startup; 1500 ms is plenty. 158 // Sync after a delay avoid I/O contention on startup; 1500 ms is plenty.
159 BrowserThread::PostDelayedTask(BrowserThread::FILE, FROM_HERE, 159 BrowserThread::PostDelayedTask(BrowserThread::FILE, FROM_HERE,
160 new PrefsSyncTask(), 1500); 160 new PrefsSyncTask(), 1500);
161 } 161 }
162 162
163 } // anonymous namespace 163 } // anonymous namespace
164 164
165 const AEEventClass kAECloudPrintInstallClass = 'GCPi'; 165 const AEEventClass kAECloudPrintInstallClass = 'GCPi';
166 const AEEventClass kAECloudPrintUninstallClass = 'GCPu'; 166 const AEEventClass kAECloudPrintUninstallClass = 'GCPu';
167 167
168 @interface NSWindow (AppControllerHelpers)
169 - (BOOL)isDescendantOf:(NSWindow*)other;
170 @end
171
172 @implementation NSWindow (AppControllerHelpers)
173 // Returns true if |self| is a descendant of the |other| window.
174 - (BOOL)isDescendantOf:(NSWindow*)other {
175 NSWindow* parent;
176 do {
177 parent = [self parentWindow];
178 if (parent == other)
179 return YES;
180 } while (parent);
181
182 return NO;
183 }
Scott Hess - ex-Googler 2011/10/25 23:40:59 I think this should probably be -isDescendentOfWin
Ilya Sherman 2011/10/26 23:22:40 I just added this because I wasn't sure if we coul
184 @end
185
168 @interface AppController (Private) 186 @interface AppController (Private)
169 - (void)initMenuState; 187 - (void)initMenuState;
170 - (void)initProfileMenu; 188 - (void)initProfileMenu;
171 - (void)updateConfirmToQuitPrefMenuItem:(NSMenuItem*)item; 189 - (void)updateConfirmToQuitPrefMenuItem:(NSMenuItem*)item;
172 - (void)registerServicesMenuTypesTo:(NSApplication*)app; 190 - (void)registerServicesMenuTypesTo:(NSApplication*)app;
173 - (void)openUrls:(const std::vector<GURL>&)urls; 191 - (void)openUrls:(const std::vector<GURL>&)urls;
174 - (void)getUrl:(NSAppleEventDescriptor*)event 192 - (void)getUrl:(NSAppleEventDescriptor*)event
175 withReply:(NSAppleEventDescriptor*)reply; 193 withReply:(NSAppleEventDescriptor*)reply;
176 - (void)submitCloudPrintJob:(NSAppleEventDescriptor*)event; 194 - (void)submitCloudPrintJob:(NSAppleEventDescriptor*)event;
177 - (void)installCloudPrint:(NSAppleEventDescriptor*)event; 195 - (void)installCloudPrint:(NSAppleEventDescriptor*)event;
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
345 if (!BrowserList::HasBrowserWithProfile([self lastProfile])) { 363 if (!BrowserList::HasBrowserWithProfile([self lastProfile])) {
346 // As we're shutting down, we need to nuke the TabRestoreService, which 364 // As we're shutting down, we need to nuke the TabRestoreService, which
347 // will start the shutdown of the NavigationControllers and allow for 365 // will start the shutdown of the NavigationControllers and allow for
348 // proper shutdown. If we don't do this, Chrome won't shut down cleanly, 366 // proper shutdown. If we don't do this, Chrome won't shut down cleanly,
349 // and may end up crashing when some thread tries to use the IO thread (or 367 // and may end up crashing when some thread tries to use the IO thread (or
350 // another thread) that is no longer valid. 368 // another thread) that is no longer valid.
351 TabRestoreServiceFactory::ResetForProfile([self lastProfile]); 369 TabRestoreServiceFactory::ResetForProfile([self lastProfile]);
352 } 370 }
353 } 371 }
354 372
355 // Helper routine to get the window controller if the key window is a tabbed
356 // window, or nil if not. Examples of non-tabbed windows are "about" or
357 // "preferences".
358 - (TabWindowController*)keyWindowTabController {
359 NSWindowController* keyWindowController =
360 [[NSApp keyWindow] windowController];
361 if ([keyWindowController isKindOfClass:[TabWindowController class]])
362 return (TabWindowController*)keyWindowController;
363
364 return nil;
365 }
366
367 // Helper routine to get the window controller if the main window is a tabbed
368 // window, or nil if not. Examples of non-tabbed windows are "about" or
369 // "preferences".
370 - (TabWindowController*)mainWindowTabController {
371 NSWindowController* mainWindowController =
372 [[NSApp mainWindow] windowController];
373 if ([mainWindowController isKindOfClass:[TabWindowController class]])
374 return (TabWindowController*)mainWindowController;
375
376 return nil;
377 }
378
379 // If the window has a tab controller, make "close window" be cmd-shift-w, 373 // If the window has a tab controller, make "close window" be cmd-shift-w,
380 // otherwise leave it as the normal cmd-w. Capitalization of the key equivalent 374 // otherwise leave it as the normal cmd-w. Capitalization of the key equivalent
381 // affects whether the shift modifer is used. 375 // affects whether the shift modifer is used.
382 - (void)adjustCloseWindowMenuItemKeyEquivalent:(BOOL)hasTabs { 376 - (void)adjustCloseWindowMenuItemKeyEquivalent:(BOOL)hasTabs {
383 [closeWindowMenuItem_ setKeyEquivalent:(hasTabs ? @"W" : @"w")]; 377 [closeWindowMenuItem_ setKeyEquivalent:(hasTabs ? @"W" : @"w")];
384 [closeWindowMenuItem_ setKeyEquivalentModifierMask:NSCommandKeyMask]; 378 [closeWindowMenuItem_ setKeyEquivalentModifierMask:NSCommandKeyMask];
385 } 379 }
386 380
387 // If the window has a tab controller, make "close tab" take over cmd-w, 381 // If the window has a tab controller, make "close tab" take over cmd-w,
388 // otherwise it shouldn't have any key-equivalent because it should be disabled. 382 // otherwise it shouldn't have any key-equivalent because it should be disabled.
(...skipping 10 matching lines...) Expand all
399 // Explicitly remove any command-key equivalents from the close tab/window 393 // Explicitly remove any command-key equivalents from the close tab/window
400 // menus so that nothing can go haywire if we get a user action during pending 394 // menus so that nothing can go haywire if we get a user action during pending
401 // updates. 395 // updates.
402 - (void)clearCloseMenuItemKeyEquivalents { 396 - (void)clearCloseMenuItemKeyEquivalents {
403 [closeTabMenuItem_ setKeyEquivalent:@""]; 397 [closeTabMenuItem_ setKeyEquivalent:@""];
404 [closeTabMenuItem_ setKeyEquivalentModifierMask:0]; 398 [closeTabMenuItem_ setKeyEquivalentModifierMask:0];
405 [closeWindowMenuItem_ setKeyEquivalent:@""]; 399 [closeWindowMenuItem_ setKeyEquivalent:@""];
406 [closeWindowMenuItem_ setKeyEquivalentModifierMask:0]; 400 [closeWindowMenuItem_ setKeyEquivalentModifierMask:0];
407 } 401 }
408 402
409 // See if we have a window with tabs open, and adjust the key equivalents for 403 // See if the focused window window has tabs, and adjust the key equivalents for
410 // Close Tab/Close Window accordingly. 404 // Close Tab/Close Window accordingly.
411 - (void)fixCloseMenuItemKeyEquivalents:(NSWindow*)window { 405 - (void)fixCloseMenuItemKeyEquivalents {
412 fileMenuUpdatePending_ = NO; 406 fileMenuUpdatePending_ = NO;
413 TabWindowController* tabController = [self keyWindowTabController]; 407
414 if (!tabController && ![NSApp keyWindow]) { 408 NSWindow* window = [NSApp keyWindow];
415 // There might be a small amount of time where there is no key window, 409 NSWindow* mainWindow = [NSApp mainWindow];
416 // so just use our main browser window if there is one. 410 if (!window || [window isDescendantOf:mainWindow]) {
Scott Hess - ex-Googler 2011/10/25 23:40:59 Wow, can window be nil and mainWindow not nil? Cr
Ilya Sherman 2011/10/26 23:22:40 Apparently, assuming the comment that used to be h
417 tabController = [self mainWindowTabController]; 411 // If the key window is a child of the main window (e.g. a bubble), the main
412 // window should be the one that handles the close menu item action.
413 // Also, there might be a small amount of time where there is no key window;
414 // in that case as well, just use our main browser window if there is one.
415 // You might think that we should just always use the main window, but the
416 // "About Chrome" window serves as a counterexample.
417 window = mainWindow;
418 } 418 }
419 BOOL hasTabs = !!tabController;
420 419
420 BOOL hasTabs =
421 [[window windowController] isKindOfClass:[TabWindowController class]];
421 [self adjustCloseWindowMenuItemKeyEquivalent:hasTabs]; 422 [self adjustCloseWindowMenuItemKeyEquivalent:hasTabs];
422 [self adjustCloseTabMenuItemKeyEquivalent:hasTabs]; 423 [self adjustCloseTabMenuItemKeyEquivalent:hasTabs];
423 } 424 }
424 425
425 // Fix up the "close tab/close window" command-key equivalents. We do this 426 // Fix up the "close tab/close window" command-key equivalents. We do this
426 // after a delay to ensure that window layer state has been set by the time 427 // after a delay to ensure that window layer state has been set by the time
427 // we do the enabling. This should only be called on the main thread, code that 428 // we do the enabling. This should only be called on the main thread, code that
428 // calls this (even as a side-effect) from other threads needs to be fixed. 429 // calls this (even as a side-effect) from other threads needs to be fixed.
429 - (void)delayedFixCloseMenuItemKeyEquivalents:(NSNotification*)notify { 430 - (void)delayedFixCloseMenuItemKeyEquivalents {
430 DCHECK([NSThread isMainThread]); 431 DCHECK([NSThread isMainThread]);
431 if (!fileMenuUpdatePending_) { 432 if (!fileMenuUpdatePending_) {
432 // The OS prefers keypresses to timers, so it's possible that a cmd-w 433 // The OS prefers keypresses to timers, so it's possible that a cmd-w
433 // can sneak in before this timer fires. In order to prevent that from 434 // can sneak in before this timer fires. In order to prevent that from
434 // having any bad consequences, just clear the keys combos altogether. They 435 // having any bad consequences, just clear the keys combos altogether. They
435 // will be reset when the timer eventually fires. 436 // will be reset when the timer eventually fires.
436 if ([NSThread isMainThread]) { 437 if ([NSThread isMainThread]) {
437 fileMenuUpdatePending_ = YES; 438 fileMenuUpdatePending_ = YES;
438 [self clearCloseMenuItemKeyEquivalents]; 439 [self clearCloseMenuItemKeyEquivalents];
439 [self performSelector:@selector(fixCloseMenuItemKeyEquivalents:) 440 [self performSelector:@selector(fixCloseMenuItemKeyEquivalents)
440 withObject:[notify object] 441 withObject:nil
441 afterDelay:0]; 442 afterDelay:0];
442 } else { 443 } else {
443 // This shouldn't be happening, but if it does, force it to the main 444 // This shouldn't be happening, but if it does, force it to the main
444 // thread to avoid dropping the update. Don't mess with 445 // thread to avoid dropping the update. Don't mess with
445 // |fileMenuUpdatePending_| as it's not expected to be threadsafe and 446 // |fileMenuUpdatePending_| as it's not expected to be threadsafe and
446 // there could be a race between the selector finishing and setting the 447 // there could be a race between the selector finishing and setting the
447 // flag. 448 // flag.
448 [self 449 [self
449 performSelectorOnMainThread:@selector(fixCloseMenuItemKeyEquivalents:) 450 performSelectorOnMainThread:@selector(fixCloseMenuItemKeyEquivalents)
450 withObject:[notify object] 451 withObject:nil
451 waitUntilDone:NO]; 452 waitUntilDone:NO];
452 } 453 }
453 } 454 }
454 } 455 }
455 456
456 // Called when we get a notification about the window layering changing to 457 // Called when we get a notification about the window layering changing to
457 // update the UI based on the new main window. 458 // update the UI based on the new main window.
458 - (void)windowLayeringDidChange:(NSNotification*)notify { 459 - (void)windowLayeringDidChange:(NSNotification*)notify {
459 [self delayedFixCloseMenuItemKeyEquivalents:notify]; 460 [self delayedFixCloseMenuItemKeyEquivalents];
460 461
461 if ([notify name] == NSWindowDidResignKeyNotification) { 462 if ([notify name] == NSWindowDidResignKeyNotification) {
462 // If a window is closed, this notification is fired but |[NSApp keyWindow]| 463 // If a window is closed, this notification is fired but |[NSApp keyWindow]|
463 // returns nil regardless of whether any suitable candidates for the key 464 // returns nil regardless of whether any suitable candidates for the key
464 // window remain. It seems that the new key window for the app is not set 465 // window remain. It seems that the new key window for the app is not set
465 // until after this notification is fired, so a check is performed after the 466 // until after this notification is fired, so a check is performed after the
466 // run loop is allowed to spin. 467 // run loop is allowed to spin.
467 [self performSelector:@selector(checkForAnyKeyWindows) 468 [self performSelector:@selector(checkForAnyKeyWindows)
468 withObject:nil 469 withObject:nil
469 afterDelay:0.0]; 470 afterDelay:0.0];
(...skipping 813 matching lines...) Expand 10 before | Expand all | Expand 10 after
1283 1284
1284 } // namespace browser 1285 } // namespace browser
1285 1286
1286 namespace app_controller_mac { 1287 namespace app_controller_mac {
1287 1288
1288 bool IsOpeningNewWindow() { 1289 bool IsOpeningNewWindow() {
1289 return g_is_opening_new_window; 1290 return g_is_opening_new_window;
1290 } 1291 }
1291 1292
1292 } // namespace app_controller_mac 1293 } // namespace app_controller_mac
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698