Index: chrome/browser/cocoa/tab_controller.mm |
diff --git a/chrome/browser/cocoa/tab_controller.mm b/chrome/browser/cocoa/tab_controller.mm |
index ef0455e24d1d73cd48a45df701c900162be6b992..2dee19c0d101df2d0c04472c2828275d2c7cdfd6 100644 |
--- a/chrome/browser/cocoa/tab_controller.mm |
+++ b/chrome/browser/cocoa/tab_controller.mm |
@@ -2,14 +2,18 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
+#import "chrome/browser/cocoa/tab_controller.h" |
+ |
+#import <Cocoa/Cocoa.h> |
+ |
#include "app/l10n_util_mac.h" |
#include "base/mac_util.h" |
#import "chrome/browser/browser_theme_provider.h" |
#import "chrome/browser/cocoa/menu_controller.h" |
-#import "chrome/browser/cocoa/tab_controller.h" |
#import "chrome/browser/cocoa/tab_controller_target.h" |
#import "chrome/browser/cocoa/tab_view.h" |
#import "chrome/browser/cocoa/themed_window.h" |
+#import "chrome/browser/cocoa/throbber_view.h" |
#include "grit/generated_resources.h" |
@implementation TabController |
@@ -75,6 +79,7 @@ class MenuDelegate : public menus::SimpleMenuModel::Delegate { |
+ (CGFloat)pinnedTabWidth { return 53; } |
- (TabView*)tabView { |
+ DCHECK([[self view] isKindOfClass:[TabView class]]); |
return static_cast<TabView*>([self view]); |
} |
@@ -105,8 +110,7 @@ class MenuDelegate : public menus::SimpleMenuModel::Delegate { |
// mark ourselves as needing a redraw. |
- (void)internalSetSelected:(BOOL)selected { |
selected_ = selected; |
- TabView* tabView = static_cast<TabView*>([self view]); |
- DCHECK([tabView isKindOfClass:[TabView class]]); |
+ TabView* tabView = [self tabView]; |
[tabView setState:selected]; |
[tabView cancelAlert]; |
[self updateVisibility]; |
@@ -120,12 +124,13 @@ class MenuDelegate : public menus::SimpleMenuModel::Delegate { |
originalIconFrame_ = [iconView_ frame]; |
// When the icon is removed, the title expands to the left to fill the space |
- // left by the icon. When the close button is removed, the title expands to |
- // the right to fill its space. These are the amounts to expand and contract |
- // titleView_ under those conditions. |
+ // left by the icon. This is the amounts to expand and contracttitleView_ |
+ // under those conditions. FIXME: update comment, simplify logic |
NSRect titleFrame = [titleView_ frame]; |
- iconTitleXOffset_ = NSMinX(titleFrame) - NSMinX(originalIconFrame_); |
- titleCloseWidthOffset_ = NSMaxX([closeButton_ frame]) - NSMaxX(titleFrame); |
+// iconTitleXOffset_ = NSMinX(titleFrame) - NSMinX(originalIconFrame_); |
+ iconTitleXOffset_ = NSMinX(titleFrame) - NSMaxX(originalIconFrame_); |
+ titleTabOffset_ = NSWidth([[self view] frame]) - NSMaxX(titleFrame); |
+ |
[self internalSetSelected:selected_]; |
} |
@@ -144,6 +149,25 @@ class MenuDelegate : public menus::SimpleMenuModel::Delegate { |
} |
- (IBAction)closeTab:(id)sender { |
+ if (![self closeButtonActive]) { |
+ |
+ NSEvent* down = [NSApp currentEvent]; |
+ NSEvent* fakeUp = [NSEvent mouseEventWithType:NSLeftMouseUp |
+ location:[down locationInWindow] |
+ modifierFlags:[down modifierFlags] |
+ timestamp:[down timestamp] |
+ windowNumber:[down windowNumber] |
+ context:[down context] |
+ eventNumber:0 // FIXME |
+ clickCount:1 |
+ pressure:0]; |
+ |
+ [closeButton_ mouseUp:fakeUp]; // clear "pressed" state |
+ [closeButton_ setState:NSOffState]; |
+ [[self view] mouseDown:[NSApp currentEvent]]; |
+ return; |
+ } |
+ |
if ([[self target] respondsToSelector:@selector(closeTab:)]) { |
[[self target] performSelector:@selector(closeTab:) |
withObject:[self view]]; |
@@ -152,11 +176,8 @@ class MenuDelegate : public menus::SimpleMenuModel::Delegate { |
- (void)setTitle:(NSString*)title { |
[[self view] setToolTip:title]; |
- if ([self pinned] && ![self selected]) { |
- TabView* tabView = static_cast<TabView*>([self view]); |
- DCHECK([tabView isKindOfClass:[TabView class]]); |
- [tabView startAlert]; |
- } |
+ if ([self pinned] && ![self selected]) |
+ [[self tabView] startAlert]; |
[super setTitle:title]; |
} |
@@ -190,86 +211,56 @@ class MenuDelegate : public menus::SimpleMenuModel::Delegate { |
return [[self view] toolTip]; |
} |
-// Return a rough approximation of the number of icons we could fit in the |
-// tab. We never actually do this, but it's a helpful guide for determining |
-// how much space we have available. |
-- (int)iconCapacity { |
- CGFloat width = NSMaxX([closeButton_ frame]) - NSMinX(originalIconFrame_); |
- CGFloat iconWidth = NSWidth(originalIconFrame_); |
- |
- return width / iconWidth; |
-} |
- |
-// Returns YES if we should show the icon. When tabs get too small, we clip |
-// the favicon before the close button for selected tabs, and prefer the |
-// favicon for unselected tabs. The icon can also be suppressed more directly |
-// by clearing iconView_. |
-- (BOOL)shouldShowIcon { |
- if (!iconView_) |
- return NO; |
- |
- if ([self pinned]) |
- return YES; |
- |
- int iconCapacity = [self iconCapacity]; |
- if ([self selected]) |
- return iconCapacity >= 2; |
- return iconCapacity >= 1; |
-} |
- |
-// Returns YES if we should be showing the close button. The selected tab |
-// always shows the close button. |
-- (BOOL)shouldShowCloseButton { |
- if ([self pinned]) |
- return NO; |
- return ([self selected] || [self iconCapacity] >= 3); |
-} |
- |
- (void)updateVisibility { |
- // iconView_ may have been replaced or it may be nil, so [iconView_ isHidden] |
- // won't work. Instead, the state of the icon is tracked separately in |
- // isIconShowing_. |
- BOOL oldShowIcon = isIconShowing_ ? YES : NO; |
- BOOL newShowIcon = [self shouldShowIcon] ? YES : NO; |
- |
- [iconView_ setHidden:newShowIcon ? NO : YES]; |
- isIconShowing_ = newShowIcon; |
- |
- // If the tab is pinned, hide the title. |
- [titleView_ setHidden:[self pinned]]; |
- |
- BOOL oldShowCloseButton = [closeButton_ isHidden] ? NO : YES; |
- BOOL newShowCloseButton = [self shouldShowCloseButton] ? YES : NO; |
- |
- [closeButton_ setHidden:newShowCloseButton ? NO : YES]; |
- |
- // Adjust the title view based on changes to the icon's and close button's |
- // visibility. |
- NSRect titleFrame = [titleView_ frame]; |
- |
- if (oldShowIcon != newShowIcon) { |
- // Adjust the left edge of the title view according to the presence or |
- // absence of the icon view. |
- |
- if (newShowIcon) { |
- titleFrame.origin.x += iconTitleXOffset_; |
- titleFrame.size.width -= iconTitleXOffset_; |
+ // Cocoa apparently gets confused if the title autoresizes too small, so |
+ // handle this manually. FIXME: comment slightly wrong |
+ CGFloat titleWidth = NSWidth([[self view] frame]) - |
+ titleTabOffset_ - |
+ NSMaxX(originalIconFrame_) - |
+ iconTitleXOffset_; |
+ |
+ bool showClose = NO; |
+ if ([[self tabView] isMouseInside]) { |
+ if ([self selected]) { |
+ showClose = YES; |
} else { |
- titleFrame.origin.x -= iconTitleXOffset_; |
- titleFrame.size.width += iconTitleXOffset_; |
+ // To make accidental tab closure less likely, only show the close button |
+ // on hover in background tabs if they are "wide enough". |
+ showClose = titleWidth >= 2*NSWidth(originalIconFrame_) || !iconView_; |
} |
+ } else if ([self selected]) { |
+ // FIXME: this is a bit of a hack; use an explicit method |
+ BOOL isLoading = [iconView_ isKindOfClass:[ThrobberView class]]; |
+ showClose = isLoading ? NO : YES; |
+ } else { |
+ // NTP should always show close, even if in background (it doesn't have |
+ // an icon). |
+ showClose = iconView_ ? NO : YES; |
} |
- if (oldShowCloseButton != newShowCloseButton) { |
- // Adjust the right edge of the title view according to the presence or |
- // absence of the close button. |
- if (newShowCloseButton) |
- titleFrame.size.width -= titleCloseWidthOffset_; |
- else |
- titleFrame.size.width += titleCloseWidthOffset_; |
+ if (titleWidth > 0) { |
+ NSRect titleFrame = [titleView_ frame]; |
+ titleFrame.size.width = titleWidth; |
+ [titleView_ setHidden:NO]; |
+ [titleView_ setFrame:titleFrame]; |
+ } else { |
+ [titleView_ setHidden:YES]; |
} |
- [titleView_ setFrame:titleFrame]; |
+ // Don't show icon if tab is not active and tab is very small. The tab strip |
+ // controller takes care to always keep the active tab wide enough for a close |
+ // button. |
+ if (NSWidth([[self view] frame]) >= [TabController minSelectedTabWidth]) { |
+ if (showClose && [closeButton_ isHidden]) { |
+ closeButtonRevealTime_ = [NSDate timeIntervalSinceReferenceDate]; |
+ } |
+ |
+ [closeButton_ setHidden:showClose ? NO : YES]; |
+ [iconView_ setHidden:showClose ? YES : NO]; |
+ } else { |
+ [closeButton_ setHidden:YES]; |
+ [iconView_ setHidden:YES]; |
+ } |
} |
- (void)updateTitleColor { |
@@ -288,10 +279,20 @@ class MenuDelegate : public menus::SimpleMenuModel::Delegate { |
[titleView_ setTextColor:titleColor ? titleColor : [NSColor textColor]]; |
} |
+- (BOOL)closeButtonActive { |
+ if ([closeButton_ isHidden]) return false; |
+ if ([self selected] || [self inRapidClosureMode]) return true; |
+ NSTimeInterval closeButtonScreenTime = |
+ [NSDate timeIntervalSinceReferenceDate] - closeButtonRevealTime_; |
+fprintf(stderr, " %f\n", closeButtonScreenTime); |
+ return ![closeButton_ isHidden] && closeButtonScreenTime > 1.0; |
+ |
+} |
+ |
// Called when our view is resized. If it gets too small, start by hiding |
// the close button and only show it if tab is selected. Eventually, hide the |
// icon as well. We know that this is for our view because we only registered |
-// for notifications from our specific view. |
+// for notifications from our specific view. FIXME: update comment |
- (void)viewResized:(NSNotification*)info { |
[self updateVisibility]; |
} |