blob: c3cc590b7d67b83b2fd86084d601d824f4ca187d [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "chrome/browser/ui/cocoa/tabs/tab_window_controller.h"
#include "base/logging.h"
#import "chrome/browser/ui/cocoa/fast_resize_view.h"
#import "chrome/browser/ui/cocoa/framed_browser_window.h"
#import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h"
#import "chrome/browser/ui/cocoa/themed_window.h"
#import "ui/base/cocoa/focus_tracker.h"
#include "ui/base/theme_provider.h"
@interface TabWindowController(PRIVATE)
- (void)setUseOverlay:(BOOL)useOverlay;
@end
@interface TabWindowOverlayWindow : NSWindow
@end
@implementation TabWindowOverlayWindow
- (ui::ThemeProvider*)themeProvider {
if ([self parentWindow])
return [[[self parentWindow] windowController] themeProvider];
return NULL;
}
- (ThemedWindowStyle)themedWindowStyle {
if ([self parentWindow])
return [[[self parentWindow] windowController] themedWindowStyle];
return NO;
}
- (NSPoint)themeImagePositionForAlignment:(ThemeImageAlignment)alignment {
if ([self parentWindow]) {
return [[[self parentWindow] windowController]
themeImagePositionForAlignment:alignment];
}
return NSZeroPoint;
}
@end
@implementation TabWindowController
- (id)initTabWindowControllerWithTabStrip:(BOOL)hasTabStrip {
NSRect contentRect = NSMakeRect(60, 229, 750, 600);
base::scoped_nsobject<FramedBrowserWindow> window(
[[FramedBrowserWindow alloc] initWithContentRect:contentRect
hasTabStrip:hasTabStrip]);
[window setReleasedWhenClosed:YES];
[window setAutorecalculatesKeyViewLoop:YES];
if ((self = [super initWithWindow:window])) {
[[self window] setDelegate:self];
tabContentArea_.reset([[FastResizeView alloc] initWithFrame:
NSMakeRect(0, 0, 750, 600)]);
[tabContentArea_ setAutoresizingMask:NSViewWidthSizable |
NSViewHeightSizable];
[[[self window] contentView] addSubview:tabContentArea_];
tabStripView_.reset([[TabStripView alloc] initWithFrame:
NSMakeRect(0, 0, 750, 37)]);
[tabStripView_ setAutoresizingMask:NSViewWidthSizable |
NSViewMinYMargin];
if (hasTabStrip)
[self addTabStripToWindow];
}
return self;
}
- (TabStripView*)tabStripView {
return tabStripView_;
}
- (FastResizeView*)tabContentArea {
return tabContentArea_;
}
// Add the top tab strop to the window, above the content box and add it to the
// view hierarchy as a sibling of the content view so it can overlap with the
// window frame.
- (void)addTabStripToWindow {
// The frame doesn't matter. This class relies on subclasses to do tab strip
// layout.
NSView* contentParent = [[[self window] contentView] superview];
[contentParent addSubview:tabStripView_];
}
- (void)removeOverlay {
[self setUseOverlay:NO];
if (closeDeferred_) {
// See comment in BrowserWindowCocoa::Close() about orderOut:.
[[self window] orderOut:self];
[[self window] performClose:self]; // Autoreleases the controller.
}
}
- (void)showOverlay {
[self setUseOverlay:YES];
}
// If |useOverlay| is YES, creates a new overlay window and puts the tab strip
// and the content area inside of it. This allows it to have a different opacity
// from the title bar. If NO, returns everything to the previous state and
// destroys the overlay window until it's needed again. The tab strip and window
// contents are returned to the original window.
- (void)setUseOverlay:(BOOL)useOverlay {
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:@selector(removeOverlay)
object:nil];
NSWindow* window = [self window];
if (useOverlay && !overlayWindow_) {
DCHECK(!originalContentView_);
overlayWindow_ = [[TabWindowOverlayWindow alloc]
initWithContentRect:[window frame]
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:YES];
[overlayWindow_ setTitle:@"overlay"];
[overlayWindow_ setBackgroundColor:[NSColor clearColor]];
[overlayWindow_ setOpaque:NO];
[overlayWindow_ setDelegate:self];
originalContentView_ = [window contentView];
[window addChildWindow:overlayWindow_ ordered:NSWindowAbove];
// Explicitly set the responder to be nil here (for restoring later).
// If the first responder were to be left non-nil here then
// [RenderWidgethostViewCocoa resignFirstResponder] would be called,
// followed by RenderWidgetHost::Blur(), which would result in an unexpected
// loss of focus.
focusBeforeOverlay_.reset([[FocusTracker alloc] initWithWindow:window]);
[window makeFirstResponder:nil];
// Move the original window's tab strip view and content view to the overlay
// window. The content view is added as a subview of the overlay window's
// content view (rather than using setContentView:) because the overlay
// window has a different content size (due to it being borderless).
[[[overlayWindow_ contentView] superview] addSubview:[self tabStripView]];
[[overlayWindow_ contentView] addSubview:originalContentView_];
[overlayWindow_ orderFront:nil];
} else if (!useOverlay && overlayWindow_) {
DCHECK(originalContentView_);
// Return the original window's tab strip view and content view to their
// places. The TabStripView always needs to be in front of the window's
// content view and therefore it should always be added after the content
// view is set.
[window setContentView:originalContentView_];
[[[window contentView] superview] addSubview:[self tabStripView]];
[[[window contentView] superview] updateTrackingAreas];
[focusBeforeOverlay_ restoreFocusInWindow:window];
focusBeforeOverlay_.reset();
[window display];
[window removeChildWindow:overlayWindow_];
[overlayWindow_ orderOut:nil];
[overlayWindow_ release];
overlayWindow_ = nil;
originalContentView_ = nil;
} else {
NOTREACHED();
}
}
- (NSWindow*)overlayWindow {
return overlayWindow_;
}
- (BOOL)shouldConstrainFrameRect {
// If we currently have an overlay window, do not attempt to change the
// window's size, as our overlay window doesn't know how to resize properly.
return overlayWindow_ == nil;
}
- (BOOL)canReceiveFrom:(TabWindowController*)source {
// subclass must implement
NOTIMPLEMENTED();
return NO;
}
- (void)moveTabView:(NSView*)view
fromController:(TabWindowController*)dragController {
NOTIMPLEMENTED();
}
- (NSView*)activeTabView {
NOTIMPLEMENTED();
return nil;
}
- (void)layoutTabs {
// subclass must implement
NOTIMPLEMENTED();
}
- (TabWindowController*)detachTabToNewWindow:(TabView*)tabView {
// subclass must implement
NOTIMPLEMENTED();
return NULL;
}
- (void)insertPlaceholderForTab:(TabView*)tab frame:(NSRect)frame {
[self showNewTabButton:NO];
}
- (void)removePlaceholder {
[self showNewTabButton:YES];
}
- (BOOL)isDragSessionActive {
NOTIMPLEMENTED();
return NO;
}
- (BOOL)tabDraggingAllowed {
return YES;
}
- (BOOL)tabTearingAllowed {
return YES;
}
- (BOOL)windowMovementAllowed {
return YES;
}
- (BOOL)isTabFullyVisible:(TabView*)tab {
// Subclasses should implement this, but it's not necessary.
return YES;
}
- (void)showNewTabButton:(BOOL)show {
// subclass must implement
NOTIMPLEMENTED();
}
- (void)detachTabView:(NSView*)view {
// subclass must implement
NOTIMPLEMENTED();
}
- (NSInteger)numberOfTabs {
// subclass must implement
NOTIMPLEMENTED();
return 0;
}
- (BOOL)hasLiveTabs {
// subclass must implement
NOTIMPLEMENTED();
return NO;
}
- (NSString*)activeTabTitle {
// subclass must implement
NOTIMPLEMENTED();
return @"";
}
- (BOOL)hasTabStrip {
// Subclasses should implement this.
NOTIMPLEMENTED();
return YES;
}
- (BOOL)isTabDraggable:(NSView*)tabView {
// Subclasses should implement this.
NOTIMPLEMENTED();
return YES;
}
// Tell the window that it needs to call performClose: as soon as the current
// drag is complete. This prevents a window (and its overlay) from going away
// during a drag.
- (void)deferPerformClose {
closeDeferred_ = YES;
}
// Called when the size of the window content area has changed. Override to
// position specific views. Base class implementation does nothing.
- (void)layoutSubviews {
NOTIMPLEMENTED();
}
@end