• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4
5#import "chrome/browser/ui/cocoa/tabs/tab_window_controller.h"
6
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"
14
15@interface TabWindowController(PRIVATE)
16- (void)setUseOverlay:(BOOL)useOverlay;
17@end
18
19@interface TabWindowOverlayWindow : NSWindow
20@end
21
22@implementation TabWindowOverlayWindow
23
24- (ui::ThemeProvider*)themeProvider {
25  if ([self parentWindow])
26    return [[[self parentWindow] windowController] themeProvider];
27  return NULL;
28}
29
30- (ThemedWindowStyle)themedWindowStyle {
31  if ([self parentWindow])
32    return [[[self parentWindow] windowController] themedWindowStyle];
33  return NO;
34}
35
36- (NSPoint)themeImagePositionForAlignment:(ThemeImageAlignment)alignment {
37  if ([self parentWindow]) {
38    return [[[self parentWindow] windowController]
39        themeImagePositionForAlignment:alignment];
40  }
41  return NSZeroPoint;
42}
43
44@end
45
46@implementation TabWindowController
47
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];
55
56  if ((self = [super initWithWindow:window])) {
57    [[self window] setDelegate:self];
58
59    tabContentArea_.reset([[FastResizeView alloc] initWithFrame:
60        NSMakeRect(0, 0, 750, 600)]);
61    [tabContentArea_ setAutoresizingMask:NSViewWidthSizable |
62                                         NSViewHeightSizable];
63    [[[self window] contentView] addSubview:tabContentArea_];
64
65    tabStripView_.reset([[TabStripView alloc] initWithFrame:
66        NSMakeRect(0, 0, 750, 37)]);
67    [tabStripView_ setAutoresizingMask:NSViewWidthSizable |
68                                       NSViewMinYMargin];
69    if (hasTabStrip)
70      [self addTabStripToWindow];
71  }
72  return self;
73}
74
75- (TabStripView*)tabStripView {
76  return tabStripView_;
77}
78
79- (FastResizeView*)tabContentArea {
80  return tabContentArea_;
81}
82
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
85// window frame.
86- (void)addTabStripToWindow {
87  // The frame doesn't matter. This class relies on subclasses to do tab strip
88  // layout.
89  NSView* contentParent = [[[self window] contentView] superview];
90  [contentParent addSubview:tabStripView_];
91}
92
93- (void)removeOverlay {
94  [self setUseOverlay:NO];
95  if (closeDeferred_) {
96    // See comment in BrowserWindowCocoa::Close() about orderOut:.
97    [[self window] orderOut:self];
98    [[self window] performClose:self];  // Autoreleases the controller.
99  }
100}
101
102- (void)showOverlay {
103  [self setUseOverlay:YES];
104}
105
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)
114                                             object:nil];
115  NSWindow* window = [self window];
116  if (useOverlay && !overlayWindow_) {
117    DCHECK(!originalContentView_);
118
119    overlayWindow_ = [[TabWindowOverlayWindow alloc]
120                         initWithContentRect:[window frame]
121                                   styleMask:NSBorderlessWindowMask
122                                     backing:NSBackingStoreBuffered
123                                       defer:YES];
124    [overlayWindow_ setTitle:@"overlay"];
125    [overlayWindow_ setBackgroundColor:[NSColor clearColor]];
126    [overlayWindow_ setOpaque:NO];
127    [overlayWindow_ setDelegate:self];
128
129    originalContentView_ = [window contentView];
130    [window addChildWindow:overlayWindow_ ordered:NSWindowAbove];
131
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
136    // loss of focus.
137    focusBeforeOverlay_.reset([[FocusTracker alloc] initWithWindow:window]);
138    [window makeFirstResponder:nil];
139
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_];
146
147    [overlayWindow_ orderFront:nil];
148  } else if (!useOverlay && overlayWindow_) {
149    DCHECK(originalContentView_);
150
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
154    // view is set.
155    [window setContentView:originalContentView_];
156    [[[window contentView] superview] addSubview:[self tabStripView]];
157    [[[window contentView] superview] updateTrackingAreas];
158
159    [focusBeforeOverlay_ restoreFocusInWindow:window];
160    focusBeforeOverlay_.reset();
161
162    [window display];
163    [window removeChildWindow:overlayWindow_];
164
165    [overlayWindow_ orderOut:nil];
166    [overlayWindow_ release];
167    overlayWindow_ = nil;
168    originalContentView_ = nil;
169  } else {
170    NOTREACHED();
171  }
172}
173
174- (NSWindow*)overlayWindow {
175  return overlayWindow_;
176}
177
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;
182}
183
184- (BOOL)canReceiveFrom:(TabWindowController*)source {
185  // subclass must implement
186  NOTIMPLEMENTED();
187  return NO;
188}
189
190- (void)moveTabViews:(NSArray*)views
191      fromController:(TabWindowController*)dragController {
192  NOTIMPLEMENTED();
193}
194
195- (NSArray*)tabViews {
196  NOTIMPLEMENTED();
197  return nil;
198}
199
200- (NSView*)activeTabView {
201  NOTIMPLEMENTED();
202  return nil;
203}
204
205- (void)layoutTabs {
206  // subclass must implement
207  NOTIMPLEMENTED();
208}
209
210- (TabWindowController*)detachTabsToNewWindow:(NSArray*)tabViews
211                                   draggedTab:(NSView*)draggedTab {
212  // subclass must implement
213  NOTIMPLEMENTED();
214  return NULL;
215}
216
217- (void)insertPlaceholderForTab:(TabView*)tab frame:(NSRect)frame {
218  [self showNewTabButton:NO];
219}
220
221- (void)removePlaceholder {
222  [self showNewTabButton:YES];
223}
224
225- (BOOL)isDragSessionActive {
226  NOTIMPLEMENTED();
227  return NO;
228}
229
230- (BOOL)tabDraggingAllowed {
231  return YES;
232}
233
234- (BOOL)tabTearingAllowed {
235  return YES;
236}
237
238- (BOOL)windowMovementAllowed {
239  return YES;
240}
241
242- (BOOL)isTabFullyVisible:(TabView*)tab {
243  // Subclasses should implement this, but it's not necessary.
244  return YES;
245}
246
247- (void)showNewTabButton:(BOOL)show {
248  // subclass must implement
249  NOTIMPLEMENTED();
250}
251
252- (void)detachTabView:(NSView*)view {
253  // subclass must implement
254  NOTIMPLEMENTED();
255}
256
257- (NSInteger)numberOfTabs {
258  // subclass must implement
259  NOTIMPLEMENTED();
260  return 0;
261}
262
263- (BOOL)hasLiveTabs {
264  // subclass must implement
265  NOTIMPLEMENTED();
266  return NO;
267}
268
269- (NSString*)activeTabTitle {
270  // subclass must implement
271  NOTIMPLEMENTED();
272  return @"";
273}
274
275- (BOOL)hasTabStrip {
276  // Subclasses should implement this.
277  NOTIMPLEMENTED();
278  return YES;
279}
280
281- (BOOL)isTabDraggable:(NSView*)tabView {
282  // Subclasses should implement this.
283  NOTIMPLEMENTED();
284  return YES;
285}
286
287// Tell the window that it needs to call performClose: as soon as the current
288// drag is complete. This prevents a window (and its overlay) from going away
289// during a drag.
290- (void)deferPerformClose {
291  closeDeferred_ = YES;
292}
293
294// Called when the size of the window content area has changed. Override to
295// position specific views. Base class implementation does nothing.
296- (void)layoutSubviews {
297  NOTIMPLEMENTED();
298}
299
300@end
301