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/fast_resize_view.h"
9 #import "chrome/browser/ui/cocoa/framed_browser_window.h"
10 #import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h"
11 #import "chrome/browser/ui/cocoa/themed_window.h"
12 #import "ui/base/cocoa/focus_tracker.h"
13 #include "ui/base/theme_provider.h"
15 @interface TabWindowController(PRIVATE)
16 - (void)setUseOverlay:(BOOL)useOverlay;
19 @interface TabWindowOverlayWindow : NSWindow
22 @implementation TabWindowOverlayWindow
24 - (ui::ThemeProvider*)themeProvider {
25 if ([self parentWindow])
26 return [[[self parentWindow] windowController] themeProvider];
30 - (ThemedWindowStyle)themedWindowStyle {
31 if ([self parentWindow])
32 return [[[self parentWindow] windowController] themedWindowStyle];
36 - (NSPoint)themeImagePositionForAlignment:(ThemeImageAlignment)alignment {
37 if ([self parentWindow]) {
38 return [[[self parentWindow] windowController]
39 themeImagePositionForAlignment:alignment];
46 @implementation TabWindowController
48 - (id)initTabWindowControllerWithTabStrip:(BOOL)hasTabStrip {
49 NSRect contentRect = NSMakeRect(60, 229, 750, 600);
50 base::scoped_nsobject<FramedBrowserWindow> window(
51 [[FramedBrowserWindow alloc] initWithContentRect:contentRect
52 hasTabStrip:hasTabStrip]);
53 [window setReleasedWhenClosed:YES];
54 [window setAutorecalculatesKeyViewLoop:YES];
56 if ((self = [super initWithWindow:window])) {
57 [[self window] setDelegate:self];
59 tabContentArea_.reset([[FastResizeView alloc] initWithFrame:
60 NSMakeRect(0, 0, 750, 600)]);
61 [tabContentArea_ setAutoresizingMask:NSViewWidthSizable |
63 [[[self window] contentView] addSubview:tabContentArea_];
65 tabStripView_.reset([[TabStripView alloc] initWithFrame:
66 NSMakeRect(0, 0, 750, 37)]);
67 [tabStripView_ setAutoresizingMask:NSViewWidthSizable |
70 [self addTabStripToWindow];
75 - (TabStripView*)tabStripView {
79 - (FastResizeView*)tabContentArea {
80 return tabContentArea_;
83 // Add the top tab strop to the window, above the content box and add it to the
84 // view hierarchy as a sibling of the content view so it can overlap with the
86 - (void)addTabStripToWindow {
87 // The frame doesn't matter. This class relies on subclasses to do tab strip
89 NSView* contentParent = [[[self window] contentView] superview];
90 [contentParent addSubview:tabStripView_];
93 - (void)removeOverlay {
94 [self setUseOverlay:NO];
96 // See comment in BrowserWindowCocoa::Close() about orderOut:.
97 [[self window] orderOut:self];
98 [[self window] performClose:self]; // Autoreleases the controller.
102 - (void)showOverlay {
103 [self setUseOverlay:YES];
106 // If |useOverlay| is YES, creates a new overlay window and puts the tab strip
107 // and the content area inside of it. This allows it to have a different opacity
108 // from the title bar. If NO, returns everything to the previous state and
109 // destroys the overlay window until it's needed again. The tab strip and window
110 // contents are returned to the original window.
111 - (void)setUseOverlay:(BOOL)useOverlay {
112 [NSObject cancelPreviousPerformRequestsWithTarget:self
113 selector:@selector(removeOverlay)
115 NSWindow* window = [self window];
116 if (useOverlay && !overlayWindow_) {
117 DCHECK(!originalContentView_);
119 overlayWindow_ = [[TabWindowOverlayWindow alloc]
120 initWithContentRect:[window frame]
121 styleMask:NSBorderlessWindowMask
122 backing:NSBackingStoreBuffered
124 [overlayWindow_ setTitle:@"overlay"];
125 [overlayWindow_ setBackgroundColor:[NSColor clearColor]];
126 [overlayWindow_ setOpaque:NO];
127 [overlayWindow_ setDelegate:self];
129 originalContentView_ = [window contentView];
130 [window addChildWindow:overlayWindow_ ordered:NSWindowAbove];
132 // Explicitly set the responder to be nil here (for restoring later).
133 // If the first responder were to be left non-nil here then
134 // [RenderWidgethostViewCocoa resignFirstResponder] would be called,
135 // followed by RenderWidgetHost::Blur(), which would result in an unexpected
137 focusBeforeOverlay_.reset([[FocusTracker alloc] initWithWindow:window]);
138 [window makeFirstResponder:nil];
140 // Move the original window's tab strip view and content view to the overlay
141 // window. The content view is added as a subview of the overlay window's
142 // content view (rather than using setContentView:) because the overlay
143 // window has a different content size (due to it being borderless).
144 [[[overlayWindow_ contentView] superview] addSubview:[self tabStripView]];
145 [[overlayWindow_ contentView] addSubview:originalContentView_];
147 [overlayWindow_ orderFront:nil];
148 } else if (!useOverlay && overlayWindow_) {
149 DCHECK(originalContentView_);
151 // Return the original window's tab strip view and content view to their
152 // places. The TabStripView always needs to be in front of the window's
153 // content view and therefore it should always be added after the content
155 [window setContentView:originalContentView_];
156 [[[window contentView] superview] addSubview:[self tabStripView]];
157 [[[window contentView] superview] updateTrackingAreas];
159 [focusBeforeOverlay_ restoreFocusInWindow:window];
160 focusBeforeOverlay_.reset();
163 [window removeChildWindow:overlayWindow_];
165 [overlayWindow_ orderOut:nil];
166 [overlayWindow_ release];
167 overlayWindow_ = nil;
168 originalContentView_ = nil;
174 - (NSWindow*)overlayWindow {
175 return overlayWindow_;
178 - (BOOL)shouldConstrainFrameRect {
179 // If we currently have an overlay window, do not attempt to change the
180 // window's size, as our overlay window doesn't know how to resize properly.
181 return overlayWindow_ == nil;
184 - (BOOL)canReceiveFrom:(TabWindowController*)source {
185 // subclass must implement
190 - (void)moveTabView:(NSView*)view
191 fromController:(TabWindowController*)dragController {
195 - (NSView*)activeTabView {
201 // subclass must implement
205 - (TabWindowController*)detachTabToNewWindow:(TabView*)tabView {
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 // Called when the size of the window content area has changed. Override to
289 // position specific views. Base class implementation does nothing.
290 - (void)layoutSubviews {