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/tabs/tab_window_controller.h"
7 #include "base/logging.h"
8 #import "chrome/browser/ui/cocoa/browser_window_layout.h"
9 #import "chrome/browser/ui/cocoa/fast_resize_view.h"
10 #import "chrome/browser/ui/cocoa/framed_browser_window.h"
11 #import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h"
12 #import "chrome/browser/ui/cocoa/themed_window.h"
13 #import "chrome/browser/ui/cocoa/version_independent_window.h"
14 #import "ui/base/cocoa/focus_tracker.h"
15 #include "ui/base/theme_provider.h"
17 @interface TabWindowController(PRIVATE)
18 - (void)setUseOverlay:(BOOL)useOverlay;
21 @interface TabWindowOverlayWindow : NSWindow
24 @implementation TabWindowOverlayWindow
26 - (ui::ThemeProvider*)themeProvider {
27 if ([self parentWindow])
28 return [[[self parentWindow] windowController] themeProvider];
32 - (ThemedWindowStyle)themedWindowStyle {
33 if ([self parentWindow])
34 return [[[self parentWindow] windowController] themedWindowStyle];
38 - (NSPoint)themeImagePositionForAlignment:(ThemeImageAlignment)alignment {
39 if ([self parentWindow]) {
40 return [[[self parentWindow] windowController]
41 themeImagePositionForAlignment:alignment];
48 @implementation TabWindowController
50 - (id)initTabWindowControllerWithTabStrip:(BOOL)hasTabStrip {
51 NSRect contentRect = NSMakeRect(60, 229, 750, 600);
52 base::scoped_nsobject<FramedBrowserWindow> window(
53 [[FramedBrowserWindow alloc] initWithContentRect:contentRect
54 hasTabStrip:hasTabStrip]);
55 [self moveContentViewToBack:[window contentView]];
56 [window setReleasedWhenClosed:YES];
57 [window setAutorecalculatesKeyViewLoop:YES];
59 if ((self = [super initWithWindow:window])) {
60 [[self window] setDelegate:self];
62 tabContentArea_.reset([[FastResizeView alloc] initWithFrame:
63 NSMakeRect(0, 0, 750, 600)]);
64 [tabContentArea_ setAutoresizingMask:NSViewWidthSizable |
66 [[[self window] contentView] addSubview:tabContentArea_];
68 tabStripView_.reset([[TabStripView alloc]
69 initWithFrame:NSMakeRect(0, 0, 750, chrome::kTabStripHeight)]);
70 [tabStripView_ setAutoresizingMask:NSViewWidthSizable |
73 [self insertTabStripView:tabStripView_ intoWindow:[self window]];
78 - (TabStripView*)tabStripView {
82 - (FastResizeView*)tabContentArea {
83 return tabContentArea_;
86 - (void)removeOverlay {
87 [self setUseOverlay:NO];
89 // See comment in BrowserWindowCocoa::Close() about orderOut:.
90 [[self window] orderOut:self];
91 [[self window] performClose:self]; // Autoreleases the controller.
96 [self setUseOverlay:YES];
99 // If |useOverlay| is YES, creates a new overlay window and puts the tab strip
100 // and the content area inside of it. This allows it to have a different opacity
101 // from the title bar. If NO, returns everything to the previous state and
102 // destroys the overlay window until it's needed again. The tab strip and window
103 // contents are returned to the original window.
104 - (void)setUseOverlay:(BOOL)useOverlay {
105 [NSObject cancelPreviousPerformRequestsWithTarget:self
106 selector:@selector(removeOverlay)
108 NSWindow* window = [self window];
109 if (useOverlay && !overlayWindow_) {
110 DCHECK(!originalContentView_);
112 overlayWindow_ = [[TabWindowOverlayWindow alloc]
113 initWithContentRect:[window frame]
114 styleMask:NSBorderlessWindowMask
115 backing:NSBackingStoreBuffered
117 [overlayWindow_ setTitle:@"overlay"];
118 [overlayWindow_ setBackgroundColor:[NSColor clearColor]];
119 [overlayWindow_ setOpaque:NO];
120 [overlayWindow_ setDelegate:self];
122 originalContentView_ = [window contentView];
123 [window addChildWindow:overlayWindow_ ordered:NSWindowAbove];
125 // Explicitly set the responder to be nil here (for restoring later).
126 // If the first responder were to be left non-nil here then
127 // [RenderWidgethostViewCocoa resignFirstResponder] would be called,
128 // followed by RenderWidgetHost::Blur(), which would result in an unexpected
130 focusBeforeOverlay_.reset([[FocusTracker alloc] initWithWindow:window]);
131 [window makeFirstResponder:nil];
133 // Move the original window's tab strip view and content view to the overlay
134 // window. The content view is added as a subview of the overlay window's
135 // content view (rather than using setContentView:) because the overlay
136 // window has a different content size (due to it being borderless).
137 [[overlayWindow_ cr_windowView] addSubview:[self tabStripView]];
138 [[overlayWindow_ contentView] addSubview:originalContentView_];
140 [overlayWindow_ orderFront:nil];
141 } else if (!useOverlay && overlayWindow_) {
142 DCHECK(originalContentView_);
144 // Return the original window's tab strip view and content view to their
145 // places. The TabStripView always needs to be in front of the window's
146 // content view and therefore it should always be added after the content
148 [window setContentView:originalContentView_];
149 [self moveContentViewToBack:originalContentView_];
150 [self insertTabStripView:[self tabStripView] intoWindow:window];
151 [[window cr_windowView] updateTrackingAreas];
153 [focusBeforeOverlay_ restoreFocusInWindow:window];
154 focusBeforeOverlay_.reset();
157 [window removeChildWindow:overlayWindow_];
159 [overlayWindow_ orderOut:nil];
160 [overlayWindow_ release];
161 overlayWindow_ = nil;
162 originalContentView_ = nil;
168 - (NSWindow*)overlayWindow {
169 return overlayWindow_;
172 - (BOOL)shouldConstrainFrameRect {
173 // If we currently have an overlay window, do not attempt to change the
174 // window's size, as our overlay window doesn't know how to resize properly.
175 return overlayWindow_ == nil;
178 - (BOOL)canReceiveFrom:(TabWindowController*)source {
179 // subclass must implement
184 - (void)moveTabViews:(NSArray*)views
185 fromController:(TabWindowController*)dragController {
189 - (NSArray*)tabViews {
194 - (NSView*)activeTabView {
200 // subclass must implement
204 - (TabWindowController*)detachTabsToNewWindow:(NSArray*)tabViews
205 draggedTab:(NSView*)draggedTab {
206 // subclass must implement
211 - (void)insertPlaceholderForTab:(TabView*)tab frame:(NSRect)frame {
212 [self showNewTabButton:NO];
215 - (void)removePlaceholder {
216 [self showNewTabButton:YES];
219 - (BOOL)isDragSessionActive {
224 - (BOOL)tabDraggingAllowed {
228 - (BOOL)tabTearingAllowed {
232 - (BOOL)windowMovementAllowed {
236 - (BOOL)isTabFullyVisible:(TabView*)tab {
237 // Subclasses should implement this, but it's not necessary.
241 - (void)showNewTabButton:(BOOL)show {
242 // subclass must implement
246 - (void)detachTabView:(NSView*)view {
247 // subclass must implement
251 - (NSInteger)numberOfTabs {
252 // subclass must implement
257 - (BOOL)hasLiveTabs {
258 // subclass must implement
263 - (NSString*)activeTabTitle {
264 // subclass must implement
269 - (BOOL)hasTabStrip {
270 // Subclasses should implement this.
275 - (BOOL)isTabDraggable:(NSView*)tabView {
276 // Subclasses should implement this.
281 // Tell the window that it needs to call performClose: as soon as the current
282 // drag is complete. This prevents a window (and its overlay) from going away
284 - (void)deferPerformClose {
285 closeDeferred_ = YES;
288 - (void)moveContentViewToBack:(NSView*)cv {
289 base::scoped_nsobject<NSView> contentView([cv retain]);
290 NSView* superview = [contentView superview];
291 [contentView removeFromSuperview];
292 [superview addSubview:contentView positioned:NSWindowBelow relativeTo:nil];
295 - (void)insertTabStripView:(NSView*)tabStripView intoWindow:(NSWindow*)window {
296 NSView* contentParent = [window cr_windowView];
297 if (contentParent == [[window contentView] superview]) {
298 // Add the tab strip directly above the content view, if they are siblings.
299 [contentParent addSubview:tabStripView
300 positioned:NSWindowAbove
301 relativeTo:[window contentView]];
303 [contentParent addSubview:tabStripView];
307 // Called when the size of the window content area has changed. Override to
308 // position specific views. Base class implementation does nothing.
309 - (void)layoutSubviews {