1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import "chrome/browser/ui/cocoa/dev_tools_controller.h"
9 #include <Cocoa/Cocoa.h>
11 #include "base/prefs/pref_service.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/profiles/profile.h"
14 #import "chrome/browser/ui/cocoa/view_id_util.h"
15 #include "chrome/common/pref_names.h"
16 #include "content/public/browser/web_contents.h"
17 #include "content/public/browser/web_contents_view.h"
18 #include "ui/base/cocoa/focus_tracker.h"
20 using content::WebContents;
22 @interface GraySplitView : NSSplitView {
26 @property(assign, nonatomic) BOOL dividerHidden;
28 - (NSColor*)dividerColor;
29 - (CGFloat)dividerThickness;
34 @implementation GraySplitView
36 @synthesize dividerHidden = dividerHidden_;
38 - (NSColor*)dividerColor {
39 return [NSColor darkGrayColor];
42 - (CGFloat)dividerThickness {
43 return dividerHidden_ ? 0 : [super dividerThickness];
48 @interface DevToolsController (Private)
49 - (void)showDevToolsContainer;
50 - (void)hideDevToolsContainer;
51 - (void)updateDevToolsSplitPosition;
55 @implementation DevToolsController
58 if ((self = [super init])) {
59 splitView_.reset([[GraySplitView alloc] initWithFrame:NSZeroRect]);
60 [splitView_ setDividerStyle:NSSplitViewDividerStyleThin];
61 [splitView_ setVertical:NO];
62 [splitView_ setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
63 [splitView_ setDelegate:self];
64 [splitView_ setDividerHidden:NO];
66 dockSide_ = DEVTOOLS_DOCK_SIDE_BOTTOM;
72 [splitView_ setDelegate:nil];
77 return splitView_.get();
80 - (NSSplitView*)splitView {
81 return splitView_.get();
84 - (void)updateDevToolsForWebContents:(WebContents*)contents
85 withProfile:(Profile*)profile {
86 DevToolsWindow* newDevToolsWindow = contents ?
87 DevToolsWindow::GetDockedInstanceForInspectedTab(contents) : NULL;
89 // Fast return in case of the same window having same orientation.
90 if (devToolsWindow_ == newDevToolsWindow) {
91 if (!newDevToolsWindow ||
92 (newDevToolsWindow->dock_side() == dockSide_)) {
97 // Store last used position.
98 if (devToolsWindow_) {
99 NSArray* subviews = [splitView_ subviews];
100 DCHECK_EQ([subviews count], 2u);
101 NSView* devToolsView = [subviews objectAtIndex:1];
102 if (dockSide_ == DEVTOOLS_DOCK_SIDE_RIGHT)
103 devToolsWindow_->SetWidth(NSWidth([devToolsView frame]));
104 else if (dockSide_ == DEVTOOLS_DOCK_SIDE_BOTTOM)
105 devToolsWindow_->SetHeight(NSHeight([devToolsView frame]));
109 [self hideDevToolsContainer];
111 devToolsWindow_ = newDevToolsWindow;
113 if (devToolsWindow_) {
114 dockSide_ = devToolsWindow_->dock_side();
115 [self showDevToolsContainer];
119 - (void)showDevToolsContainer {
120 NSArray* subviews = [splitView_ subviews];
121 DCHECK_EQ([subviews count], 1u);
122 WebContents* devToolsContents = devToolsWindow_->web_contents();
124 [[FocusTracker alloc] initWithWindow:[splitView_ window]]);
126 // |devToolsView| is a TabContentsViewCocoa object, whose ViewID was
127 // set to VIEW_ID_TAB_CONTAINER initially, so we need to change it to
128 // VIEW_ID_DEV_TOOLS_DOCKED here.
129 NSView* devToolsView = devToolsContents->GetView()->GetNativeView();
130 view_id_util::SetID(devToolsView, VIEW_ID_DEV_TOOLS_DOCKED);
131 [splitView_ addSubview:devToolsView];
133 BOOL isVertical = devToolsWindow_->dock_side() == DEVTOOLS_DOCK_SIDE_RIGHT;
134 [splitView_ setVertical:isVertical];
135 [self updateDevToolsSplitPosition];
138 - (void)hideDevToolsContainer {
139 NSArray* subviews = [splitView_ subviews];
140 DCHECK_EQ([subviews count], 2u);
141 NSView* oldDevToolsContentsView = [subviews objectAtIndex:1];
142 [oldDevToolsContentsView removeFromSuperview];
143 [splitView_ adjustSubviews];
144 [focusTracker_ restoreFocusInWindow:[splitView_ window]];
145 focusTracker_.reset();
148 - (void)updateDevToolsSplitPosition {
149 NSArray* subviews = [splitView_ subviews];
151 // It seems as if |-setPosition:ofDividerAtIndex:| should do what's needed,
152 // but I can't figure out how to use it. Manually resize web and devtools.
153 // TODO(alekseys): either make setPosition:ofDividerAtIndex: work or to add a
154 // category on NSSplitView to handle manual resizing.
155 NSView* webView = [subviews objectAtIndex:0];
156 NSRect webFrame = [webView frame];
157 NSView* devToolsView = [subviews objectAtIndex:1];
158 NSRect devToolsFrame = [devToolsView frame];
160 BOOL noDivider = devToolsWindow_->dock_side() == DEVTOOLS_DOCK_SIDE_MINIMIZED;
161 [splitView_ setDividerHidden:noDivider];
163 if (devToolsWindow_->dock_side() == DEVTOOLS_DOCK_SIDE_RIGHT) {
164 CGFloat size = devToolsWindow_->GetWidth(NSWidth([splitView_ frame]));
165 devToolsFrame.size.width = size;
166 webFrame.size.width =
167 NSWidth([splitView_ frame]) - ([splitView_ dividerThickness] + size);
170 devToolsWindow_->dock_side() == DEVTOOLS_DOCK_SIDE_MINIMIZED ?
171 devToolsWindow_->GetMinimizedHeight() :
172 devToolsWindow_->GetHeight(NSHeight([splitView_ frame]));
173 devToolsFrame.size.height = size;
174 webFrame.size.height =
175 NSHeight([splitView_ frame]) - ([splitView_ dividerThickness] + size);
178 [[splitView_ window] disableScreenUpdatesUntilFlush];
179 [webView setFrame:webFrame];
180 [devToolsView setFrame:devToolsFrame];
182 [splitView_ adjustSubviews];
185 // NSSplitViewDelegate protocol.
186 - (BOOL)splitView:(NSSplitView *)splitView
187 shouldAdjustSizeOfSubview:(NSView *)subview {
188 // Return NO for the devTools view to indicate that it should not be resized
189 // automatically. It preserves the height set by the user and also keeps
190 // view height the same while changing tabs when one of the tabs shows infobar
191 // and others are not.
192 if ([[splitView_ subviews] indexOfObject:subview] == 1)
197 - (NSRect)splitView:(NSSplitView*)splitView
198 effectiveRect:(NSRect)proposedEffectiveRect
199 forDrawnRect:(NSRect)drawnRect
200 ofDividerAtIndex:(NSInteger)dividerIndex {
201 if (devToolsWindow_->dock_side() == DEVTOOLS_DOCK_SIDE_MINIMIZED) {
204 return proposedEffectiveRect;
208 - (CGFloat)splitView:(NSSplitView*)splitView
209 constrainMaxCoordinate:(CGFloat)proposedMax
210 ofSubviewAt:(NSInteger)dividerIndex {
211 if ([splitView_ isVertical]) {
212 return NSWidth([splitView_ frame]) - [splitView_ dividerThickness] -
213 devToolsWindow_->GetMinimumWidth();
215 return NSHeight([splitView_ frame]) - [splitView_ dividerThickness] -
216 devToolsWindow_->GetMinimumHeight();
220 - (CGFloat)splitView:(NSSplitView *)splitView
221 constrainSplitPosition:(CGFloat)proposedPosition
222 ofSubviewAt:(NSInteger)dividerIndex {
223 return round(proposedPosition);
226 -(void)splitViewWillResizeSubviews:(NSNotification *)notification {
227 [[splitView_ window] disableScreenUpdatesUntilFlush];