Index: chrome/browser/cocoa/tab_strip_controller.mm |
diff --git a/chrome/browser/cocoa/tab_strip_controller.mm b/chrome/browser/cocoa/tab_strip_controller.mm |
index 029bdb7ee90a18afdd6435eb463cb4d70c068c04..46834b24d96445dd05cd9b3a0f69d440771183ec 100644 |
--- a/chrome/browser/cocoa/tab_strip_controller.mm |
+++ b/chrome/browser/cocoa/tab_strip_controller.mm |
@@ -576,16 +576,32 @@ private: |
if (!isClosingLastTab) { |
// Limit the width available for laying out tabs so that tabs are not |
// resized until a later time (when the mouse leaves the tab strip). |
- // TODO(pinkerton): re-visit when handling tab overflow. |
- // http://crbug.com/188 |
NSView* penultimateTab = [self viewAtIndex:numberOfOpenTabs - 2]; |
availableResizeWidth_ = NSMaxX([penultimateTab frame]); |
} else { |
// If the rightmost tab is closed, change the available width so that |
// another tab's close button lands below the cursor (assuming the tabs |
- // are currently below their maximum width and can grow). |
+ // are currently below their maximum width and can grow) if possible. |
NSView* lastTab = [self viewAtIndex:numberOfOpenTabs - 1]; |
availableResizeWidth_ = NSMaxX([lastTab frame]); |
+ |
+ // Since close buttons are on the left, this is a bit tricky. To make this |
+ // at all possible, the rightmost tab keeps its narrow pre-close width |
+ // and the other tabs expand to push it over. |
+ // Only do this if the other tabs can be pushed far enough, though. |
+ lastClosedTabWidth_.reset(); |
+ const CGFloat kPinnedTabWidth = [TabController pinnedTabWidth]; |
+ const CGFloat pinnedWidth = |
+ [self numberOfOpenPinnedTabs] * (kPinnedTabWidth - kTabOverlap); |
+ const CGFloat kMaxTabWidth = [TabController maxTabWidth]; |
+ const CGFloat unpinnedWidth = // 1 tab is candidate for being shorter |
+ ([self numberOfOpenUnpinnedTabs] - 1) * (kMaxTabWidth - kTabOverlap); |
+ CGFloat candidateWidth = NSWidth([lastTab frame]); |
+ // Technically, it should be |
+ // |pinnedWidth + unpinnedWidth + widthOfPartOfLastTabThatContainsClose|, |
+ // but that's complicated _and_ makes the last tab look very thin. |
+ if (pinnedWidth + unpinnedWidth >= availableResizeWidth_) |
+ lastClosedTabWidth_.reset(new CGFloat(candidateWidth)); |
} |
tabStripModel_->CloseTabContentsAt(index); |
} else { |
@@ -667,6 +683,8 @@ private: |
CGFloat availableWidth = 0; |
if ([self inRapidClosureMode]) { |
availableWidth = availableResizeWidth_; |
+ if (lastClosedTabWidth_.get()) |
+ availableWidth -= *lastClosedTabWidth_.get(); |
} else { |
availableWidth = NSWidth([tabStripView_ frame]); |
availableWidth -= NSWidth([newTabButton_ frame]) + kNewTabButtonOffset; |
@@ -681,10 +699,13 @@ private: |
// Initialize |unpinnedTabWidth| in case there aren't any unpinned tabs; this |
// value shouldn't actually be used. |
CGFloat unpinnedTabWidth = kMaxTabWidth; |
- const NSInteger numberOfOpenUnpinnedTabs = [self numberOfOpenUnpinnedTabs]; |
+ const NSInteger numberOfOpenUnpinnedTabs = [self numberOfOpenUnpinnedTabs] |
+ - (lastClosedTabWidth_.get() ? 1 : 0); |
if (numberOfOpenUnpinnedTabs) { // Find the width of an unpinned tab. |
// Add in the amount we "get back" from the tabs overlapping. |
availableWidthForUnpinned += (numberOfOpenUnpinnedTabs - 1) * kTabOverlap; |
+ if (lastClosedTabWidth_.get()) |
+ availableWidthForUnpinned += kTabOverlap; |
// Divide up the space between the unpinned tabs. |
unpinnedTabWidth = availableWidthForUnpinned / numberOfOpenUnpinnedTabs; |
@@ -697,13 +718,14 @@ private: |
BOOL visible = [[tabStripView_ window] isVisible]; |
CGFloat offset = [self indentForControls]; |
- NSUInteger i = 0; |
bool hasPlaceholderGap = false; |
+ int openTabCount = 0; |
for (TabController* tab in tabArray_.get()) { |
// Ignore a tab that is going through a close animation. |
if ([closingControllers_ containsObject:tab]) |
continue; |
+ ++openTabCount; |
BOOL isPlaceholder = [[tab view] isEqual:placeholderTab_]; |
NSRect tabFrame = [[tab view] frame]; |
tabFrame.size.height = [[self class] defaultTabHeight] + 1; |
@@ -750,6 +772,12 @@ private: |
if ([tab selected]) |
tabFrame.size.width = MAX(tabFrame.size.width, kMinSelectedTabWidth); |
+ // When in rapid-closure mode, treat the width of the last tab in a way |
+ // that its close button ends up below the cursor. |
+ BOOL isLastOpenTab = tabStripModel_->count() == openTabCount; |
+ if (isLastOpenTab && lastClosedTabWidth_.get()) |
+ tabFrame.size.width = *lastClosedTabWidth_.get(); |
+ |
// Animate a new tab in by putting it below the horizon unless told to put |
// it in a specific location (i.e., from a drop). |
if (newTab && visible && animate) { |
@@ -776,7 +804,6 @@ private: |
offset += NSWidth(tabFrame); |
offset -= kTabOverlap; |
- i++; |
} |
// Hide the new tab button if we're explicitly told to. It may already |
@@ -891,6 +918,7 @@ private: |
// If a tab is being inserted, we can again use the entire tab strip width |
// for layout. |
availableResizeWidth_ = kUseFullAvailableWidth; |
+ lastClosedTabWidth_.reset(); |
// We don't need to call |-layoutTabs| if the tab will be in the foreground |
// because it will get called when the new tab is selected by the tab model. |
@@ -1409,6 +1437,7 @@ private: |
mouseInside_ = NO; |
[self setTabTrackingAreasEnabled:NO]; |
availableResizeWidth_ = kUseFullAvailableWidth; |
+ lastClosedTabWidth_.reset(); |
[hoveredTab_ mouseExited:event]; |
hoveredTab_ = nil; |
[self layoutTabs]; |