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