Index: chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.mm |
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.mm |
index a0da0c0a6cdbf80225eedea43d9fb33ab7490ec8..ca1997740c1e134a73cc59f7e82fdbea52d9115d 100644 |
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.mm |
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_folder_controller.mm |
@@ -129,13 +129,18 @@ NSRect GetFirstButtonFrameForHeight(CGFloat height) { |
- (void)_updateTrackingAreas; |
@end |
-@interface BookmarkBarFolderController(Private) |
+@interface BookmarkBarFolderController () |
- (void)configureWindow; |
- (void)addOrUpdateScrollTracking; |
- (void)removeScrollTracking; |
- (void)endScroll; |
- (void)addScrollTimerWithDelta:(CGFloat)delta; |
+// Return the screen to which the menu should be restricted. The screen list is |
+// very volatile and can change with very short notice so it isn't worth |
+// caching. http://crbug.com/463458 |
+- (NSScreen*)menuScreen; |
+ |
// Helper function to configureWindow which performs a basic layout of |
// the window subviews, in particular the menu buttons and the window width. |
- (void)layOutWindowWithHeight:(CGFloat)height; |
@@ -261,33 +266,6 @@ NSRect GetFirstButtonFrameForHeight(CGFloat height) { |
// We want the button to remain bordered as part of the menu path. |
[button forceButtonBorderToStayOnAlways:YES]; |
- // Pick the parent button's screen to be the screen upon which all display |
- // happens. This loop over all screens is not equivalent to |
- // |[[button window] screen]|. BookmarkButtons are commonly positioned near |
- // the edge of their windows (both in the bookmark bar and in other bookmark |
- // menus), and |[[button window] screen]| would return the screen that the |
- // majority of their window was on even if the parent button were clearly |
- // contained within a different screen. |
- NSRect parentButtonGlobalFrame = |
- [button convertRect:[button bounds] toView:nil]; |
- parentButtonGlobalFrame.origin = |
- [[button window] convertBaseToScreen:parentButtonGlobalFrame.origin]; |
- for (NSScreen* screen in [NSScreen screens]) { |
- if (NSIntersectsRect([screen frame], parentButtonGlobalFrame)) { |
- screen_ = screen; |
- break; |
- } |
- } |
- if (!screen_) { |
- // The parent button is offscreen. The ideal thing to do would be to |
- // calculate the "closest" screen, the screen which has an edge parallel |
- // to, and the least distance from, one of the edges of the button. |
- // However, popping a subfolder from an offscreen button is an unrealistic |
- // edge case and so this ideal remains unrealized. Cheat instead; this |
- // code is wrong but a lot simpler. |
- screen_ = [[button window] screen]; |
- } |
- |
parentController_.reset([parentController retain]); |
if (!parentController_) |
[self setSubFolderGrowthToRight:YES]; |
@@ -468,6 +446,7 @@ NSRect GetFirstButtonFrameForHeight(CGFloat height) { |
// left but not in that order). Limit us to three tries in case |
// the folder window can't fit on either side of the screen; we |
// don't want to loop forever. |
+ NSRect screenVisibleFrame = [[self menuScreen] visibleFrame]; |
CGFloat x; |
int tries = 0; |
while (tries < 2) { |
@@ -477,9 +456,8 @@ NSRect GetFirstButtonFrameForHeight(CGFloat height) { |
x = NSMaxX([[parentButton_ window] frame]) - |
bookmarks::kBookmarkMenuOverlap; |
// If off the screen, switch direction. |
- if ((x + windowWidth + |
- bookmarks::kBookmarkHorizontalScreenPadding) > |
- NSMaxX([screen_ visibleFrame])) { |
+ if ((x + windowWidth + bookmarks::kBookmarkHorizontalScreenPadding) > |
+ NSMaxX(screenVisibleFrame)) { |
[self setSubFolderGrowthToRight:NO]; |
} else { |
return x; |
@@ -492,7 +470,7 @@ NSRect GetFirstButtonFrameForHeight(CGFloat height) { |
bookmarks::kBookmarkMenuOverlap - |
windowWidth; |
// If off the screen, switch direction. |
- if (x < NSMinX([screen_ visibleFrame])) { |
+ if (x < NSMinX(screenVisibleFrame)) { |
[self setSubFolderGrowthToRight:YES]; |
} else { |
return x; |
@@ -500,7 +478,7 @@ NSRect GetFirstButtonFrameForHeight(CGFloat height) { |
} |
} |
// Unhappy; do the best we can. |
- return NSMaxX([screen_ visibleFrame]) - windowWidth; |
+ return NSMaxX(screenVisibleFrame) - windowWidth; |
} |
@@ -530,26 +508,27 @@ NSRect GetFirstButtonFrameForHeight(CGFloat height) { |
// Make sure the window is on-screen; if not, push left or right. It is |
// intentional that top level folders "push left" or "push right" slightly |
// different than subfolders. |
- NSRect screenFrame = [screen_ visibleFrame]; |
+ NSRect screenVisibleFrame = [[self menuScreen] visibleFrame]; |
// Test if window goes off-screen on the right side. |
- CGFloat spillOff = (newWindowTopLeft.x + windowWidth) - NSMaxX(screenFrame); |
+ CGFloat spillOff = |
+ newWindowTopLeft.x + windowWidth - NSMaxX(screenVisibleFrame); |
if (spillOff > 0.0) { |
newWindowTopLeft.x = std::max(newWindowTopLeft.x - spillOff, |
- NSMinX(screenFrame)); |
- } else if (newWindowTopLeft.x < NSMinX(screenFrame)) { |
+ NSMinX(screenVisibleFrame)); |
+ } else if (newWindowTopLeft.x < NSMinX(screenVisibleFrame)) { |
// For left side. |
- newWindowTopLeft.x = NSMinX(screenFrame); |
+ newWindowTopLeft.x = NSMinX(screenVisibleFrame); |
} |
// The menu looks bad when it is squeezed up against the bottom of the |
// screen and ends up being only a few pixels tall. If it meets the |
// threshold for this case, instead show the menu above the button. |
CGFloat availableVerticalSpace = newWindowTopLeft.y - |
- (NSMinY(screenFrame) + bookmarks::kScrollWindowVerticalMargin); |
+ (NSMinY(screenVisibleFrame) + bookmarks::kScrollWindowVerticalMargin); |
if ((availableVerticalSpace < kMinSqueezedMenuHeight) && |
(windowHeight > availableVerticalSpace)) { |
newWindowTopLeft.y = std::min( |
newWindowTopLeft.y + windowHeight + NSHeight([parentButton_ frame]), |
- NSMaxY(screenFrame)); |
+ NSMaxY(screenVisibleFrame)); |
} |
} else { |
// Parent is a folder: expose as much as we can vertically; grow right/left. |
@@ -615,9 +594,9 @@ NSRect GetFirstButtonFrameForHeight(CGFloat height) { |
metrics.deltaScrollerHeight = 0.0; |
metrics.deltaScrollerY = 0.0; |
- metrics.minimumY = NSMinY([screen_ visibleFrame]) + |
+ metrics.minimumY = NSMinY([[self menuScreen] visibleFrame]) + |
bookmarks::kScrollWindowVerticalMargin; |
- metrics.screenBottomY = NSMinY([screen_ frame]); |
+ metrics.screenBottomY = NSMinY([[self menuScreen] frame]); |
metrics.oldWindowY = NSMinY(metrics.windowFrame); |
metrics.folderY = |
metrics.scrollerFrame.origin.y + metrics.visibleFrame.origin.y + |
@@ -632,7 +611,8 @@ NSRect GetFirstButtonFrameForHeight(CGFloat height) { |
effectiveFolderY -= metrics.windowSize.height; |
metrics.canScrollUp = effectiveFolderY < metrics.minimumY; |
CGFloat maximumY = |
- NSMaxY([screen_ visibleFrame]) - bookmarks::kScrollWindowVerticalMargin; |
+ NSMaxY([[self menuScreen] visibleFrame]) - |
+ bookmarks::kScrollWindowVerticalMargin; |
metrics.canScrollDown = metrics.folderTop > maximumY; |
// Accommodate changes in the bottom of the menu. |
@@ -707,7 +687,7 @@ NSRect GetFirstButtonFrameForHeight(CGFloat height) { |
} else { |
if (metrics.canScrollDown) { |
// Couldn't -> Can |
- const CGFloat maximumY = NSMaxY([screen_ visibleFrame]); |
+ const CGFloat maximumY = NSMaxY([[self menuScreen] visibleFrame]); |
metrics.deltaWindowHeight += (maximumY - NSMaxY(metrics.windowFrame)); |
metrics.deltaVisibleHeight -= bookmarks::kScrollWindowVerticalMargin; |
metrics.deltaScrollerHeight -= verticalScrollArrowHeight_; |
@@ -839,7 +819,7 @@ NSRect GetFirstButtonFrameForHeight(CGFloat height) { |
// Make sure as much of a submenu is exposed (which otherwise would be a |
// problem if the parent button is close to the bottom of the screen). |
if ([parentController_ isKindOfClass:[self class]]) { |
- CGFloat minimumY = NSMinY([screen_ visibleFrame]) + |
+ CGFloat minimumY = NSMinY([[self menuScreen] visibleFrame]) + |
bookmarks::kScrollWindowVerticalMargin + |
height; |
newWindowTopLeft.y = MAX(newWindowTopLeft.y, minimumY); |
@@ -984,6 +964,7 @@ NSRect GetFirstButtonFrameForHeight(CGFloat height) { |
(delta < 0.0 && ![scrollDownArrowView_ isHidden])) { |
NSWindow* window = [self window]; |
NSRect windowFrame = [window frame]; |
+ NSRect screenVisibleFrame = [[self menuScreen] visibleFrame]; |
NSPoint scrollPosition = [scrollView_ documentVisibleRect].origin; |
CGFloat scrollY = scrollPosition.y; |
NSRect scrollerFrame = [scrollView_ frame]; |
@@ -995,14 +976,13 @@ NSRect GetFirstButtonFrameForHeight(CGFloat height) { |
if (delta > 0.0) { |
// Scrolling up. |
- CGFloat minimumY = NSMinY([screen_ visibleFrame]) + |
+ CGFloat minimumY = NSMinY(screenVisibleFrame) + |
bookmarks::kScrollWindowVerticalMargin; |
CGFloat maxUpDelta = scrollY - offset + minimumY; |
delta = MIN(delta, maxUpDelta); |
} else { |
// Scrolling down. |
- NSRect screenFrame = [screen_ visibleFrame]; |
- CGFloat topOfScreen = NSMaxY(screenFrame); |
+ CGFloat topOfScreen = NSMaxY(screenVisibleFrame); |
NSRect folderFrame = [folderView_ frame]; |
CGFloat folderHeight = NSHeight(folderFrame); |
CGFloat folderTop = folderHeight - scrollY + offset; |
@@ -1040,6 +1020,32 @@ NSRect GetFirstButtonFrameForHeight(CGFloat height) { |
[[NSRunLoop mainRunLoop] addTimer:scrollTimer_ forMode:NSRunLoopCommonModes]; |
} |
+- (NSScreen*)menuScreen { |
+ // Return the parent button's screen for use as the screen upon which all |
+ // display happens. This loop over all screens is not equivalent to |
+ // |[[button window] screen]|. BookmarkButtons are commonly positioned near |
+ // the edge of their windows (both in the bookmark bar and in other bookmark |
+ // menus), and |[[button window] screen]| would return the screen that the |
+ // majority of their window was on even if the parent button were clearly |
+ // contained within a different screen. |
+ NSButton* button = parentButton_.get(); |
+ NSRect parentButtonGlobalFrame = |
+ [button convertRect:[button bounds] toView:nil]; |
+ parentButtonGlobalFrame.origin = |
+ [[button window] convertBaseToScreen:parentButtonGlobalFrame.origin]; |
+ for (NSScreen* screen in [NSScreen screens]) { |
+ if (NSIntersectsRect([screen frame], parentButtonGlobalFrame)) |
+ return screen; |
+ } |
+ |
+ // The parent button is offscreen. The ideal thing to do would be to calculate |
+ // the "closest" screen, the screen which has an edge parallel to, and the |
+ // least distance from, one of the edges of the button. However, popping a |
+ // subfolder from an offscreen button is an unrealistic edge case and so this |
+ // ideal remains unrealized. Cheat instead; this code is wrong but a lot |
+ // simpler. |
+ return [[button window] screen]; |
+} |
// Called as a result of our tracking area. Warning: on the main |
// screen (of a single-screened machine), the minimum mouse y value is |