tab_window_controller.mm revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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)themePatternPhase { 37 if ([self parentWindow]) 38 return [[[self parentWindow] windowController] themePatternPhase]; 39 return NSZeroPoint; 40} 41 42@end 43 44@implementation TabWindowController 45 46- (id)initTabWindowControllerWithTabStrip:(BOOL)hasTabStrip { 47 NSRect contentRect = NSMakeRect(60, 229, 750, 600); 48 base::scoped_nsobject<FramedBrowserWindow> window( 49 [[FramedBrowserWindow alloc] initWithContentRect:contentRect 50 hasTabStrip:hasTabStrip]); 51 [window setReleasedWhenClosed:YES]; 52 [window setAutorecalculatesKeyViewLoop:YES]; 53 54 if ((self = [super initWithWindow:window])) { 55 [[self window] setDelegate:self]; 56 57 tabContentArea_.reset([[FastResizeView alloc] initWithFrame: 58 NSMakeRect(0, 0, 750, 600)]); 59 [tabContentArea_ setAutoresizingMask:NSViewWidthSizable | 60 NSViewHeightSizable]; 61 [[[self window] contentView] addSubview:tabContentArea_]; 62 63 tabStripView_.reset([[TabStripView alloc] initWithFrame: 64 NSMakeRect(0, 0, 750, 37)]); 65 [tabStripView_ setAutoresizingMask:NSViewWidthSizable | 66 NSViewMinYMargin]; 67 if (hasTabStrip) 68 [self addTabStripToWindow]; 69 } 70 return self; 71} 72 73- (TabStripView*)tabStripView { 74 return tabStripView_; 75} 76 77- (FastResizeView*)tabContentArea { 78 return tabContentArea_; 79} 80 81// Add the top tab strop to the window, above the content box and add it to the 82// view hierarchy as a sibling of the content view so it can overlap with the 83// window frame. 84- (void)addTabStripToWindow { 85 // The frame doesn't matter. This class relies on subclasses to do tab strip 86 // layout. 87 NSView* contentParent = [[[self window] contentView] superview]; 88 [contentParent addSubview:tabStripView_]; 89} 90 91- (void)removeOverlay { 92 [self setUseOverlay:NO]; 93 if (closeDeferred_) { 94 // See comment in BrowserWindowCocoa::Close() about orderOut:. 95 [[self window] orderOut:self]; 96 [[self window] performClose:self]; // Autoreleases the controller. 97 } 98} 99 100- (void)showOverlay { 101 [self setUseOverlay:YES]; 102} 103 104// If |useOverlay| is YES, creates a new overlay window and puts the tab strip 105// and the content area inside of it. This allows it to have a different opacity 106// from the title bar. If NO, returns everything to the previous state and 107// destroys the overlay window until it's needed again. The tab strip and window 108// contents are returned to the original window. 109- (void)setUseOverlay:(BOOL)useOverlay { 110 [NSObject cancelPreviousPerformRequestsWithTarget:self 111 selector:@selector(removeOverlay) 112 object:nil]; 113 NSWindow* window = [self window]; 114 if (useOverlay && !overlayWindow_) { 115 DCHECK(!originalContentView_); 116 117 overlayWindow_ = [[TabWindowOverlayWindow alloc] 118 initWithContentRect:[window frame] 119 styleMask:NSBorderlessWindowMask 120 backing:NSBackingStoreBuffered 121 defer:YES]; 122 [overlayWindow_ setTitle:@"overlay"]; 123 [overlayWindow_ setBackgroundColor:[NSColor clearColor]]; 124 [overlayWindow_ setOpaque:NO]; 125 [overlayWindow_ setDelegate:self]; 126 127 originalContentView_ = [window contentView]; 128 [window addChildWindow:overlayWindow_ ordered:NSWindowAbove]; 129 130 // Explicitly set the responder to be nil here (for restoring later). 131 // If the first responder were to be left non-nil here then 132 // [RenderWidgethostViewCocoa resignFirstResponder] would be called, 133 // followed by RenderWidgetHost::Blur(), which would result in an unexpected 134 // loss of focus. 135 focusBeforeOverlay_.reset([[FocusTracker alloc] initWithWindow:window]); 136 [window makeFirstResponder:nil]; 137 138 // Move the original window's tab strip view and content view to the overlay 139 // window. The content view is added as a subview of the overlay window's 140 // content view (rather than using setContentView:) because the overlay 141 // window has a different content size (due to it being borderless). 142 [[[overlayWindow_ contentView] superview] addSubview:[self tabStripView]]; 143 [[overlayWindow_ contentView] addSubview:originalContentView_]; 144 145 [overlayWindow_ orderFront:nil]; 146 } else if (!useOverlay && overlayWindow_) { 147 DCHECK(originalContentView_); 148 149 // Return the original window's tab strip view and content view to their 150 // places. The TabStripView always needs to be in front of the window's 151 // content view and therefore it should always be added after the content 152 // view is set. 153 [window setContentView:originalContentView_]; 154 [[[window contentView] superview] addSubview:[self tabStripView]]; 155 [[[window contentView] superview] updateTrackingAreas]; 156 157 [focusBeforeOverlay_ restoreFocusInWindow:window]; 158 focusBeforeOverlay_.reset(); 159 160 [window display]; 161 [window removeChildWindow:overlayWindow_]; 162 163 [overlayWindow_ orderOut:nil]; 164 [overlayWindow_ release]; 165 overlayWindow_ = nil; 166 originalContentView_ = nil; 167 } else { 168 NOTREACHED(); 169 } 170} 171 172- (NSWindow*)overlayWindow { 173 return overlayWindow_; 174} 175 176- (BOOL)shouldConstrainFrameRect { 177 // If we currently have an overlay window, do not attempt to change the 178 // window's size, as our overlay window doesn't know how to resize properly. 179 return overlayWindow_ == nil; 180} 181 182- (BOOL)canReceiveFrom:(TabWindowController*)source { 183 // subclass must implement 184 NOTIMPLEMENTED(); 185 return NO; 186} 187 188- (void)moveTabView:(NSView*)view 189 fromController:(TabWindowController*)dragController { 190 NOTIMPLEMENTED(); 191} 192 193- (NSView*)activeTabView { 194 NOTIMPLEMENTED(); 195 return nil; 196} 197 198- (void)layoutTabs { 199 // subclass must implement 200 NOTIMPLEMENTED(); 201} 202 203- (TabWindowController*)detachTabToNewWindow:(TabView*)tabView { 204 // subclass must implement 205 NOTIMPLEMENTED(); 206 return NULL; 207} 208 209- (void)insertPlaceholderForTab:(TabView*)tab frame:(NSRect)frame { 210 [self showNewTabButton:NO]; 211} 212 213- (void)removePlaceholder { 214 [self showNewTabButton:YES]; 215} 216 217- (BOOL)isDragSessionActive { 218 NOTIMPLEMENTED(); 219 return NO; 220} 221 222- (BOOL)tabDraggingAllowed { 223 return YES; 224} 225 226- (BOOL)tabTearingAllowed { 227 return YES; 228} 229 230- (BOOL)windowMovementAllowed { 231 return YES; 232} 233 234- (BOOL)isTabFullyVisible:(TabView*)tab { 235 // Subclasses should implement this, but it's not necessary. 236 return YES; 237} 238 239- (void)showNewTabButton:(BOOL)show { 240 // subclass must implement 241 NOTIMPLEMENTED(); 242} 243 244- (void)detachTabView:(NSView*)view { 245 // subclass must implement 246 NOTIMPLEMENTED(); 247} 248 249- (NSInteger)numberOfTabs { 250 // subclass must implement 251 NOTIMPLEMENTED(); 252 return 0; 253} 254 255- (BOOL)hasLiveTabs { 256 // subclass must implement 257 NOTIMPLEMENTED(); 258 return NO; 259} 260 261- (NSString*)activeTabTitle { 262 // subclass must implement 263 NOTIMPLEMENTED(); 264 return @""; 265} 266 267- (BOOL)hasTabStrip { 268 // Subclasses should implement this. 269 NOTIMPLEMENTED(); 270 return YES; 271} 272 273- (BOOL)isTabDraggable:(NSView*)tabView { 274 // Subclasses should implement this. 275 NOTIMPLEMENTED(); 276 return YES; 277} 278 279// Tell the window that it needs to call performClose: as soon as the current 280// drag is complete. This prevents a window (and its overlay) from going away 281// during a drag. 282- (void)deferPerformClose { 283 closeDeferred_ = YES; 284} 285 286// Called when the size of the window content area has changed. Override to 287// position specific views. Base class implementation does nothing. 288- (void)layoutSubviews { 289 NOTIMPLEMENTED(); 290} 291 292@end 293