summaryrefslogtreecommitdiffstats
path: root/chrome/browser/cocoa
diff options
context:
space:
mode:
authoralekseys@chromium.org <alekseys@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-09 18:11:57 +0000
committeralekseys@chromium.org <alekseys@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-09 18:11:57 +0000
commita578606f5e15b4db72928f955995e71a92b683f9 (patch)
tree188b1dec0f544a795dac8db48a0abe4aa7bbcf1c /chrome/browser/cocoa
parenta8c4602bfcedf0ad1ab0731bcfaa3da3c2e1cded (diff)
downloadchromium_src-a578606f5e15b4db72928f955995e71a92b683f9.zip
chromium_src-a578606f5e15b4db72928f955995e71a92b683f9.tar.gz
chromium_src-a578606f5e15b4db72928f955995e71a92b683f9.tar.bz2
Move devtools and sidebar handling to BWC and ensure the order of layout adjustments
during tab change updates to eliminate UI flickering. TabContents.xib changes: devtools and sidebar NSSplitViews removed (moved to BrowserWindow.xib), contentsContainer_ view removed (now it's inserted at runtime). BrowserWindow.xib chnages: devtools and sidebar NSSplitViews added into FastResizeView. BUG=22717, 31633 TEST=Run unit_tests, browser_tests and interactive_ui_tests. Open google.com in one tab (it's easy to spot content relayout on google.com), trigger an infobar and content scroll bar on another tab (ru.wikipedia.org with translation infobar will do), switch tabs back and forth. Content should not relayout, scroll bar should not "jump". Open new tab and make sure bookmark bar is not always visible, open any site which triggers infobar and big enough to show content scroll bar on another tab, switch tabs back and forth. Content should not relayout, scroolbar should not "jump". Repeat the tests above with sidebar opened on any of these tabs, page and sidebar content should not relayout, sidebar should stay the same width, scrollbar should not "jump". Repeat the tests above with devtools docked. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@58964 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/cocoa')
-rw-r--r--chrome/browser/cocoa/browser_window_controller.h13
-rw-r--r--chrome/browser/cocoa/browser_window_controller.mm123
-rw-r--r--chrome/browser/cocoa/browser_window_controller_private.mm8
-rw-r--r--chrome/browser/cocoa/dev_tools_controller.h48
-rw-r--r--chrome/browser/cocoa/dev_tools_controller.mm105
-rw-r--r--chrome/browser/cocoa/infobar_container_controller.h26
-rw-r--r--chrome/browser/cocoa/infobar_container_controller.mm66
-rw-r--r--chrome/browser/cocoa/infobar_container_controller_unittest.mm6
-rw-r--r--chrome/browser/cocoa/side_tab_strip_controller.mm8
-rw-r--r--chrome/browser/cocoa/sidebar_controller.h50
-rw-r--r--chrome/browser/cocoa/sidebar_controller.mm124
-rw-r--r--chrome/browser/cocoa/tab_contents_controller.h43
-rw-r--r--chrome/browser/cocoa/tab_contents_controller.mm175
-rw-r--r--chrome/browser/cocoa/tab_strip_controller.h29
-rw-r--r--chrome/browser/cocoa/tab_strip_controller.mm102
-rw-r--r--chrome/browser/cocoa/tab_strip_controller_unittest.mm19
-rw-r--r--chrome/browser/cocoa/tab_window_controller.h10
-rw-r--r--chrome/browser/cocoa/tab_window_controller.mm2
18 files changed, 591 insertions, 366 deletions
diff --git a/chrome/browser/cocoa/browser_window_controller.h b/chrome/browser/cocoa/browser_window_controller.h
index c971777..7bbbe96 100644
--- a/chrome/browser/cocoa/browser_window_controller.h
+++ b/chrome/browser/cocoa/browser_window_controller.h
@@ -17,7 +17,10 @@
#include "base/scoped_ptr.h"
#import "chrome/browser/cocoa/bookmark_bar_controller.h"
#import "chrome/browser/cocoa/bookmark_bubble_controller.h"
+#import "chrome/browser/cocoa/dev_tools_controller.h"
#import "chrome/browser/cocoa/browser_command_executor.h"
+#import "chrome/browser/cocoa/sidebar_controller.h"
+#import "chrome/browser/cocoa/tab_strip_controller.h"
#import "chrome/browser/cocoa/tab_window_controller.h"
#import "chrome/browser/cocoa/themed_window.h"
#import "chrome/browser/cocoa/url_drop_target.h"
@@ -39,7 +42,6 @@ class LocationBarViewMac;
class StatusBubbleMac;
class TabContents;
@class TabStripController;
-class TabStripModelObserverBridge;
@class TabStripView;
@class ToolbarController;
@@ -48,7 +50,10 @@ class TabStripModelObserverBridge;
TabWindowController<NSUserInterfaceValidations,
BookmarkBarControllerDelegate,
BrowserCommandExecutor,
- ViewResizer> {
+ ViewResizer,
+ DevToolsControllerDelegate,
+ SidebarControllerDelegate,
+ TabStripControllerDelegate> {
@private
// The ordering of these members is important as it determines the order in
// which they are destroyed. |browser_| needs to be destroyed last as most of
@@ -56,7 +61,6 @@ class TabStripModelObserverBridge;
// (tab/toolbar/bookmark models, profiles, etc).
scoped_ptr<Browser> browser_;
NSWindow* savedRegularWindow_;
- scoped_ptr<TabStripModelObserverBridge> tabObserver_;
scoped_ptr<BrowserWindowCocoa> windowShim_;
scoped_nsobject<ToolbarController> toolbarController_;
scoped_nsobject<TabStripController> tabStripController_;
@@ -64,6 +68,8 @@ class TabStripModelObserverBridge;
scoped_nsobject<InfoBarContainerController> infoBarContainerController_;
scoped_nsobject<DownloadShelfController> downloadShelfController_;
scoped_nsobject<BookmarkBarController> bookmarkBarController_;
+ scoped_nsobject<DevToolsController> devToolsController_;
+ scoped_nsobject<SidebarController> sidebarController_;
scoped_nsobject<FullscreenController> fullscreenController_;
// Strong. StatusBubble is a special case of a strong reference that
@@ -75,7 +81,6 @@ class TabStripModelObserverBridge;
BookmarkBubbleController* bookmarkBubbleController_; // Weak.
BOOL initializing_; // YES while we are currently in initWithBrowser:
BOOL ownsBrowser_; // Only ever NO when testing
- CGFloat verticalOffsetForStatusBubble_;
// The total amount by which we've grown the window up or down (to display a
// bookmark bar and/or download shelf), respectively; reset to 0 when moved
diff --git a/chrome/browser/cocoa/browser_window_controller.mm b/chrome/browser/cocoa/browser_window_controller.mm
index e4fc9ce..b2ec489 100644
--- a/chrome/browser/cocoa/browser_window_controller.mm
+++ b/chrome/browser/cocoa/browser_window_controller.mm
@@ -36,7 +36,6 @@
#import "chrome/browser/cocoa/status_bubble_mac.h"
#import "chrome/browser/cocoa/tab_contents_controller.h"
#import "chrome/browser/cocoa/tab_strip_controller.h"
-#import "chrome/browser/cocoa/tab_strip_model_observer_bridge.h"
#import "chrome/browser/cocoa/tab_strip_view.h"
#import "chrome/browser/cocoa/tab_view.h"
#import "chrome/browser/cocoa/tabpose_window.h"
@@ -56,7 +55,6 @@
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
-
// ORGANIZATION: This is a big file. It is (in principle) organized as follows
// (in order):
// 1. Interfaces. Very short, one-time-use classes may include an implementation
@@ -191,8 +189,6 @@
initializing_ = YES;
browser_.reset(browser);
ownsBrowser_ = ownIt;
- tabObserver_.reset(
- new TabStripModelObserverBridge(browser->tabstrip_model(), self));
NSWindow* window = [self window];
windowShim_.reset(new BrowserWindowCocoa(browser, self, window));
@@ -240,9 +236,7 @@
// Create the infobar container view, so we can pass it to the
// ToolbarController.
infoBarContainerController_.reset(
- [[InfoBarContainerController alloc]
- initWithTabStripModel:(browser_->tabstrip_model())
- resizeDelegate:self]);
+ [[InfoBarContainerController alloc] initWithResizeDelegate:self]);
[[[self window] contentView] addSubview:[infoBarContainerController_ view]];
// Create a controller for the toolbar, giving it the toolbar model object
@@ -276,6 +270,16 @@
relativeTo:[toolbarController_ view]];
[bookmarkBarController_ setBookmarkBarEnabled:[self supportsBookmarkBar]];
+ // Create a sub-controller for the docked devTools.
+ devToolsController_.reset(
+ [[DevToolsController alloc] initWithView:[self devToolsContainer]
+ delegate:self]);
+
+ // Create a sub-controller for the docked devTools.
+ sidebarController_.reset(
+ [[SidebarController alloc] initWithView:[self contentsContainer]
+ delegate:self]);
+
// We don't want to try and show the bar before it gets placed in its parent
// view, so this step shoudn't be inside the bookmark bar controller's
// |-awakeFromNib|.
@@ -396,11 +400,11 @@
}
- (void)updateDevToolsForContents:(TabContents*)contents {
- [tabStripController_ updateDevToolsForContents:contents];
+ [devToolsController_ updateDevToolsForTabContents:contents];
}
- (void)updateSidebarForContents:(TabContents*)contents {
- [tabStripController_ updateSidebarForContents:contents];
+ [sidebarController_ updateSidebarForTabContents:contents];
}
// Called when the user wants to close a window or from the shutdown process.
@@ -979,9 +983,13 @@
// StatusBubble delegate method: tell the status bubble how far above the bottom
// of the window it should position itself.
+// TODO(alekseys): status bubble should respect web view bounds, not just its
+// vertical size. Now it can overlap sidebar contents. http://crbug.com/54882
- (CGFloat)verticalOffsetForStatusBubble {
- return verticalOffsetForStatusBubble_ +
- [[tabStripController_ activeTabContentsController] devToolsHeight];
+ NSRect contents_bounds = [[self contentsContainer] bounds];
+ NSView* baseView = [[self window] contentView];
+ return NSMinY([baseView convertRect:contents_bounds
+ fromView:[self contentsContainer]]);
}
- (GTMWindowSheetController*)sheetController {
@@ -1297,41 +1305,90 @@
return [self supportsWindowFeature:Browser::FEATURE_TABSTRIP];
}
-- (void)selectTabWithContents:(TabContents*)newContents
- previousContents:(TabContents*)oldContents
- atIndex:(NSInteger)index
- userGesture:(bool)wasUserGesture {
- DCHECK(oldContents != newContents);
+// DevToolsController protocol.
+- (void)resizeDevToolsToNewHeight:(CGFloat)height {
+ NSSplitView* container = [self devToolsContainer];
+ NSArray* subviews = [container subviews];
+
+ // It seems as if |-setPosition:ofDividerAtIndex:| should do what's needed,
+ // but I can't figure out how to use it. Manually resize web and devtools.
+ // TODO(alekseys): either make setPosition:ofDividerAtIndex: work or to add a
+ // category on NSSplitView to handle manual resizing.
+ NSView* devToolsView = [subviews objectAtIndex:1];
+ NSRect devToolsFrame = [devToolsView frame];
+ devToolsFrame.size.height = height;
+ [devToolsView setFrame:devToolsFrame];
+
+ NSView* webView = [subviews objectAtIndex:0];
+ NSRect webFrame = [webView frame];
+ webFrame.size.height =
+ NSHeight([container frame]) - ([container dividerThickness] + height);
+ [webView setFrame:webFrame];
+
+ [container adjustSubviews];
+}
+
+// SidebarController protocol.
+- (void)resizeSidebarToNewWidth:(CGFloat)width {
+ NSSplitView* container = [self contentsContainer];
+ NSArray* subviews = [container subviews];
+
+ // It seems as if |-setPosition:ofDividerAtIndex:| should do what's needed,
+ // but I can't figure out how to use it. Manually resize web and sidebar.
+ // TODO(alekseys): either make setPosition:ofDividerAtIndex: work or to add a
+ // category on NSSplitView to handle manual resizing.
+ NSView* sidebarView = [subviews objectAtIndex:1];
+ NSRect sidebarFrame = [sidebarView frame];
+ sidebarFrame.size.width = width;
+ [sidebarView setFrame:sidebarFrame];
+
+ NSView* webView = [subviews objectAtIndex:0];
+ NSRect webFrame = [webView frame];
+ webFrame.size.width =
+ NSWidth([container frame]) - ([container dividerThickness] + width);
+ [webView setFrame:webFrame];
+ [container adjustSubviews];
+}
+
+// TabStripControllerDelegate protocol.
+- (void)onSelectTabWithContents:(TabContents*)contents {
// Update various elements that are interested in knowing the current
// TabContents.
// Update all the UI bits.
windowShim_->UpdateTitleBar();
+ [self updateSidebarForContents:contents];
+ [self updateDevToolsForContents:contents];
+
// Update the bookmark bar.
+ // Must do it after sidebar and devtools update, otherwise bookmark bar might
+ // call resizeView -> layoutSubviews and cause unnecessary relayout.
// TODO(viettrungluu): perhaps update to not terminate running animations (if
// applicable)?
[self updateBookmarkBarVisibilityWithAnimation:NO];
+
+ [infoBarContainerController_ changeTabContents:contents];
}
-- (void)tabChangedWithContents:(TabContents*)contents
- atIndex:(NSInteger)index
- changeType:(TabStripModelObserver::TabChangeType)change {
- if (index == browser_->tabstrip_model()->selected_index()) {
- // Update titles if this is the currently selected tab and if it isn't just
- // the loading state which changed.
- if (change != TabStripModelObserver::LOADING_ONLY)
- windowShim_->UpdateTitleBar();
-
- // Update the bookmark bar if this is the currently selected tab and if it
- // isn't just the title which changed. This for transitions between the NTP
- // (showing its floating bookmark bar) and normal web pages (showing no
- // bookmark bar).
- // TODO(viettrungluu): perhaps update to not terminate running animations?
- if (change != TabStripModelObserver::TITLE_NOT_LOADING)
- [self updateBookmarkBarVisibilityWithAnimation:NO];
- }
+- (void)onSelectedTabChange:(TabStripModelObserver::TabChangeType)change {
+ // Update titles if this is the currently selected tab and if it isn't just
+ // the loading state which changed.
+ if (change != TabStripModelObserver::LOADING_ONLY)
+ windowShim_->UpdateTitleBar();
+
+ // Update the bookmark bar if this is the currently selected tab and if it
+ // isn't just the title which changed. This for transitions between the NTP
+ // (showing its floating bookmark bar) and normal web pages (showing no
+ // bookmark bar).
+ // TODO(viettrungluu): perhaps update to not terminate running animations?
+ if (change != TabStripModelObserver::TITLE_NOT_LOADING)
+ [self updateBookmarkBarVisibilityWithAnimation:NO];
+}
+
+- (void)onTabDetachedWithContents:(TabContents*)contents {
+ [infoBarContainerController_ tabDetachedWithContents:contents];
}
- (void)userChangedTheme {
diff --git a/chrome/browser/cocoa/browser_window_controller_private.mm b/chrome/browser/cocoa/browser_window_controller_private.mm
index 35ea1e0..1fbd31e 100644
--- a/chrome/browser/cocoa/browser_window_controller_private.mm
+++ b/chrome/browser/cocoa/browser_window_controller_private.mm
@@ -52,8 +52,9 @@ const CGFloat kLocBarBottomInset = 1;
tabStripController_.reset([[factory alloc]
initWithView:[self tabStripView]
- switchView:[self tabContentArea]
- browser:browser_.get()]);
+ switchView:[self contentsContainer]
+ browser:browser_.get()
+ delegate:self]);
}
- (void)saveWindowPositionIfNeeded {
@@ -229,9 +230,6 @@ willPositionSheet:(NSWindow*)sheet
NSRect contentAreaRect = NSMakeRect(minX, minY, width, maxY - minY);
[self layoutTabContentArea:contentAreaRect];
- // Place the status bubble at the bottom of the content area.
- verticalOffsetForStatusBubble_ = minY;
-
// Normally, we don't need to tell the toolbar whether or not to show the
// divider, but things break down during animation.
[toolbarController_
diff --git a/chrome/browser/cocoa/dev_tools_controller.h b/chrome/browser/cocoa/dev_tools_controller.h
new file mode 100644
index 0000000..1d6254e5
--- /dev/null
+++ b/chrome/browser/cocoa/dev_tools_controller.h
@@ -0,0 +1,48 @@
+// 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.
+
+#ifndef CHROME_BROWSER_COCOA_DEV_TOOLS_CONTROLLER_H_
+#define CHROME_BROWSER_COCOA_DEV_TOOLS_CONTROLLER_H_
+#pragma once
+
+#import <Foundation/Foundation.h>
+
+#include "base/scoped_nsobject.h"
+
+@class NSSplitView;
+@class NSView;
+
+class TabContents;
+
+// DevTools controller's delegate interface. Delegate is responsible
+// for the actual subviews resize and layout.
+@protocol DevToolsControllerDelegate
+
+// Resizes the devTools view to the new |height| and adjusts window layout
+// accordingly.
+- (void)resizeDevToolsToNewHeight:(CGFloat)height;
+
+@end
+
+// A class that handles updates of the devTools view within a browser window.
+// It swaps in the relevant devTools contents for a given TabContents or removes
+// the vew, if there's no devTools contents to show.
+@interface DevToolsController : NSObject {
+ @private
+ // A view hosting docked devTools contents.
+ scoped_nsobject<NSSplitView> devToolsView_;
+ id<DevToolsControllerDelegate> delegate_; // weak
+}
+
+- (id)initWithView:(NSSplitView*)devToolsView
+ delegate:(id<DevToolsControllerDelegate>)delegate;
+
+// Depending on |contents|'s state, decides whether the docked web inspector
+// should be shown or hidden and adjusts its height (|delegate_| handles
+// the actual resize).
+- (void)updateDevToolsForTabContents:(TabContents*)contents;
+
+@end
+
+#endif // CHROME_BROWSER_COCOA_DEV_TOOLS_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/dev_tools_controller.mm b/chrome/browser/cocoa/dev_tools_controller.mm
new file mode 100644
index 0000000..1a7e3b6
--- /dev/null
+++ b/chrome/browser/cocoa/dev_tools_controller.mm
@@ -0,0 +1,105 @@
+// 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/dev_tools_controller.h"
+
+#include <algorithm>
+
+#include <Cocoa/Cocoa.h>
+
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_process.h"
+#import "chrome/browser/cocoa/view_id_util.h"
+#include "chrome/browser/debugger/devtools_window.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/pref_names.h"
+
+namespace {
+
+// Default offset of the contents splitter in pixels.
+const int kDefaultContentsSplitOffset = 400;
+
+// Never make the web part of the tab contents smaller than this (needed if the
+// window is only a few pixels high).
+const int kMinWebHeight = 50;
+
+} // end namespace
+
+
+@interface DevToolsController (Private)
+- (void)showDevToolsContents:(TabContents*)devToolsContents;
+@end
+
+
+@implementation DevToolsController
+
+- (id)initWithView:(NSSplitView*)devToolsView
+ delegate:(id<DevToolsControllerDelegate>)delegate {
+ DCHECK(delegate);
+ if ((self = [super init])) {
+ devToolsView_.reset([devToolsView retain]);
+ delegate_ = delegate;
+ }
+ return self;
+}
+
+- (void)updateDevToolsForTabContents:(TabContents*)contents {
+ // Get current devtools content.
+ TabContents* devToolsContents = contents ?
+ DevToolsWindow::GetDevToolsContents(contents) : NULL;
+
+ [self showDevToolsContents:devToolsContents];
+}
+
+- (void)showDevToolsContents:(TabContents*)devToolsContents {
+ NSArray* subviews = [devToolsView_ subviews];
+ if (devToolsContents) {
+ DCHECK_GE([subviews count], 1u);
+
+ // |devToolsView| is a TabContentsViewCocoa object, whose ViewID was
+ // set to VIEW_ID_TAB_CONTAINER initially, so we need to change it to
+ // VIEW_ID_DEV_TOOLS_DOCKED here.
+ NSView* devToolsView = devToolsContents->GetNativeView();
+ view_id_util::SetID(devToolsView, VIEW_ID_DEV_TOOLS_DOCKED);
+
+ CGFloat splitOffset = 0;
+ if ([subviews count] == 1) {
+ // Load the default split offset.
+ splitOffset = g_browser_process->local_state()->GetInteger(
+ prefs::kDevToolsSplitLocation);
+ if (splitOffset < 0) {
+ // Initial load, set to default value.
+ splitOffset = kDefaultContentsSplitOffset;
+ }
+ [devToolsView_ addSubview:devToolsView];
+ } else {
+ DCHECK_EQ([subviews count], 2u);
+ // If devtools are already visible, keep the current size.
+ splitOffset = NSHeight([devToolsView frame]);
+ [devToolsView_ replaceSubview:[subviews objectAtIndex:1]
+ with:devToolsView];
+ }
+
+ // Make sure |splitOffset| isn't too large or too small.
+ splitOffset =
+ std::min(splitOffset, NSHeight([devToolsView_ frame]) - kMinWebHeight);
+ DCHECK_GE(splitOffset, 0) << "kMinWebHeight needs to be smaller than "
+ << "smallest available tab contents space.";
+ splitOffset = std::max(static_cast<CGFloat>(0), splitOffset);
+
+ [delegate_ resizeDevToolsToNewHeight:splitOffset];
+ } else {
+ if ([subviews count] > 1) {
+ NSView* oldDevToolsContentsView = [subviews objectAtIndex:1];
+ // Store split offset when hiding devtools window only.
+ int splitOffset = NSHeight([oldDevToolsContentsView frame]);
+ g_browser_process->local_state()->SetInteger(
+ prefs::kDevToolsSplitLocation, splitOffset);
+ [oldDevToolsContentsView removeFromSuperview];
+ }
+ }
+}
+
+@end
diff --git a/chrome/browser/cocoa/infobar_container_controller.h b/chrome/browser/cocoa/infobar_container_controller.h
index 81e82f4..495b6e8 100644
--- a/chrome/browser/cocoa/infobar_container_controller.h
+++ b/chrome/browser/cocoa/infobar_container_controller.h
@@ -2,6 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#ifndef CHROME_BROWSER_COCOA_INFOBAR_CONTAINER_CONTROLLER_H_
+#define CHROME_BROWSER_COCOA_INFOBAR_CONTAINER_CONTROLLER_H_
+#pragma once
+
#import <Cocoa/Cocoa.h>
#include "base/scoped_nsobject.h"
@@ -14,7 +18,6 @@ class InfoBarDelegate;
class InfoBarNotificationObserver;
class TabContents;
class TabStripModel;
-class TabStripModelObserverBridge;
// Protocol for basic container methods, as needed by an InfoBarController.
// This protocol exists to make mocking easier in unittests.
@@ -40,9 +43,6 @@ class TabStripModelObserverBridge;
// Holds the InfoBarControllers currently owned by this container.
scoped_nsobject<NSMutableArray> infobarControllers_;
- // Lets us get TabChanged/TabDetachedAt notifications.
- scoped_ptr<TabStripModelObserverBridge> tabObserver_;
-
// Lets us registers for INFOBAR_ADDED/INFOBAR_REMOVED
// notifications. The actual notifications are sent to the
// InfoBarNotificationObserver object, which proxies them back to us.
@@ -50,8 +50,7 @@ class TabStripModelObserverBridge;
scoped_ptr<InfoBarNotificationObserver> infoBarObserver_;
}
-- (id)initWithTabStripModel:(TabStripModel*)model
- resizeDelegate:(id<ViewResizer>)resizeDelegate;
+- (id)initWithResizeDelegate:(id<ViewResizer>)resizeDelegate;
// Informs the selected TabContents that the infobars for the given
// |delegate| need to be removed. Does not remove any infobar views
@@ -65,6 +64,19 @@ class TabStripModelObserverBridge;
// |controller| is still on the call stack.
- (void)removeController:(InfoBarController*)controller;
+// Modifies this container to display infobars for the given
+// |contents|. Registers for INFOBAR_ADDED and INFOBAR_REMOVED
+// notifications for |contents|. If we are currently showing any
+// infobars, removes them first and deregisters for any
+// notifications. |contents| can be NULL, in which case no infobars
+// are shown and no notifications are registered for.
+- (void)changeTabContents:(TabContents*)contents;
+
+// Stripped down version of TabStripModelObserverBridge:tabDetachedWithContents.
+// Forwarded by BWC. Removes all infobars and deregisters for any notifications
+// if |contents| is the current tab contents.
+- (void)tabDetachedWithContents:(TabContents*)contents;
+
@end
@@ -97,3 +109,5 @@ class TabStripModelObserverBridge;
- (void)removeAllInfoBars;
@end
+
+#endif // CHROME_BROWSER_COCOA_INFOBAR_CONTAINER_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/infobar_container_controller.mm b/chrome/browser/cocoa/infobar_container_controller.mm
index 374d920..7fe8aed 100644
--- a/chrome/browser/cocoa/infobar_container_controller.mm
+++ b/chrome/browser/cocoa/infobar_container_controller.mm
@@ -8,7 +8,6 @@
#include "chrome/browser/cocoa/infobar.h"
#import "chrome/browser/cocoa/infobar_container_controller.h"
#import "chrome/browser/cocoa/infobar_controller.h"
-#include "chrome/browser/cocoa/tab_strip_model_observer_bridge.h"
#import "chrome/browser/cocoa/view_id_util.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
@@ -64,25 +63,15 @@ class InfoBarNotificationObserver : public NotificationObserver {
// adding together the heights of all its subviews.
- (CGFloat)desiredHeight;
-// Modifies this container to display infobars for the given
-// |contents|. Registers for INFOBAR_ADDED and INFOBAR_REMOVED
-// notifications for |contents|. If we are currently showing any
-// infobars, removes them first and deregisters for any
-// notifications. |contents| can be NULL, in which case no infobars
-// are shown and no notifications are registered for.
-- (void)changeTabContents:(TabContents*)contents;
-
@end
@implementation InfoBarContainerController
-- (id)initWithTabStripModel:(TabStripModel*)model
- resizeDelegate:(id<ViewResizer>)resizeDelegate {
+- (id)initWithResizeDelegate:(id<ViewResizer>)resizeDelegate {
DCHECK(resizeDelegate);
if ((self = [super initWithNibName:@"InfoBarContainer"
bundle:mac_util::MainAppBundle()])) {
resizeDelegate_ = resizeDelegate;
- tabObserver_.reset(new TabStripModelObserverBridge(model, self));
infoBarObserver_.reset(new InfoBarNotificationObserver(self));
// NSMutableArray needs an initial capacity, and we rarely ever see
@@ -122,16 +111,30 @@ class InfoBarNotificationObserver : public NotificationObserver {
[self positionInfoBarsAndRedraw];
}
-// TabStripModelObserverBridge notifications
-- (void)selectTabWithContents:(TabContents*)newContents
- previousContents:(TabContents*)oldContents
- atIndex:(NSInteger)index
- userGesture:(bool)wasUserGesture {
- [self changeTabContents:newContents];
+- (void)changeTabContents:(TabContents*)contents {
+ registrar_.RemoveAll();
+ [self removeAllInfoBars];
+
+ currentTabContents_ = contents;
+ if (currentTabContents_) {
+ for (int i = 0; i < currentTabContents_->infobar_delegate_count(); ++i) {
+ [self addInfoBar:currentTabContents_->GetInfoBarDelegateAt(i)
+ animate:NO];
+ }
+
+ Source<TabContents> source(currentTabContents_);
+ registrar_.Add(infoBarObserver_.get(),
+ NotificationType::TAB_CONTENTS_INFOBAR_ADDED, source);
+ registrar_.Add(infoBarObserver_.get(),
+ NotificationType::TAB_CONTENTS_INFOBAR_REMOVED, source);
+ registrar_.Add(infoBarObserver_.get(),
+ NotificationType::TAB_CONTENTS_INFOBAR_REPLACED, source);
+ }
+
+ [self positionInfoBarsAndRedraw];
}
-- (void)tabDetachedWithContents:(TabContents*)contents
- atIndex:(NSInteger)index {
+- (void)tabDetachedWithContents:(TabContents*)contents {
if (currentTabContents_ == contents)
[self changeTabContents:NULL];
}
@@ -159,29 +162,6 @@ class InfoBarNotificationObserver : public NotificationObserver {
return height;
}
-- (void)changeTabContents:(TabContents*)contents {
- registrar_.RemoveAll();
- [self removeAllInfoBars];
-
- currentTabContents_ = contents;
- if (currentTabContents_) {
- for (int i = 0; i < currentTabContents_->infobar_delegate_count(); ++i) {
- [self addInfoBar:currentTabContents_->GetInfoBarDelegateAt(i)
- animate:NO];
- }
-
- Source<TabContents> source(currentTabContents_);
- registrar_.Add(infoBarObserver_.get(),
- NotificationType::TAB_CONTENTS_INFOBAR_ADDED, source);
- registrar_.Add(infoBarObserver_.get(),
- NotificationType::TAB_CONTENTS_INFOBAR_REMOVED, source);
- registrar_.Add(infoBarObserver_.get(),
- NotificationType::TAB_CONTENTS_INFOBAR_REPLACED, source);
- }
-
- [self positionInfoBarsAndRedraw];
-}
-
- (void)addInfoBar:(InfoBarDelegate*)delegate animate:(BOOL)animate {
scoped_ptr<InfoBar> infobar(delegate->CreateInfoBar());
InfoBarController* controller = infobar->controller();
diff --git a/chrome/browser/cocoa/infobar_container_controller_unittest.mm b/chrome/browser/cocoa/infobar_container_controller_unittest.mm
index 569ed72..b9f74c7 100644
--- a/chrome/browser/cocoa/infobar_container_controller_unittest.mm
+++ b/chrome/browser/cocoa/infobar_container_controller_unittest.mm
@@ -5,7 +5,6 @@
#import <Cocoa/Cocoa.h>
#include "base/scoped_nsobject.h"
-#include "chrome/browser/cocoa/browser_test_helper.h"
#import "chrome/browser/cocoa/cocoa_test_helper.h"
#import "chrome/browser/cocoa/infobar_container_controller.h"
#include "chrome/browser/cocoa/infobar_test_helper.h"
@@ -19,11 +18,9 @@ class InfoBarContainerControllerTest : public CocoaTest {
virtual void SetUp() {
CocoaTest::SetUp();
resizeDelegate_.reset([[ViewResizerPong alloc] init]);
- TabStripModel* model = browser_helper_.browser()->tabstrip_model();
ViewResizerPong *viewResizer = resizeDelegate_.get();
controller_ =
- [[InfoBarContainerController alloc] initWithTabStripModel:model
- resizeDelegate:viewResizer];
+ [[InfoBarContainerController alloc] initWithResizeDelegate:viewResizer];
NSView* view = [controller_ view];
[[test_window() contentView] addSubview:view];
}
@@ -35,7 +32,6 @@ class InfoBarContainerControllerTest : public CocoaTest {
}
public:
- BrowserTestHelper browser_helper_;
scoped_nsobject<ViewResizerPong> resizeDelegate_;
InfoBarContainerController* controller_;
};
diff --git a/chrome/browser/cocoa/side_tab_strip_controller.mm b/chrome/browser/cocoa/side_tab_strip_controller.mm
index 0f59329..9ff73d1 100644
--- a/chrome/browser/cocoa/side_tab_strip_controller.mm
+++ b/chrome/browser/cocoa/side_tab_strip_controller.mm
@@ -14,8 +14,12 @@
- (id)initWithView:(TabStripView*)view
switchView:(NSView*)switchView
- browser:(Browser*)browser {
- self = [super initWithView:view switchView:switchView browser:browser];
+ browser:(Browser*)browser
+ delegate:(id<TabStripControllerDelegate>)delegate {
+ self = [super initWithView:view
+ switchView:switchView
+ browser:browser
+ delegate:delegate];
if (self) {
// Side tabs have no indent since they are not sharing space with the
// window controls.
diff --git a/chrome/browser/cocoa/sidebar_controller.h b/chrome/browser/cocoa/sidebar_controller.h
new file mode 100644
index 0000000..c6bdfc6
--- /dev/null
+++ b/chrome/browser/cocoa/sidebar_controller.h
@@ -0,0 +1,50 @@
+// 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.
+
+#ifndef CHROME_BROWSER_COCOA_SIDEBAR_CONTROLLER_H_
+#define CHROME_BROWSER_COCOA_SIDEBAR_CONTROLLER_H_
+#pragma once
+
+#import <Foundation/Foundation.h>
+
+#include "base/scoped_nsobject.h"
+
+@class NSSplitView;
+@class NSView;
+
+class TabContents;
+
+// Sidebar controller's delegate interface. Delegate is responsible
+// for the actual subviews resize and layout.
+@protocol SidebarControllerDelegate
+
+// Resizes the sidebar view to the new |width| and adjusts window layout
+// accordingly.
+- (void)resizeSidebarToNewWidth:(CGFloat)width;
+
+@end
+
+// A class that handles updates of the sidebar view within a browser window.
+// It swaps in the relevant sidebar contents for a given TabContents or removes
+// the vew, if there's no sidebar contents to show.
+@interface SidebarController : NSObject {
+ @private
+ // A view hosting sidebar contents.
+ scoped_nsobject<NSSplitView> sidebarView_;
+ id<SidebarControllerDelegate> delegate_; // weak
+ // Currently displayed sidebar contents.
+ TabContents* sidebarContents_; // weak.
+}
+
+- (id)initWithView:(NSSplitView*)sidebarView
+ delegate:(id<SidebarControllerDelegate>)delegate;
+
+// Depending on |contents|'s state, decides whether the sidebar
+// should be shown or hidden and adjusts its width (|delegate_| handles
+// the actual resize).
+- (void)updateSidebarForTabContents:(TabContents*)contents;
+
+@end
+
+#endif // CHROME_BROWSER_COCOA_SIDEBAR_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/sidebar_controller.mm b/chrome/browser/cocoa/sidebar_controller.mm
new file mode 100644
index 0000000..1855358
--- /dev/null
+++ b/chrome/browser/cocoa/sidebar_controller.mm
@@ -0,0 +1,124 @@
+// 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/sidebar_controller.h"
+
+#include <algorithm>
+
+#include <Cocoa/Cocoa.h>
+
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_process.h"
+#import "chrome/browser/cocoa/view_id_util.h"
+#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/sidebar/sidebar_manager.h"
+#include "chrome/browser/tab_contents/tab_contents.h"
+#include "chrome/common/pref_names.h"
+
+namespace {
+
+// By default sidebar width is 1/7th of the current page content width.
+const CGFloat kDefaultSidebarWidthRatio = 1.0 / 7;
+
+// Never make the web part of the tab contents smaller than this (needed if the
+// window is only a few pixels wide).
+const int kMinWebWidth = 50;
+
+} // end namespace
+
+
+@interface SidebarController (Private)
+- (void)showSidebarContents:(TabContents*)sidebarContents;
+@end
+
+
+@implementation SidebarController
+
+- (id)initWithView:(NSSplitView*)sidebarView
+ delegate:(id<SidebarControllerDelegate>)delegate {
+ DCHECK(delegate);
+ if ((self = [super init])) {
+ sidebarView_.reset([sidebarView retain]);
+ delegate_ = delegate;
+ sidebarContents_ = NULL;
+ }
+ return self;
+}
+
+- (void)updateSidebarForTabContents:(TabContents*)contents {
+ // Get the active sidebar content.
+ if (SidebarManager::GetInstance() == NULL) // Happens in tests.
+ return;
+
+ TabContents* sidebarContents = NULL;
+ if (contents && SidebarManager::IsSidebarAllowed()) {
+ SidebarContainer* activeSidebar =
+ SidebarManager::GetInstance()->GetActiveSidebarContainerFor(contents);
+ if (activeSidebar)
+ sidebarContents = activeSidebar->sidebar_contents();
+ }
+ if (sidebarContents_ == sidebarContents)
+ return;
+
+ TabContents* oldSidebarContents = sidebarContents_;
+ sidebarContents_ = sidebarContents;
+
+ // Adjust sidebar view.
+ [self showSidebarContents:sidebarContents];
+
+ // Notify extensions.
+ SidebarManager::GetInstance()->NotifyStateChanges(
+ oldSidebarContents, sidebarContents);
+}
+
+- (void)showSidebarContents:(TabContents*)sidebarContents {
+ NSArray* subviews = [sidebarView_ subviews];
+ if (sidebarContents) {
+ DCHECK_GE([subviews count], 1u);
+
+ // |sidebarView| is a TabContentsViewCocoa object, whose ViewID was
+ // set to VIEW_ID_TAB_CONTAINER initially, so we need to change it to
+ // VIEW_ID_SIDE_BAR_CONTAINER here.
+ NSView* sidebarView = sidebarContents->GetNativeView();
+ view_id_util::SetID(sidebarView, VIEW_ID_SIDE_BAR_CONTAINER);
+
+ CGFloat sidebarWidth = 0;
+ if ([subviews count] == 1) {
+ // Load the default split offset.
+ sidebarWidth = g_browser_process->local_state()->GetInteger(
+ prefs::kExtensionSidebarWidth);
+ if (sidebarWidth < 0) {
+ // Initial load, set to default value.
+ sidebarWidth =
+ NSWidth([sidebarView_ frame]) * kDefaultSidebarWidthRatio;
+ }
+ [sidebarView_ addSubview:sidebarView];
+ } else {
+ DCHECK_EQ([subviews count], 2u);
+ sidebarWidth = NSWidth([[subviews objectAtIndex:1] frame]);
+ [sidebarView_ replaceSubview:[subviews objectAtIndex:1]
+ with:sidebarView];
+ }
+
+ // Make sure |sidebarWidth| isn't too large or too small.
+ sidebarWidth = std::min(sidebarWidth,
+ NSWidth([sidebarView_ frame]) - kMinWebWidth);
+ DCHECK_GE(sidebarWidth, 0) << "kMinWebWidth needs to be smaller than "
+ << "smallest available tab contents space.";
+ sidebarWidth = std::max(static_cast<CGFloat>(0), sidebarWidth);
+
+ [delegate_ resizeSidebarToNewWidth:sidebarWidth];
+ } else {
+ if ([subviews count] > 1) {
+ NSView* oldSidebarContentsView = [subviews objectAtIndex:1];
+ // Store split offset when hiding sidebar window only.
+ int sidebarWidth = NSWidth([oldSidebarContentsView frame]);
+ g_browser_process->local_state()->SetInteger(
+ prefs::kExtensionSidebarWidth, sidebarWidth);
+ [oldSidebarContentsView removeFromSuperview];
+ }
+ }
+}
+
+@end
diff --git a/chrome/browser/cocoa/tab_contents_controller.h b/chrome/browser/cocoa/tab_contents_controller.h
index ce156c0..64a60cc 100644
--- a/chrome/browser/cocoa/tab_contents_controller.h
+++ b/chrome/browser/cocoa/tab_contents_controller.h
@@ -9,26 +9,19 @@
#include <Cocoa/Cocoa.h>
class TabContents;
-class TabContentsCommandObserver;
-class TabStripModel;
// A class that controls the web contents of a tab. It manages displaying the
-// native view for a given TabContents and optionally its docked devtools in
-// |contentsContainer_|.
-// Note that just creating the class does not display the view in
-// |contentsContainer_|. We defer inserting it until the box is the correct size
-// to avoid multiple resize messages to the renderer. You must call
-// |-ensureContentsVisible| to display the render widget host view.
+// native view for a given TabContents.
+// Note that just creating the class does not display the view. We defer
+// inserting it until the box is the correct size to avoid multiple resize
+// messages to the renderer. You must call |-ensureContentsVisible| to display
+// the render widget host view.
@interface TabContentsController : NSViewController {
@private
- TabContentsCommandObserver* observer_; // nil if |commands_| is nil
TabContents* contents_; // weak
- TabContents* sidebarContents_; // weak
-
- IBOutlet NSSplitView* contentsContainer_;
- IBOutlet NSSplitView* devToolsContainer_;
}
+@property(readonly, nonatomic) TabContents* tabContents;
// Create the contents of a tab represented by |contents| and loaded from the
// nib given by |name|.
@@ -44,6 +37,10 @@ class TabStripModel;
// enabled.
- (void)willBecomeSelectedTab;
+// Call when the tab contents is about to be replaced with the currently
+// selected tab contents to do not trigger unnecessary content relayout.
+- (void)ensureContentsSizeDoesNotChange;
+
// Call when the tab view is properly sized and the render widget host view
// should be put into the view hierarchy.
- (void)ensureContentsVisible;
@@ -53,26 +50,6 @@ class TabStripModel;
// an entirely new tab contents object.
- (void)tabDidChange:(TabContents*)updatedContents;
-// Shows |devToolsContents| in a split view, or removes the bottom view in the
-// split viewif |devToolsContents| is NULL.
-// TODO(thakis): Either move this to tab_window or move infobar handling to here
-// too -- http://crbug.com/31633 .
-- (void)showDevToolsContents:(TabContents*)devToolsContents;
-
-// Returns the height required by devtools and divider, or 0 if no devtools are
-// docked to the tab.
-- (CGFloat)devToolsHeight;
-
-// Shows |sidebarContents| in a split view, or removes the right view in the
-// split view if |sidebarContents| is NULL.
-// TODO(thakis): Either move this to tab_window or move infobar handling to here
-// too -- http://crbug.com/31633 .
-- (void)showSidebarContents:(TabContents*)sidebarContents;
-
-// Returns contents of the currently displayed sidebar; returns NULL if there
-// isn't any.
-- (TabContents*)sidebarContents;
-
@end
#endif // CHROME_BROWSER_COCOA_TAB_CONTENTS_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/tab_contents_controller.mm b/chrome/browser/cocoa/tab_contents_controller.mm
index 545d6f1..ac0c8c2 100644
--- a/chrome/browser/cocoa/tab_contents_controller.mm
+++ b/chrome/browser/cocoa/tab_contents_controller.mm
@@ -5,26 +5,13 @@
#import "chrome/browser/cocoa/tab_contents_controller.h"
#include "base/mac_util.h"
-#include "base/sys_string_conversions.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/bookmarks/bookmark_model.h"
-#import "chrome/browser/cocoa/view_id_util.h"
-#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/tab_contents/tab_contents.h"
-#include "chrome/common/pref_names.h"
-
-// Default offset of the contents splitter in pixels.
-static const int kDefaultContentsSplitOffset = 400;
-
-// Never make the web part of the tab contents smaller than this (needed if the
-// window is only a few pixels high/wide).
-const int kMinWebHeight = 50;
-const int kMinWebWidth = 50;
@implementation TabContentsController
+@synthesize tabContents = contents_;
- (id)initWithNibName:(NSString*)name
contents:(TabContents*)contents {
@@ -32,7 +19,6 @@ const int kMinWebWidth = 50;
bundle:mac_util::MainAppBundle()])) {
contents_ = contents;
}
- sidebarContents_ = NULL;
return self;
}
@@ -42,15 +28,28 @@ const int kMinWebWidth = 50;
[super dealloc];
}
+- (void)ensureContentsSizeDoesNotChange {
+ NSView* contentsContainer = [self view];
+ NSArray* subviews = [contentsContainer subviews];
+ if ([subviews count] > 0)
+ [contents_->GetNativeView() setAutoresizingMask:NSViewNotSizable];
+}
+
// Call when the tab view is properly sized and the render widget host view
// should be put into the view hierarchy.
- (void)ensureContentsVisible {
- NSArray* subviews = [contentsContainer_ subviews];
- if ([subviews count] == 0)
- [contentsContainer_ addSubview:contents_->GetNativeView()];
- else if ([subviews objectAtIndex:0] != contents_->GetNativeView())
- [contentsContainer_ replaceSubview:[subviews objectAtIndex:0]
- with:contents_->GetNativeView()];
+ NSView* contentsContainer = [self view];
+ NSArray* subviews = [contentsContainer subviews];
+ NSView* contentsNativeView = contents_->GetNativeView();
+ [contentsNativeView setFrame:[contentsContainer frame]];
+ if ([subviews count] == 0) {
+ [contentsContainer addSubview:contentsNativeView];
+ } else if ([subviews objectAtIndex:0] != contentsNativeView) {
+ [contentsContainer replaceSubview:[subviews objectAtIndex:0]
+ with:contentsNativeView];
+ }
+ [contentsNativeView setAutoresizingMask:NSViewWidthSizable|
+ NSViewHeightSizable];
}
// Returns YES if the tab represented by this controller is the front-most.
@@ -85,138 +84,4 @@ const int kMinWebWidth = 50;
}
}
-- (void)showDevToolsContents:(TabContents*)devToolsContents {
- NSArray* subviews = [devToolsContainer_ subviews];
- if (devToolsContents) {
- DCHECK_GE([subviews count], 1u);
-
- // Load the default split offset. If we are already showing devtools, we
- // will replace the default with the current devtools height.
- CGFloat splitOffset = g_browser_process->local_state()->GetInteger(
- prefs::kDevToolsSplitLocation);
- if (splitOffset == -1) {
- // Initial load, set to default value.
- splitOffset = kDefaultContentsSplitOffset;
- }
-
- // |devtoolsView| is a TabContentsViewCocoa object, whose ViewID was
- // set to VIEW_ID_TAB_CONTAINER initially, so we need to change it to
- // VIEW_ID_DEV_TOOLS_DOCKED here.
- NSView* devtoolsView = devToolsContents->GetNativeView();
- view_id_util::SetID(devtoolsView, VIEW_ID_DEV_TOOLS_DOCKED);
- if ([subviews count] == 1) {
- [devToolsContainer_ addSubview:devtoolsView];
- } else {
- DCHECK_EQ([subviews count], 2u);
- [devToolsContainer_ replaceSubview:[subviews objectAtIndex:1]
- with:devToolsContents->GetNativeView()];
- // If devtools are already visible, keep the current size.
- splitOffset = NSHeight([devtoolsView frame]);
- }
-
- // Make sure |splitOffset| isn't too large or too small.
- splitOffset = MIN(splitOffset,
- NSHeight([devToolsContainer_ frame]) - kMinWebHeight);
- DCHECK_GE(splitOffset, 0) << "kMinWebHeight needs to be smaller than "
- << "smallest available tab contents space.";
- splitOffset = MAX(0, splitOffset);
-
- // It seems as if |-setPosition:ofDividerAtIndex:| should do what's needed,
- // but I can't figure out how to use it. Manually resize web and devtools.
- NSRect devtoolsFrame = [devtoolsView frame];
- devtoolsFrame.size.height = splitOffset;
- [devtoolsView setFrame:devtoolsFrame];
-
- NSRect webFrame = [[subviews objectAtIndex:0] frame];
- webFrame.size.height = NSHeight([devToolsContainer_ frame]) -
- [self devToolsHeight];
- [[subviews objectAtIndex:0] setFrame:webFrame];
-
- [devToolsContainer_ adjustSubviews];
- } else {
- if ([subviews count] > 1) {
- NSView* oldDevToolsContentsView = [subviews objectAtIndex:1];
- // Store split offset when hiding devtools window only.
- int splitOffset = NSHeight([oldDevToolsContentsView frame]);
- g_browser_process->local_state()->SetInteger(
- prefs::kDevToolsSplitLocation, splitOffset);
- [oldDevToolsContentsView removeFromSuperview];
- }
- }
-}
-
-- (CGFloat)devToolsHeight {
- NSArray* subviews = [devToolsContainer_ subviews];
- if ([subviews count] < 2)
- return 0;
- return NSHeight([[subviews objectAtIndex:1] frame]) +
- [devToolsContainer_ dividerThickness];
-}
-
-// This function is very similar to showDevToolsContents.
-// TODO(alekseys): refactor and move both to browser window.
-// I (alekseys) intend to do it very soon.
-- (void)showSidebarContents:(TabContents*)sidebarContents {
- sidebarContents_ = sidebarContents;
- NSArray* subviews = [contentsContainer_ subviews];
- if (sidebarContents) {
- DCHECK_GE([subviews count], 1u);
-
- // Load the default split offset.
- CGFloat sidebarWidth = g_browser_process->local_state()->GetInteger(
- prefs::kExtensionSidebarWidth);
- if (sidebarWidth == -1) {
- // Initial load, set to default value.
- sidebarWidth = NSWidth([contentsContainer_ frame]) / 7;
- }
-
- // |sidebarView| is a TabContentsViewCocoa object, whose ViewID was
- // set to VIEW_ID_TAB_CONTAINER initially, so we need to change it to
- // VIEW_ID_SIDE_BAR_CONTAINER here.
- NSView* sidebarView = sidebarContents->GetNativeView();
- view_id_util::SetID(sidebarView, VIEW_ID_SIDE_BAR_CONTAINER);
- if ([subviews count] == 1) {
- [contentsContainer_ addSubview:sidebarView];
- } else {
- DCHECK_EQ([subviews count], 2u);
- sidebarWidth = NSWidth([[subviews objectAtIndex:1] frame]);
- [contentsContainer_ replaceSubview:[subviews objectAtIndex:1]
- with:sidebarContents->GetNativeView()];
- }
-
- // Make sure |sidebarWidth| isn't too large or too small.
- sidebarWidth = MIN(sidebarWidth,
- NSWidth([contentsContainer_ frame]) - kMinWebWidth);
- DCHECK_GE(sidebarWidth, 0) << "kMinWebWidth needs to be smaller than "
- << "smallest available tab contents space.";
- sidebarWidth = MAX(0, sidebarWidth);
-
- // It seems as if |-setPosition:ofDividerAtIndex:| should do what's needed,
- // but I can't figure out how to use it. Manually resize web and sidebar.
- NSRect sidebarFrame = [sidebarView frame];
- sidebarFrame.size.width = sidebarWidth;
- [sidebarView setFrame:sidebarFrame];
-
- NSRect webFrame = [[subviews objectAtIndex:0] frame];
- webFrame.size.width = NSWidth([contentsContainer_ frame]) -
- ([contentsContainer_ dividerThickness] + sidebarWidth);
- [[subviews objectAtIndex:0] setFrame:webFrame];
-
- [contentsContainer_ adjustSubviews];
- } else {
- if ([subviews count] > 1) {
- NSView* oldSidebarContentsView = [subviews objectAtIndex:1];
- // Store split offset when hiding sidebar window only.
- int sidebarWidth = NSWidth([oldSidebarContentsView frame]);
- g_browser_process->local_state()->SetInteger(
- prefs::kExtensionSidebarWidth, sidebarWidth);
- [oldSidebarContentsView removeFromSuperview];
- }
- }
-}
-
-- (TabContents*)sidebarContents {
- return sidebarContents_;
-}
-
@end
diff --git a/chrome/browser/cocoa/tab_strip_controller.h b/chrome/browser/cocoa/tab_strip_controller.h
index e03267b..170d3ac 100644
--- a/chrome/browser/cocoa/tab_strip_controller.h
+++ b/chrome/browser/cocoa/tab_strip_controller.h
@@ -26,6 +26,26 @@ class TabStripModel;
class TabContents;
class ToolbarModel;
+// The interface for the tab strip controller's delegate. Currently, the
+// delegate is the BWC and is responsible for subviews layout and forwarding
+// these events to InfoBarContainerController.
+// Delegating TabStripModelObserverBridge's events (in lieu of subscrining
+// BWC and InfoBarContainerController to TabStripModelObserverBridge events)
+// is necessary to guarantee a proper order of subviews layout updates,
+// otherwise it might trigger unnesessary content relayout, UI flickering etc.
+@protocol TabStripControllerDelegate
+
+// Stripped down version of TabStripModelObserverBridge:selectTabWithContents.
+- (void)onSelectTabWithContents:(TabContents*)contents;
+
+// Stripped down version of TabStripModelObserverBridge:tabChangedWithContents.
+- (void)onSelectedTabChange:(TabStripModelObserver::TabChangeType)change;
+
+// Stripped down version of TabStripModelObserverBridge:tabDetachedWithContents.
+- (void)onTabDetachedWithContents:(TabContents*)contents;
+
+@end
+
// A class that handles managing the tab strip in a browser window. It uses
// a supporting C++ bridge object to register for notifications from the
// TabStripModel. The Obj-C part of this class handles drag and drop and all
@@ -52,6 +72,8 @@ class ToolbarModel;
scoped_ptr<TabStripModelObserverBridge> bridge_;
Browser* browser_; // weak
TabStripModel* tabStripModel_; // weak
+ // Delegate that is informed about tab state changes.
+ id<TabStripControllerDelegate> delegate_; // weak
// YES if the new tab button is currently displaying the hover image (if the
// mouse is currently over the button).
@@ -126,9 +148,12 @@ class ToolbarModel;
// "switched" every time the user switches tabs. The children of this view
// will be released, so if you want them to stay around, make sure
// you have retained them.
+// |delegate| is the one listening to filtered TabStripModelObserverBridge's
+// events (see TabStripControllerDelegate for more details).
- (id)initWithView:(TabStripView*)view
switchView:(NSView*)switchView
- browser:(Browser*)browser;
+ browser:(Browser*)browser
+ delegate:(id<TabStripControllerDelegate>)delegate;
// Return the view for the currently selected tab.
- (NSView*)selectedTabView;
@@ -221,8 +246,6 @@ class ToolbarModel;
// functions.
- (void)attachConstrainedWindow:(ConstrainedWindowMac*)window;
- (void)removeConstrainedWindow:(ConstrainedWindowMac*)window;
-- (void)updateDevToolsForContents:(TabContents*)contents;
-- (void)updateSidebarForContents:(TabContents*)contents;
@end
diff --git a/chrome/browser/cocoa/tab_strip_controller.mm b/chrome/browser/cocoa/tab_strip_controller.mm
index 225b6d5..b3b19c0 100644
--- a/chrome/browser/cocoa/tab_strip_controller.mm
+++ b/chrome/browser/cocoa/tab_strip_controller.mm
@@ -279,13 +279,15 @@ private:
- (id)initWithView:(TabStripView*)view
switchView:(NSView*)switchView
- browser:(Browser*)browser {
- DCHECK(view && switchView && browser);
+ browser:(Browser*)browser
+ delegate:(id<TabStripControllerDelegate>)delegate {
+ DCHECK(view && switchView && browser && delegate);
if ((self = [super init])) {
tabStripView_.reset([view retain]);
switchView_ = switchView;
browser_ = browser;
tabStripModel_ = browser_->tabstrip_model();
+ delegate_ = delegate;
bridge_.reset(new TabStripModelObserverBridge(tabStripModel_, self));
tabContentsArray_.reset([[NSMutableArray alloc] init]);
tabArray_.reset([[NSMutableArray alloc] init]);
@@ -440,9 +442,10 @@ private:
// the view hierarchy. This is in order to avoid sending the renderer a
// spurious default size loaded from the nib during the call to |-view|.
NSView* newView = [controller view];
- NSRect frame = [switchView_ bounds];
- [newView setFrame:frame];
- [controller ensureContentsVisible];
+
+ // Turns content autoresizing off, so removing and inserting views won't
+ // trigger unnecessary content relayout.
+ [controller ensureContentsSizeDoesNotChange];
// Remove the old view from the view hierarchy. We know there's only one
// child of |switchView_| because we're the one who put it there. There
@@ -451,11 +454,22 @@ private:
NSArray* subviews = [switchView_ subviews];
if ([subviews count]) {
NSView* oldView = [subviews objectAtIndex:0];
+ // Set newView frame to the oldVew frame to prevent NSSplitView hosting
+ // sidebar and tab content from resizing sidebar's content view.
+ // ensureContentsVisible (see below) sets content size and autoresizing
+ // properties.
+ [newView setFrame:[oldView frame]];
[switchView_ replaceSubview:oldView with:newView];
} else {
[switchView_ addSubview:newView];
}
+ // New content is in place, delegate should adjust itself accordingly.
+ [delegate_ onSelectTabWithContents:[controller tabContents]];
+
+ // It also resores content autoresizing properties.
+ [controller ensureContentsVisible];
+
// Make sure the new tabs's sheets are visible (necessary when a background
// tab opened a sheet while it was in the background and now becomes active).
TabContents* newTab = tabStripModel_->GetTabContentsAt(modelIndex);
@@ -1048,8 +1062,6 @@ private:
// Swap in the contents for the new tab.
[self swapInTabAtIndex:modelIndex];
- [self updateSidebarForContents:newContents];
- [self updateDevToolsForContents:newContents];
if (newContents) {
newContents->DidBecomeSelected();
@@ -1155,14 +1167,12 @@ private:
[self removeTab:tab];
}
- // Does nothing, purely for consistency with the windows/linux code.
- [self updateSidebarForContents:NULL];
- [self updateDevToolsForContents:NULL];
-
// Send a broadcast that the number of tabs have changed.
[[NSNotificationCenter defaultCenter]
postNotificationName:kTabStripNumberOfTabsChanged
object:self];
+
+ [delegate_ onTabDetachedWithContents:contents];
}
// A helper routine for creating an NSImageView to hold the fav icon or app icon
@@ -1275,6 +1285,9 @@ private:
// Take closing tabs into account.
NSInteger index = [self indexFromModelIndex:modelIndex];
+ if (modelIndex == tabStripModel_->selected_index())
+ [delegate_ onSelectedTabChange:change];
+
if (change == TabStripModelObserver::TITLE_NOT_LOADING) {
// TODO(sky): make this work.
// We'll receive another notification of the change asynchronously.
@@ -1792,14 +1805,12 @@ private:
// View hierarchy of the contents view:
// NSView -- switchView, same for all tabs
- // +- NSView -- TabContentsController's view
- // +- NSSplitView
- // +- NSSplitView
- // +- TabContentsViewCocoa
+ // +- NSView -- TabContentsController's view
+ // +- TabContentsViewCocoa
+ // Changing it? Do not forget to modify removeConstrainedWindow too.
// We use the TabContentsController's view in |swapInTabAtIndex|, so we have
// to pass it to the sheet controller here.
- NSView* tabContentsView =
- [[[window->owner()->GetNativeView() superview] superview] superview];
+ NSView* tabContentsView = [window->owner()->GetNativeView() superview];
window->delegate()->RunSheet([self sheetController], tabContentsView);
// TODO(avi, thakis): GTMWindowSheetController has no api to move tabsheets
@@ -1817,8 +1828,7 @@ private:
}
- (void)removeConstrainedWindow:(ConstrainedWindowMac*)window {
- NSView* tabContentsView =
- [[[window->owner()->GetNativeView() superview] superview] superview];
+ NSView* tabContentsView = [window->owner()->GetNativeView() superview];
// TODO(avi, thakis): GTMWindowSheetController has no api to move tabsheets
// between windows. Until then, we have to prevent having to move a tabsheet
@@ -1833,58 +1843,4 @@ private:
}
}
-- (void)updateDevToolsForContents:(TabContents*)contents {
- int modelIndex = tabStripModel_->GetIndexOfTabContents(contents);
-
- // This happens e.g. if one hits cmd-q with a docked devtools window open.
- if (modelIndex == TabStripModel::kNoTab)
- return;
-
- NSInteger index = [self indexFromModelIndex:modelIndex];
- DCHECK_GE(index, 0);
- DCHECK_LT(index, (NSInteger)[tabContentsArray_ count]);
- if (index < 0 || index >= (NSInteger)[tabContentsArray_ count])
- return;
-
- TabContentsController* tabController =
- [tabContentsArray_ objectAtIndex:index];
- TabContents* devtoolsContents = contents ?
- DevToolsWindow::GetDevToolsContents(contents) : NULL;
- [tabController showDevToolsContents:devtoolsContents];
-}
-
-// This function is very similar to updateDevToolsContents.
-// TODO(alekseys): refactor and move both to browser window.
-// I (alekseys) intend to do it very soon.
-- (void)updateSidebarForContents:(TabContents*)contents {
- if (SidebarManager::GetInstance() == NULL) // Happens in tests.
- return;
-
- int modelIndex = tabStripModel_->GetIndexOfTabContents(contents);
-
- // This happens e.g. if one hits cmd-q with sidebar expanded.
- if (modelIndex == TabStripModel::kNoTab)
- return;
-
- NSInteger index = [self indexFromModelIndex:modelIndex];
- DCHECK_GE(index, 0);
- DCHECK_LT(index, (NSInteger)[tabContentsArray_ count]);
- if (index < 0 || index >= (NSInteger)[tabContentsArray_ count])
- return;
-
- TabContentsController* tabController =
- [tabContentsArray_ objectAtIndex:index];
- TabContents* sidebar_contents = NULL;
- if (contents && SidebarManager::IsSidebarAllowed()) {
- SidebarContainer* active_sidebar =
- SidebarManager::GetInstance()->GetActiveSidebarContainerFor(contents);
- if (active_sidebar)
- sidebar_contents = active_sidebar->sidebar_contents();
- }
- TabContents* old_sidebar_contents = [tabController sidebarContents];
- [tabController showSidebarContents:sidebar_contents];
- SidebarManager::GetInstance()->NotifyStateChanges(
- old_sidebar_contents, sidebar_contents);
-}
-
@end
diff --git a/chrome/browser/cocoa/tab_strip_controller_unittest.mm b/chrome/browser/cocoa/tab_strip_controller_unittest.mm
index eee7580..e879b3c 100644
--- a/chrome/browser/cocoa/tab_strip_controller_unittest.mm
+++ b/chrome/browser/cocoa/tab_strip_controller_unittest.mm
@@ -15,6 +15,20 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
+@interface TestTabStripControllerDelegate :
+ NSObject<TabStripControllerDelegate> {
+}
+@end
+
+@implementation TestTabStripControllerDelegate
+- (void)onSelectTabWithContents:(TabContents*)contents {
+}
+- (void)onSelectedTabChange:(TabStripModelObserver::TabChangeType)change {
+}
+- (void)onTabDetachedWithContents:(TabContents*)contents {
+}
+@end
+
namespace {
// Stub model delegate
@@ -104,10 +118,12 @@ class TabStripControllerTest : public CocoaTest {
delegate_.reset(new TestTabStripDelegate());
model_ = browser->tabstrip_model();
+ controller_delegate_.reset([TestTabStripControllerDelegate alloc]);
controller_.reset([[TabStripController alloc]
initWithView:static_cast<TabStripView*>(tab_strip.get())
switchView:switch_view.get()
- browser:browser]);
+ browser:browser
+ delegate:controller_delegate_.get()]);
}
virtual void TearDown() {
@@ -122,6 +138,7 @@ class TabStripControllerTest : public CocoaTest {
BrowserTestHelper browser_helper_;
scoped_ptr<TestTabStripDelegate> delegate_;
TabStripModel* model_;
+ scoped_nsobject<TestTabStripControllerDelegate> controller_delegate_;
scoped_nsobject<TabStripController> controller_;
};
diff --git a/chrome/browser/cocoa/tab_window_controller.h b/chrome/browser/cocoa/tab_window_controller.h
index c4bdf79..9d97fe1 100644
--- a/chrome/browser/cocoa/tab_window_controller.h
+++ b/chrome/browser/cocoa/tab_window_controller.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CHROME_BROWSER_TAB_WINDOW_CONTROLLER_H_
-#define CHROME_BROWSER_TAB_WINDOW_CONTROLLER_H_
+#ifndef CHROME_BROWSER_COCOA_TAB_WINDOW_CONTROLLER_H_
+#define CHROME_BROWSER_COCOA_TAB_WINDOW_CONTROLLER_H_
#pragma once
// A class acting as the Objective-C window controller for a window that has
@@ -39,6 +39,8 @@
@interface TabWindowController : NSWindowController<NSWindowDelegate> {
@private
IBOutlet FastResizeView* tabContentArea_;
+ IBOutlet NSSplitView* contentsContainer_;
+ IBOutlet NSSplitView* devToolsContainer_;
// 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_;
@@ -57,6 +59,8 @@
}
@property(readonly, nonatomic) TabStripView* tabStripView;
@property(readonly, nonatomic) FastResizeView* tabContentArea;
+@property(readonly, nonatomic) NSSplitView* contentsContainer;
+@property(readonly, nonatomic) NSSplitView* devToolsContainer;
// Used during tab dragging to turn on/off the overlay window when a tab
// is torn off. If -deferPerformClose (below) is used, -removeOverlay will
@@ -174,4 +178,4 @@
- (void)layoutSubviews;
@end
-#endif // CHROME_BROWSER_TAB_WINDOW_CONTROLLER_H_
+#endif // CHROME_BROWSER_COCOA_TAB_WINDOW_CONTROLLER_H_
diff --git a/chrome/browser/cocoa/tab_window_controller.mm b/chrome/browser/cocoa/tab_window_controller.mm
index 4e886eb..f9e390b 100644
--- a/chrome/browser/cocoa/tab_window_controller.mm
+++ b/chrome/browser/cocoa/tab_window_controller.mm
@@ -41,6 +41,8 @@
@implementation TabWindowController
@synthesize tabContentArea = tabContentArea_;
+@synthesize contentsContainer = contentsContainer_;
+@synthesize devToolsContainer = devToolsContainer_;
- (id)initWithWindow:(NSWindow*)window {
if ((self = [super initWithWindow:window]) != nil) {