summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorpinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-23 16:37:13 +0000
committerpinkerton@chromium.org <pinkerton@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-23 16:37:13 +0000
commit52a63f4d1c139345fb3fe0bc294ab27abfcd6db8 (patch)
tree033fe46019059f06d7b14990f45350543d713a84 /chrome
parentf15a3b036835167385507265692b626969b305f1 (diff)
downloadchromium_src-52a63f4d1c139345fb3fe0bc294ab27abfcd6db8.zip
chromium_src-52a63f4d1c139345fb3fe0bc294ab27abfcd6db8.tar.gz
chromium_src-52a63f4d1c139345fb3fe0bc294ab27abfcd6db8.tar.bz2
Implement side tab view and controller and hook up their creation. Parameterize tab strip layout so it can be vertical in addition to horizontal without breaking up the code too much. Abstracted some of the side tab knowledge into TabWindowController with overrides in BrowserWindowController.
Nib change: added a SideTabStripView custom view to BrowserWindow and hooked it to an outlet. Renamed the outlets to better reflect both views. BUG=44773 TEST=Tab layout, full screen, dragging tabs within and to other windows to make sure they reflow and draw correctly. Side tabs themselves are still behind a flag, but this cl touches many normal codepaths. Review URL: http://codereview.chromium.org/2846028 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@50606 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/app/nibs/BrowserWindow.xib96
-rw-r--r--chrome/browser/cocoa/browser_window_controller.mm30
-rw-r--r--chrome/browser/cocoa/browser_window_controller_private.h5
-rw-r--r--chrome/browser/cocoa/browser_window_controller_private.mm44
-rwxr-xr-xchrome/browser/cocoa/side_tab_strip_controller.h19
-rwxr-xr-xchrome/browser/cocoa/side_tab_strip_controller.mm29
-rwxr-xr-xchrome/browser/cocoa/side_tab_strip_view.h15
-rwxr-xr-xchrome/browser/cocoa/side_tab_strip_view.mm43
-rw-r--r--chrome/browser/cocoa/side_tab_strip_view_unittest.mm30
-rw-r--r--chrome/browser/cocoa/tab_strip_controller.h4
-rw-r--r--chrome/browser/cocoa/tab_strip_controller.mm127
-rw-r--r--chrome/browser/cocoa/tab_strip_view.h10
-rw-r--r--chrome/browser/cocoa/tab_strip_view.mm35
-rw-r--r--chrome/browser/cocoa/tab_window_controller.h29
-rw-r--r--chrome/browser/cocoa/tab_window_controller.mm102
-rw-r--r--chrome/chrome_browser.gypi4
-rw-r--r--chrome/chrome_tests.gypi1
17 files changed, 510 insertions, 113 deletions
diff --git a/chrome/app/nibs/BrowserWindow.xib b/chrome/app/nibs/BrowserWindow.xib
index 4d5564a..4345d67 100644
--- a/chrome/app/nibs/BrowserWindow.xib
+++ b/chrome/app/nibs/BrowserWindow.xib
@@ -2,14 +2,13 @@
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.03">
<data>
<int key="IBDocument.SystemTarget">1050</int>
- <string key="IBDocument.SystemVersion">9L30</string>
- <string key="IBDocument.InterfaceBuilderVersion">680</string>
+ <string key="IBDocument.SystemVersion">9L31a</string>
+ <string key="IBDocument.InterfaceBuilderVersion">677</string>
<string key="IBDocument.AppKitVersion">949.54</string>
<string key="IBDocument.HIToolboxVersion">353.00</string>
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
<bool key="EncodedWithXMLCoder">YES</bool>
- <integer value="56"/>
- <integer value="1"/>
+ <integer value="89"/>
</object>
<object class="NSArray" key="IBDocument.PluginDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -46,7 +45,7 @@
<string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string>
<string key="NSWindowContentMinSize">{400, 250}</string>
<object class="NSView" key="NSWindowView" id="1006">
- <reference key="NSNextResponder"/>
+ <nil key="NSNextResponder"/>
<int key="NSvFlags">256</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -59,14 +58,13 @@
</object>
</object>
<string key="NSFrameSize">{750, 600}</string>
- <reference key="NSSuperview"/>
</object>
<string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
<string key="NSMinSize">{400, 272}</string>
<string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string>
</object>
<object class="NSCustomView" id="1029219716">
- <reference key="NSNextResponder"/>
+ <nil key="NSNextResponder"/>
<int key="NSvFlags">266</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -96,9 +94,15 @@
</object>
</object>
<string key="NSFrameSize">{483, 36}</string>
- <reference key="NSSuperview"/>
<string key="NSClassName">TabStripView</string>
</object>
+ <object class="NSCustomView" id="529166964">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">272</int>
+ <string key="NSFrameSize">{236, 393}</string>
+ <reference key="NSSuperview"/>
+ <string key="NSClassName">SideTabStripView</string>
+ </object>
</object>
<object class="IBObjectContainer" key="IBDocument.Objects">
<object class="NSMutableArray" key="connectionRecords">
@@ -121,14 +125,6 @@
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
- <string key="label">tabStripView_</string>
- <reference key="source" ref="1001"/>
- <reference key="destination" ref="1029219716"/>
- </object>
- <int key="connectionID">65</int>
- </object>
- <object class="IBConnectionRecord">
- <object class="IBOutletConnection" key="connection">
<string key="label">tabContentArea_</string>
<reference key="source" ref="1001"/>
<reference key="destination" ref="1858870"/>
@@ -143,6 +139,22 @@
</object>
<int key="connectionID">87</int>
</object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">topTabStripView_</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="1029219716"/>
+ </object>
+ <int key="connectionID">88</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">sideTabStripView_</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="529166964"/>
+ </object>
+ <int key="connectionID">90</int>
+ </object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
@@ -221,6 +233,11 @@
<reference key="object" ref="1858870"/>
<reference key="parent" ref="1006"/>
</object>
+ <object class="IBObjectRecord">
+ <int key="objectID">89</int>
+ <reference key="object" ref="529166964"/>
+ <reference key="parent" ref="490739442"/>
+ </object>
</object>
</object>
<object class="NSMutableDictionary" key="flattenedProperties">
@@ -248,6 +265,8 @@
<string>66.IBPluginDependency</string>
<string>67.IBPluginDependency</string>
<string>84.IBPluginDependency</string>
+ <string>89.IBEditorWindowLastContentRect</string>
+ <string>89.IBPluginDependency</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -275,6 +294,8 @@
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>{{89, 611}, {236, 393}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
</object>
</object>
<object class="NSMutableDictionary" key="unlocalizedProperties">
@@ -297,7 +318,7 @@
</object>
</object>
<nil key="sourceID"/>
- <int key="maxID">87</int>
+ <int key="maxID">90</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
@@ -311,9 +332,16 @@
</object>
</object>
<object class="IBPartialClassDescription">
+ <string key="className">BrowserWindowController</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">browser/cocoa/browser_window_controller_private.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
<string key="className">ChromeBrowserWindow</string>
<string key="superclassName">ChromeEventProcessingWindow</string>
- <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="924273615">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">browser/cocoa/chrome_browser_window.h</string>
</object>
@@ -350,6 +378,20 @@
<string key="className">NSObject</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">../third_party/GTM/Foundation/GTMNSObject+KeyValueObserving.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">browser/cocoa/objc_zombie.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
<string key="minorKey">browser/cocoa/status_bubble_mac.h</string>
</object>
</object>
@@ -362,9 +404,21 @@
</object>
<object class="IBPartialClassDescription">
<string key="className">NSWindow</string>
+ <reference key="sourceIdentifier" ref="924273615"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSWindow</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
- <string key="minorKey">browser/cocoa/nswindow_local_state.h</string>
+ <string key="minorKey">browser/cocoa/themed_window.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">SideTabStripView</string>
+ <string key="superclassName">TabStripView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">browser/cocoa/side_tab_strip_view.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
@@ -386,11 +440,13 @@
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSMutableArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
+ <string>sideTabStripView_</string>
<string>tabContentArea_</string>
- <string>tabStripView_</string>
+ <string>topTabStripView_</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
+ <string>TabStripView</string>
<string>FastResizeView</string>
<string>TabStripView</string>
</object>
diff --git a/chrome/browser/cocoa/browser_window_controller.mm b/chrome/browser/cocoa/browser_window_controller.mm
index d189313..ccd632e 100644
--- a/chrome/browser/cocoa/browser_window_controller.mm
+++ b/chrome/browser/cocoa/browser_window_controller.mm
@@ -233,16 +233,7 @@
// this window's Browser and the tab strip view. The controller will handle
// registering for the appropriate tab notifications from the back-end and
// managing the creation of new tabs.
- if (![self useVerticalTabs]) {
- tabStripController_.reset([[TabStripController alloc]
- initWithView:[self tabStripView]
- switchView:[self tabContentArea]
- browser:browser_.get()]);
- } else {
- // TODO(pinkerton): Load SideTabController when written and add it to the
- // contentView. This should be abstracted into a separate method like
- // the toolbar controller initialization below.
- }
+ [self createTabStripController];
// Create the infobar container view, so we can pass it to the
// ToolbarController.
@@ -1299,8 +1290,6 @@
// (Override of |TabWindowController| method.)
- (BOOL)hasTabStrip {
- if ([self useVerticalTabs])
- return NO;
return [self supportsWindowFeature:Browser::FEATURE_TABSTRIP];
}
@@ -1638,14 +1627,15 @@ willAnimateFromState:(bookmarks::VisualState)oldState
isShrinkingFromZoomed_ = NO;
}
+// Override to swap in the correct tab strip controller based on the new
+// tab strip mode.
- (void)toggleTabStripDisplayMode {
- // TODO(pinkerton) re-initialize tab strip. Finish writing this method.
- // Right now, it only switches one direction, which clearly isn't cool.
- // [self initTabStrip:browser_->tabstrip_model()];
- [[self tabStripView] removeFromSuperview];
-
+ [super toggleTabStripDisplayMode];
+ [self createTabStripController];
+}
- [self layoutSubviews];
+- (BOOL)useVerticalTabs {
+ return browser_->tabstrip_model()->delegate()->UseVerticalTabs();
}
@end // @implementation BrowserWindowController
@@ -1699,7 +1689,7 @@ willAnimateFromState:(bookmarks::VisualState)oldState
// Retain the tab strip view while we remove it from its superview.
scoped_nsobject<NSView> tabStripView;
- if ([self hasTabStrip]) {
+ if ([self hasTabStrip] && ![self useVerticalTabs]) {
tabStripView.reset([[self tabStripView] retain]);
[tabStripView removeFromSuperview];
}
@@ -1745,7 +1735,7 @@ willAnimateFromState:(bookmarks::VisualState)oldState
// Add the tab strip after setting the content view and moving the incognito
// badge (if any), so that the tab strip will be on top (in the z-order).
- if ([self hasTabStrip])
+ if ([self hasTabStrip] && ![self useVerticalTabs])
[[[destWindow contentView] superview] addSubview:tabStripView];
[window setWindowController:nil];
diff --git a/chrome/browser/cocoa/browser_window_controller_private.h b/chrome/browser/cocoa/browser_window_controller_private.h
index 19573bd..a9915a7 100644
--- a/chrome/browser/cocoa/browser_window_controller_private.h
+++ b/chrome/browser/cocoa/browser_window_controller_private.h
@@ -16,8 +16,9 @@
// "dependencies").
@interface BrowserWindowController(Private)
-// Returns YES if vertical tabs are enabled for this browser.
-- (BOOL)useVerticalTabs;
+// Create the appropriate tab strip controller based on whether or not side
+// tabs are enabled. Replaces the current controller.
+- (void)createTabStripController;
// Saves the window's position in the local state preferences.
- (void)saveWindowPositionIfNeeded;
diff --git a/chrome/browser/cocoa/browser_window_controller_private.mm b/chrome/browser/cocoa/browser_window_controller_private.mm
index 2c707a1..9f14c2e 100644
--- a/chrome/browser/cocoa/browser_window_controller_private.mm
+++ b/chrome/browser/cocoa/browser_window_controller_private.mm
@@ -15,6 +15,7 @@
#import "chrome/browser/cocoa/find_bar_cocoa_controller.h"
#import "chrome/browser/cocoa/floating_bar_backing_view.h"
#import "chrome/browser/cocoa/fullscreen_controller.h"
+#import "chrome/browser/cocoa/side_tab_strip_controller.h"
#import "chrome/browser/cocoa/tab_strip_controller.h"
#import "chrome/browser/cocoa/tab_strip_view.h"
#import "chrome/browser/cocoa/toolbar_controller.h"
@@ -43,8 +44,17 @@ const CGFloat kLocBarBottomInset = 1;
@implementation BrowserWindowController(Private)
-- (BOOL)useVerticalTabs {
- return browser_->tabstrip_model()->delegate()->UseVerticalTabs();
+// Create the appropriate tab strip controller based on whether or not side
+// tabs are enabled.
+- (void)createTabStripController {
+ Class factory = [TabStripController class];
+ if ([self useVerticalTabs])
+ factory = [SideTabStripController class];
+
+ tabStripController_.reset([[factory alloc]
+ initWithView:[self tabStripView]
+ switchView:[self tabContentArea]
+ browser:browser_.get()]);
}
- (void)saveWindowPositionIfNeeded {
@@ -133,7 +143,7 @@ willPositionSheet:(NSWindow*)sheet
}
- (void)layoutSubviews {
- // With the exception of the tab strip, the subviews which we lay out are
+ // With the exception of the top tab strip, the subviews which we lay out are
// subviews of the content view, so we mainly work in the content view's
// coordinate system. Note, however, that the content view's coordinate system
// and the window's base coordinate system should coincide.
@@ -158,9 +168,9 @@ willPositionSheet:(NSWindow*)sheet
CGFloat maxY = NSMaxY(contentBounds) + yOffset;
CGFloat startMaxY = maxY;
- if ([self hasTabStrip]) {
- // If we need to lay out the tab strip, replace |maxY| and |startMaxY| with
- // higher values, and then lay out the tab strip.
+ if ([self hasTabStrip] && ![self useVerticalTabs]) {
+ // If we need to lay out the top tab strip, replace |maxY| and |startMaxY|
+ // with higher values, and then lay out the tab strip.
NSRect windowFrame = [contentView convertRect:[window frame] fromView:nil];
startMaxY = maxY = NSHeight(windowFrame) + yOffset;
maxY = [self layoutTabStripAtMaxY:maxY width:width fullscreen:isFullscreen];
@@ -170,22 +180,20 @@ willPositionSheet:(NSWindow*)sheet
DCHECK_GE(maxY, minY);
DCHECK_LE(maxY, NSMaxY(contentBounds) + yOffset);
- // Position the vertical tab strip on the left, taking up the entire height.
- // TODO(pinkerton): Make width not fixed.
- const CGFloat kSidebarWidth = 200.0;
+ // The base class already positions the side tab strip on the left side
+ // of the window's content area and sizes it to take the entire vertical
+ // height. All that's needed here is to push everything over to the right,
+ // if necessary.
if ([self useVerticalTabs]) {
- // TODO(pinkerton): Position the side bar at |minX| when the controller
- // is implemented.
-
- // Push everything else over to the right.
- minX += kSidebarWidth;
- width -= kSidebarWidth;
+ const CGFloat sideTabWidth = [[self tabStripView] bounds].size.width;
+ minX += sideTabWidth;
+ width -= sideTabWidth;
}
// Place the toolbar at the top of the reserved area.
maxY = [self layoutToolbarAtMinX:minX maxY:maxY width:width];
- // If we're not displaying the bookmark bar below the infobar, then it goes
+ // If we're not displaying the bookmark bar below the infobar, then it goes
// immediately below the toolbar.
BOOL placeBookmarkBarBelowInfoBar = [self placeBookmarkBarBelowInfoBar];
if (!placeBookmarkBarBelowInfoBar)
@@ -417,7 +425,9 @@ willPositionSheet:(NSWindow*)sheet
NSView* tabContentView = [self tabContentArea];
NSRect tabContentFrame = [tabContentView frame];
- bool contentShifted = NSMaxY(tabContentFrame) != NSMaxY(newFrame);
+ bool contentShifted =
+ NSMaxY(tabContentFrame) != NSMaxY(newFrame) ||
+ NSMinX(tabContentFrame) != NSMinX(newFrame);
tabContentFrame = newFrame;
[tabContentView setFrame:tabContentFrame];
diff --git a/chrome/browser/cocoa/side_tab_strip_controller.h b/chrome/browser/cocoa/side_tab_strip_controller.h
new file mode 100755
index 0000000..1961842
--- /dev/null
+++ b/chrome/browser/cocoa/side_tab_strip_controller.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+
+#import "chrome/browser/cocoa/tab_strip_controller.h"
+
+// A controller for the tab strip when side tabs are enabled.
+//
+// TODO(pinkerton): I'm expecting there are more things here that need
+// overriding rather than just tweaking a couple of settings, so I'm creating
+// a full-blown subclass. Clearly, very little is actually necessary at this
+// point for it to work.
+
+@interface SideTabStripController : TabStripController {
+}
+
+@end
diff --git a/chrome/browser/cocoa/side_tab_strip_controller.mm b/chrome/browser/cocoa/side_tab_strip_controller.mm
new file mode 100755
index 0000000..0f59329
--- /dev/null
+++ b/chrome/browser/cocoa/side_tab_strip_controller.mm
@@ -0,0 +1,29 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "chrome/browser/cocoa/side_tab_strip_controller.h"
+
+@implementation SideTabStripController
+
+// TODO(pinkerton): Still need to figure out several things:
+// - new tab button placement and layout
+// - animating tabs in and out
+// - being able to drop a tab elsewhere besides the 1st position
+// - how to load a different tab view nib for each tab.
+
+- (id)initWithView:(TabStripView*)view
+ switchView:(NSView*)switchView
+ browser:(Browser*)browser {
+ self = [super initWithView:view switchView:switchView browser:browser];
+ if (self) {
+ // Side tabs have no indent since they are not sharing space with the
+ // window controls.
+ [self setIndentForControls:0.0];
+ verticalLayout_ = YES;
+ }
+ return self;
+}
+
+@end
+
diff --git a/chrome/browser/cocoa/side_tab_strip_view.h b/chrome/browser/cocoa/side_tab_strip_view.h
new file mode 100755
index 0000000..b4b4629
--- /dev/null
+++ b/chrome/browser/cocoa/side_tab_strip_view.h
@@ -0,0 +1,15 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+
+#import "chrome/browser/cocoa/tab_strip_view.h"
+
+// A class that handles drawing the background of the tab strip when side tabs
+// are enabled.
+
+@interface SideTabStripView : TabStripView {
+}
+
+@end
diff --git a/chrome/browser/cocoa/side_tab_strip_view.mm b/chrome/browser/cocoa/side_tab_strip_view.mm
new file mode 100755
index 0000000..b7bebe0
--- /dev/null
+++ b/chrome/browser/cocoa/side_tab_strip_view.mm
@@ -0,0 +1,43 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "chrome/browser/cocoa/side_tab_strip_view.h"
+
+#include "base/scoped_nsobject.h"
+#import "third_party/GTM/AppKit/GTMNSColor+Luminance.h"
+
+@implementation SideTabStripView
+
+- (void)drawBorder:(NSRect)bounds {
+ // Draw a border on the right side.
+ NSRect borderRect, contentRect;
+ NSDivideRect(bounds, &borderRect, &contentRect, 1, NSMaxXEdge);
+ [[NSColor colorWithCalibratedWhite:0.0 alpha:0.2] set];
+ NSRectFillUsingOperation(borderRect, NSCompositeSourceOver);
+}
+
+// Override to prevent double-clicks from minimizing the window. The side
+// tab strip doesn't have that behavior (since it's in the window content
+// area).
+- (BOOL)doubleClickMinimizesWindow {
+ return NO;
+}
+
+- (void)drawRect:(NSRect)rect {
+ // BOOL isKey = [[self window] isKeyWindow];
+ NSColor* aColor =
+ [NSColor colorWithCalibratedRed:0.506 green:0.660 blue:0.985 alpha:1.000];
+ NSColor* bColor =
+ [NSColor colorWithCalibratedRed:0.099 green:0.140 blue:0.254 alpha:1.000];
+ scoped_nsobject<NSGradient> gradient(
+ [[NSGradient alloc] initWithStartingColor:aColor endingColor:bColor]);
+
+ NSRect gradientRect = [self bounds];
+ [gradient drawInRect:gradientRect angle:270.0];
+
+ // Draw borders and any drop feedback.
+ [super drawRect:rect];
+}
+
+@end
diff --git a/chrome/browser/cocoa/side_tab_strip_view_unittest.mm b/chrome/browser/cocoa/side_tab_strip_view_unittest.mm
new file mode 100644
index 0000000..79acebf
--- /dev/null
+++ b/chrome/browser/cocoa/side_tab_strip_view_unittest.mm
@@ -0,0 +1,30 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/scoped_nsobject.h"
+#import "chrome/browser/cocoa/side_tab_strip_view.h"
+#import "chrome/browser/cocoa/cocoa_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class SideTabStripViewTest : public CocoaTest {
+ public:
+ SideTabStripViewTest() {
+ NSRect frame = NSMakeRect(0, 0, 100, 30);
+ scoped_nsobject<SideTabStripView> view(
+ [[SideTabStripView alloc] initWithFrame:frame]);
+ view_ = view.get();
+ [[test_window() contentView] addSubview:view_];
+ }
+
+ SideTabStripView* view_;
+};
+
+TEST_VIEW(SideTabStripViewTest, view_)
+
+} // namespace
diff --git a/chrome/browser/cocoa/tab_strip_controller.h b/chrome/browser/cocoa/tab_strip_controller.h
index 005b9c7..5caf381 100644
--- a/chrome/browser/cocoa/tab_strip_controller.h
+++ b/chrome/browser/cocoa/tab_strip_controller.h
@@ -35,6 +35,10 @@ class ToolbarModel;
NSObject<TabControllerTarget,
URLDropTargetController,
GTMWindowSheetControllerDelegate> {
+ @protected
+ // YES if tabs are to be laid out vertically instead of horizontally.
+ BOOL verticalLayout_;
+
@private
TabContents* currentTab_; // weak, tab for which we're showing state
scoped_nsobject<TabStripView> tabStripView_;
diff --git a/chrome/browser/cocoa/tab_strip_controller.mm b/chrome/browser/cocoa/tab_strip_controller.mm
index 6bf651d..e721414 100644
--- a/chrome/browser/cocoa/tab_strip_controller.mm
+++ b/chrome/browser/cocoa/tab_strip_controller.mm
@@ -360,6 +360,35 @@ private:
[[newTabButton_ cell]
accessibilitySetOverrideValue:description
forAttribute:NSAccessibilityDescriptionAttribute];
+
+ // Controller may have been (re-)created by switching layout modes, which
+ // means the tab model is already fully formed with tabs. Need to walk the
+ // list and create the UI for each.
+ const int existingTabCount = tabStripModel_->count();
+ const TabContents* selection = tabStripModel_->GetSelectedTabContents();
+ for (int i = 0; i < existingTabCount; ++i) {
+ TabContents* currentContents = tabStripModel_->GetTabContentsAt(i);
+ [self insertTabWithContents:currentContents
+ atIndex:i
+ inForeground:NO];
+ if (selection == currentContents) {
+ // Must manually force a selection since the model won't send
+ // selection messages in this scenario.
+ [self selectTabWithContents:currentContents
+ previousContents:NULL
+ atIndex:i
+ userGesture:NO];
+ }
+ }
+ // Don't lay out the tabs until after the controller has been fully
+ // constructed. The |verticalLayout_| flag has not been initialized by
+ // subclasses at this point, which would cause layout to potentially use
+ // the wrong mode.
+ if (existingTabCount) {
+ [self performSelectorOnMainThread:@selector(layoutTabs)
+ withObject:nil
+ waitUntilDone:NO];
+ }
}
return self;
}
@@ -671,39 +700,47 @@ private:
// mini-tabs have a fixed width. We may not be able to use the entire width
// if the user is quickly closing tabs. This may be negative, but that's okay
// (taken care of by |MAX()| when calculating tab sizes).
- CGFloat availableWidth = 0;
- if ([self inRapidClosureMode]) {
- availableWidth = availableResizeWidth_;
+ CGFloat availableSpace = 0;
+ if (verticalLayout_) {
+ availableSpace = NSHeight([tabStripView_ bounds]);
} else {
- availableWidth = NSWidth([tabStripView_ frame]);
- // Account for the new tab button and the incognito badge.
- availableWidth -= NSWidth([newTabButton_ frame]) + kNewTabButtonOffset;
- if (browser_->profile()->IsOffTheRecord())
- availableWidth -= kIncognitoBadgeTabStripShrink;
+ if ([self inRapidClosureMode]) {
+ availableSpace = availableResizeWidth_;
+ } else {
+ availableSpace = NSWidth([tabStripView_ frame]);
+ // Account for the new tab button and the incognito badge.
+ availableSpace -= NSWidth([newTabButton_ frame]) + kNewTabButtonOffset;
+ if (browser_->profile()->IsOffTheRecord())
+ availableSpace -= kIncognitoBadgeTabStripShrink;
+ }
+ availableSpace -= [self indentForControls];
}
- availableWidth -= [self indentForControls];
// This may be negative, but that's okay (taken care of by |MAX()| when
- // calculating tab sizes).
- CGFloat availableWidthForNonMini = availableWidth -
- [self numberOfOpenMiniTabs] * (kMiniTabWidth - kTabOverlap);
+ // calculating tab sizes). "mini" tabs in horizontal mode just get a special
+ // section, they don't change size.
+ CGFloat availableSpaceForNonMini = availableSpace;
+ if (!verticalLayout_) {
+ availableSpaceForNonMini -=
+ [self numberOfOpenMiniTabs] * (kMiniTabWidth - kTabOverlap);
+ }
// Initialize |nonMiniTabWidth| in case there aren't any non-mini-tabs; this
// value shouldn't actually be used.
CGFloat nonMiniTabWidth = kMaxTabWidth;
const NSInteger numberOfOpenNonMiniTabs = [self numberOfOpenNonMiniTabs];
- if (numberOfOpenNonMiniTabs) { // Find the width of a non-mini-tab.
- // Add in the amount we "get back" from the tabs overlapping.
- availableWidthForNonMini += (numberOfOpenNonMiniTabs - 1) * kTabOverlap;
+ if (!verticalLayout_ && numberOfOpenNonMiniTabs) {
+ // Find the width of a non-mini-tab. This only applies to horizontal
+ // mode. Add in the amount we "get back" from the tabs overlapping.
+ availableSpaceForNonMini += (numberOfOpenNonMiniTabs - 1) * kTabOverlap;
// Divide up the space between the non-mini-tabs.
- nonMiniTabWidth = availableWidthForNonMini / numberOfOpenNonMiniTabs;
+ nonMiniTabWidth = availableSpaceForNonMini / numberOfOpenNonMiniTabs;
// Clamp the width between the max and min.
nonMiniTabWidth = MAX(MIN(nonMiniTabWidth, kMaxTabWidth), kMinTabWidth);
}
- const CGFloat minX = NSMinX(placeholderFrame_);
BOOL visible = [[tabStripView_ window] isVisible];
CGFloat offset = [self indentForControls];
@@ -717,9 +754,13 @@ private:
BOOL isPlaceholder = [[tab view] isEqual:placeholderTab_];
NSRect tabFrame = [[tab view] frame];
tabFrame.size.height = [[self class] defaultTabHeight] + 1;
- tabFrame.origin.y = 0;
- tabFrame.origin.x = offset;
-
+ if (verticalLayout_) {
+ tabFrame.origin.y = availableSpace - tabFrame.size.height - offset;
+ tabFrame.origin.x = 0;
+ } else {
+ tabFrame.origin.y = 0;
+ tabFrame.origin.x = offset;
+ }
// If the tab is hidden, we consider it a new tab. We make it visible
// and animate it in.
BOOL newTab = [[tab view] isHidden];
@@ -732,7 +773,10 @@ private:
// We need a duration or else it doesn't cancel an inflight animation.
ScopedNSAnimationContextGroup localAnimationGroup(animate);
localAnimationGroup.SetCurrentContextShortestDuration();
- tabFrame.origin.x = placeholderFrame_.origin.x;
+ if (verticalLayout_)
+ tabFrame.origin.y = availableSpace - tabFrame.size.height - offset;
+ else
+ tabFrame.origin.x = placeholderFrame_.origin.x;
// TODO(alcor): reenable this
//tabFrame.size.height += 10.0 * placeholderStretchiness_;
id target = animate ? [[tab view] animator] : [tab view];
@@ -745,13 +789,26 @@ private:
continue;
}
- // If our left edge is to the left of the placeholder's left, but our mid is
- // to the right of it we should slide over to make space for it.
- if (placeholderTab_ && !hasPlaceholderGap && NSMidX(tabFrame) > minX) {
- hasPlaceholderGap = true;
- offset += NSWidth(placeholderFrame_);
- offset -= kTabOverlap;
- tabFrame.origin.x = offset;
+ if (placeholderTab_ && !hasPlaceholderGap) {
+ const CGFloat placeholderMin =
+ verticalLayout_ ? NSMinY(placeholderFrame_) :
+ NSMinX(placeholderFrame_);
+ if (verticalLayout_) {
+ if (NSMidY(tabFrame) > placeholderMin) {
+ hasPlaceholderGap = true;
+ offset += NSHeight(placeholderFrame_);
+ tabFrame.origin.y = availableSpace - tabFrame.size.height - offset;
+ }
+ } else {
+ // If the left edge is to the left of the placeholder's left, but the
+ // mid is to the right of it slide over to make space for it.
+ if (NSMidX(tabFrame) > placeholderMin) {
+ hasPlaceholderGap = true;
+ offset += NSWidth(placeholderFrame_);
+ offset -= kTabOverlap;
+ tabFrame.origin.x = offset;
+ }
+ }
}
// Set the width. Selected tabs are slightly wider when things get really
@@ -762,6 +819,7 @@ private:
// 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).
+ // TODO(pinkerton): figure out vertical tab animations.
if (newTab && visible && animate) {
if (NSEqualRects(droppedTabFrame_, NSZeroRect)) {
[[tab view] setFrame:NSOffsetRect(tabFrame, 0, -NSHeight(tabFrame))];
@@ -784,8 +842,12 @@ private:
enclosingRect = NSUnionRect(tabFrame, enclosingRect);
- offset += NSWidth(tabFrame);
- offset -= kTabOverlap;
+ if (verticalLayout_) {
+ offset += NSHeight(tabFrame);
+ } else {
+ offset += NSWidth(tabFrame);
+ offset -= kTabOverlap;
+ }
i++;
}
@@ -797,7 +859,7 @@ private:
} else {
NSRect newTabNewFrame = [newTabButton_ frame];
// We've already ensured there's enough space for the new tab button
- // so we don't have to check it against the available width. We do need
+ // so we don't have to check it against the available space. We do need
// to make sure we put it after any placeholder.
newTabNewFrame.origin = NSMakePoint(offset, 0);
newTabNewFrame.origin.x = MAX(newTabNewFrame.origin.x,
@@ -1457,7 +1519,8 @@ private:
// transitory subviews (tabs). |-regenerateSubviewList| must be called to
// effectuate the addition.
- (void)addSubviewToPermanentList:(NSView*)aView {
- [permanentSubviews_ addObject:aView];
+ if (aView)
+ [permanentSubviews_ addObject:aView];
}
// Update the subviews, keeping the permanent ones (or, more correctly, putting
diff --git a/chrome/browser/cocoa/tab_strip_view.h b/chrome/browser/cocoa/tab_strip_view.h
index 6816348..770e83d 100644
--- a/chrome/browser/cocoa/tab_strip_view.h
+++ b/chrome/browser/cocoa/tab_strip_view.h
@@ -10,7 +10,8 @@
#include "base/scoped_nsobject.h"
#import "chrome/browser/cocoa/url_drop_target.h"
-// A view class that handles rendering the tab strip
+// A view class that handles rendering the tab strip and drops of URLS with
+// a positioning locator for drop feedback.
@interface TabStripView : NSView<URLDropTarget> {
@private
@@ -34,4 +35,11 @@
@end
+// Protected methods subclasses can override to alter behavior. Clients should
+// not call these directly.
+@interface TabStripView(Protected)
+- (void)drawBottomBorder:(NSRect)bounds;
+- (BOOL)doubleClickMinimizesWindow;
+@end
+
#endif // CHROME_BROWSER_COCOA_TAB_STRIP_VIEW_H_
diff --git a/chrome/browser/cocoa/tab_strip_view.mm b/chrome/browser/cocoa/tab_strip_view.mm
index 25ed090..5149dbf 100644
--- a/chrome/browser/cocoa/tab_strip_view.mm
+++ b/chrome/browser/cocoa/tab_strip_view.mm
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -28,21 +28,26 @@
return self;
}
-- (void)drawRect:(NSRect)rect {
- NSRect boundsRect = [self bounds];
+// Draw bottom border (a dark border and light highlight). Each tab is
+// responsible for mimicing this bottom border, unless it's the selected
+// tab.
+- (void)drawBorder:(NSRect)bounds {
NSRect borderRect, contentRect;
- // Draw bottom border (a dark border and light highlight). Each tab is
- // responsible for mimicing this bottom border, unless it's the selected
- // tab.
- borderRect = boundsRect;
+ borderRect = bounds;
borderRect.origin.y = 1;
borderRect.size.height = 1;
[[NSColor colorWithCalibratedWhite:0.0 alpha:0.2] set];
NSRectFillUsingOperation(borderRect, NSCompositeSourceOver);
- NSDivideRect(boundsRect, &borderRect, &contentRect, 1, NSMinYEdge);
+ NSDivideRect(bounds, &borderRect, &contentRect, 1, NSMinYEdge);
[[NSColor colorWithCalibratedWhite:0.96 alpha:1.0] set];
NSRectFillUsingOperation(borderRect, NSCompositeSourceOver);
+}
+
+- (void)drawRect:(NSRect)rect {
+ NSRect boundsRect = [self bounds];
+
+ [self drawBorder:boundsRect];
// Draw drop-indicator arrow (if appropriate).
// TODO(viettrungluu): this is all a stop-gap measure.
@@ -70,7 +75,7 @@
// Height we have to work with (insetting on the top).
CGFloat availableHeight =
- NSMaxY([self bounds]) - arrowTipPos.y - kArrowTopInset;
+ NSMaxY(boundsRect) - arrowTipPos.y - kArrowTopInset;
DCHECK(availableHeight >= 5);
// Based on the knobs above, calculate actual dimensions which we'll need
@@ -104,6 +109,12 @@
}
}
+// YES if a double-click in the background of the tab strip minimizes the
+// window.
+- (BOOL)doubleClickMinimizesWindow {
+ return YES;
+}
+
// We accept first mouse so clicks onto close/zoom/miniaturize buttons and
// title bar double-clicks are properly detected even when the window is in the
// background.
@@ -113,6 +124,12 @@
// Trap double-clicks and make them miniaturize the browser window.
- (void)mouseUp:(NSEvent*)event {
+ // Bail early if double-clicks are disabled.
+ if (![self doubleClickMinimizesWindow]) {
+ [super mouseUp:event];
+ return;
+ }
+
NSInteger clickCount = [event clickCount];
NSTimeInterval timestamp = [event timestamp];
diff --git a/chrome/browser/cocoa/tab_window_controller.h b/chrome/browser/cocoa/tab_window_controller.h
index 64fe78a..fbdb6da 100644
--- a/chrome/browser/cocoa/tab_window_controller.h
+++ b/chrome/browser/cocoa/tab_window_controller.h
@@ -17,6 +17,13 @@
// between tabs. It needs to be a regular NSView, not something like an NSBox
// because the TabStripController makes certain assumptions about how it can
// swap out subviews.
+//
+// The tab strip can exist in different orientations and window locations,
+// depending on the return value of -usesVerticalTabs. If NO (the default),
+// the tab strip is placed outside the window's content area, overlapping the
+// title area and window controls and will be stretched to fill the width
+// of the window. If YES, the tab strip is vertical and lives within the
+// window's content area. It will be stretched to fill the window's height.
#import <Cocoa/Cocoa.h>
@@ -30,13 +37,20 @@
@interface TabWindowController : NSWindowController<NSWindowDelegate> {
@private
IBOutlet FastResizeView* tabContentArea_;
- IBOutlet TabStripView* tabStripView_;
+ // TODO(pinkerton): Figure out a better way to initialize one or the other
+ // w/out needing both to be in the nib.
+ IBOutlet TabStripView* topTabStripView_;
+ IBOutlet TabStripView* sideTabStripView_;
NSWindow* overlayWindow_; // Used during dragging for window opacity tricks
NSView* cachedContentView_; // Used during dragging for identifying which
// view is the proper content area in the overlay
// (weak)
scoped_nsobject<NSMutableSet> lockedTabs_;
BOOL closeDeferred_; // If YES, call performClose: in removeOverlay:.
+ // Difference between height of window content area and height of the
+ // |tabContentArea_|. Calculated when the window is loaded from the nib and
+ // cached in order to restore the delta when switching tab modes.
+ CGFloat contentAreaHeightDelta_;
}
@property(readonly, nonatomic) TabStripView* tabStripView;
@property(readonly, nonatomic) FastResizeView* tabContentArea;
@@ -127,6 +141,11 @@
// if it does, NO otherwise). The default implementation returns YES.
- (BOOL)hasTabStrip;
+// Returns YES if the tab strip lives in the window content area alongside the
+// tab contents. Returns NO if the tab strip is outside the window content
+// area, along the top of the window.
+- (BOOL)useVerticalTabs;
+
// Get/set whether a particular tab is draggable between windows.
- (BOOL)isTabDraggable:(NSView*)tabView;
- (void)setTab:(NSView*)tabView isDraggable:(BOOL)draggable;
@@ -142,6 +161,14 @@
// Tells the tab strip to forget about this tab in preparation for it being
// put into a different tab strip, such as during a drop on another window.
- (void)detachTabView:(NSView*)view;
+
+// Toggles from one display mode of the tab strip to another. Will automatically
+// call -layoutSubviews to reposition other content.
+- (void)toggleTabStripDisplayMode;
+
+// Called when the size of the window content area has changed. Override to
+// position specific views. Base class implementation does nothing.
+- (void)layoutSubviews;
@end
#endif // CHROME_BROWSER_TAB_WINDOW_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/tab_window_controller.mm b/chrome/browser/cocoa/tab_window_controller.mm
index 2338483..0a7b696 100644
--- a/chrome/browser/cocoa/tab_window_controller.mm
+++ b/chrome/browser/cocoa/tab_window_controller.mm
@@ -39,7 +39,6 @@
@end
@implementation TabWindowController
-@synthesize tabStripView = tabStripView_;
@synthesize tabContentArea = tabContentArea_;
- (id)initWithWindow:(NSWindow*)window {
@@ -49,24 +48,93 @@
return self;
}
+// Add the side tab strip to the left side of the window's content area,
+// making it fill the full height of the content area.
+- (void)addSideTabStripToWindow {
+ NSView* contentView = [[self window] contentView];
+ NSRect contentFrame = [contentView frame];
+ NSRect sideStripFrame =
+ NSMakeRect(0, 0,
+ NSWidth([sideTabStripView_ frame]),
+ NSHeight(contentFrame));
+ [sideTabStripView_ setFrame:sideStripFrame];
+ [contentView addSubview:sideTabStripView_];
+}
+
+// Add the top tab strop to the window, above the content box and add it to the
+// view hierarchy as a sibling of the content view so it can overlap with the
+// window frame.
+- (void)addTopTabStripToWindow {
+ NSRect tabFrame =
+ NSMakeRect(0, NSMaxY(tabFrame),
+ NSWidth([tabContentArea_ frame]),
+ NSHeight([topTabStripView_ frame]));
+ [topTabStripView_ setFrame:tabFrame];
+ NSView* contentParent = [[[self window] contentView] superview];
+ [contentParent addSubview:topTabStripView_];
+}
+
- (void)windowDidLoad {
+ // Cache the difference in height between the window content area and the
+ // tab content area.
+ NSRect tabFrame = [tabContentArea_ frame];
+ NSRect contentFrame = [[[self window] contentView] frame];
+ contentAreaHeightDelta_ = NSHeight(contentFrame) - NSHeight(tabFrame);
+
if ([self hasTabStrip]) {
- // Place the tab bar above the content box and add it to the view hierarchy
- // as a sibling of the content view so it can overlap with the window frame.
- NSRect tabFrame = [tabContentArea_ frame];
- tabFrame.origin = NSMakePoint(0, NSMaxY(tabFrame));
- tabFrame.size.height = NSHeight([tabStripView_ frame]);
- [tabStripView_ setFrame:tabFrame];
- [[[[self window] contentView] superview] addSubview:tabStripView_];
+ if ([self useVerticalTabs]) {
+ // No top tabstrip so remove the tabContentArea offset.
+ tabFrame.size.height = contentFrame.size.height;
+ [tabContentArea_ setFrame:tabFrame];
+ [self addSideTabStripToWindow];
+ } else {
+ [self addTopTabStripToWindow];
+ }
} else {
- // No tabstrip so remove the tabContentArea offset.
- NSRect tabFrame = [tabContentArea_ frame];
- NSRect contentFrame = [[[self window] contentView] frame];
+ // No top tabstrip so remove the tabContentArea offset.
tabFrame.size.height = contentFrame.size.height;
[tabContentArea_ setFrame:tabFrame];
}
}
+// Toggles from one display mode of the tab strip to another. Will automatically
+// call -layoutSubviews to reposition other content.
+- (void)toggleTabStripDisplayMode {
+ // Adjust the size of the tab contents to either use more or less space,
+ // depending on the direction of the toggle. This needs to be done prior to
+ // adding back in the top tab strip as its position is based off the MaxY
+ // of the tab content area.
+ BOOL useVertical = [self useVerticalTabs];
+ NSRect tabContentsFrame = [tabContentArea_ frame];
+ tabContentsFrame.size.height += useVertical ?
+ contentAreaHeightDelta_ : -contentAreaHeightDelta_;
+ [tabContentArea_ setFrame:tabContentsFrame];
+
+ if (useVertical) {
+ // Remove the top tab strip and add the sidebar in.
+ [topTabStripView_ removeFromSuperview];
+ [self addSideTabStripToWindow];
+ } else {
+ // Remove the side tab strip and add the top tab strip as a sibling of the
+ // window's content area.
+ [sideTabStripView_ removeFromSuperview];
+ NSRect tabContentsFrame = [tabContentArea_ frame];
+ tabContentsFrame.size.height -= contentAreaHeightDelta_;
+ [tabContentArea_ setFrame:tabContentsFrame];
+ [self addTopTabStripToWindow];
+ }
+
+ [self layoutSubviews];
+}
+
+// Return the appropriate tab strip based on whether or not side tabs are
+// enabled.
+- (TabStripView*)tabStripView {
+ if ([self useVerticalTabs])
+ return sideTabStripView_;
+ return topTabStripView_;
+}
+
- (void)removeOverlay {
[self setUseOverlay:NO];
if (closeDeferred_) {
@@ -237,6 +305,12 @@
return YES;
}
+- (BOOL)useVerticalTabs {
+ // Subclasses should implement this.
+ NOTIMPLEMENTED();
+ return NO;
+}
+
- (BOOL)isTabDraggable:(NSView*)tabView {
return ![lockedTabs_ containsObject:tabView];
}
@@ -255,4 +329,10 @@
closeDeferred_ = YES;
}
+// Called when the size of the window content area has changed. Override to
+// position specific views. Base class implementation does nothing.
+- (void)layoutSubviews {
+ NOTIMPLEMENTED();
+}
+
@end
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 010a6ae..c01b309 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -853,6 +853,10 @@
'browser/cocoa/search_engine_list_model.h',
'browser/cocoa/search_engine_list_model.mm',
'browser/cocoa/shell_dialogs_mac.mm',
+ 'browser/cocoa/side_tab_strip_controller.h',
+ 'browser/cocoa/side_tab_strip_controller.mm',
+ 'browser/cocoa/side_tab_strip_view.h',
+ 'browser/cocoa/side_tab_strip_view.mm',
'browser/cocoa/status_bubble_mac.h',
'browser/cocoa/status_bubble_mac.mm',
'browser/cocoa/status_icons/status_icon_mac.h',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 17ec36b..03b41b2 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -734,6 +734,7 @@
'browser/cocoa/sad_tab_controller_unittest.mm',
'browser/cocoa/sad_tab_view_unittest.mm',
'browser/cocoa/search_engine_list_model_unittest.mm',
+ 'browser/cocoa/side_tab_strip_view_unittest.mm',
'browser/cocoa/status_bubble_mac_unittest.mm',
'browser/cocoa/status_icons/status_icon_mac_unittest.mm',
'browser/cocoa/styled_text_field_cell_unittest.mm',