blob: de0ca9a50d3eb22275edd7b4bdecc6408fca9e97 [file] [log] [blame]
// Copyright 2014 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/version_independent_window.h"
#include "base/logging.h"
#include "base/mac/mac_util.h"
#include "base/mac/scoped_nsobject.h"
// This view always takes the size of its superview. It is intended to be used
// as a NSWindow's contentView. It is needed because NSWindow's implementation
// explicitly resizes the contentView at inopportune times.
@interface FullSizeContentView : NSView
@end
namespace {
// Reorders the subviews of NSWindow's root view so that the contentView is
// moved to the back, and the ordering of the other views is unchanged.
// |context| should be an NSArray containing the subviews of the root view as
// they were previously ordered.
NSComparisonResult ReorderContentViewToBack(id firstView,
id secondView,
void* context) {
NSView* contentView = [[firstView window] contentView];
NSArray* subviews = static_cast<NSArray*>(context);
if (firstView == contentView)
return NSOrderedAscending;
if (secondView == contentView)
return NSOrderedDescending;
NSUInteger index1 = [subviews indexOfObject:firstView];
NSUInteger index2 = [subviews indexOfObject:secondView];
return (index1 < index2) ? NSOrderedAscending : NSOrderedDescending;
}
} // namespace
@interface VersionIndependentWindow ()
+ (BOOL)shouldUseFullSizeContentViewForStyle:(NSUInteger)windowStyle;
- (NSView*)chromeWindowView;
@end
@implementation FullSizeContentView
// This method is directly called by NSWindow during a window resize on OSX
// 10.10.0, beta 2. We must override it to prevent the content view from
// shrinking.
- (void)setFrameSize:(NSSize)size {
if ([self superview])
size = [[self superview] bounds].size;
[super setFrameSize:size];
}
@end
@implementation NSWindow (VersionIndependentWindow)
- (NSView*)cr_windowView {
if ([self isKindOfClass:[VersionIndependentWindow class]]) {
VersionIndependentWindow* window =
static_cast<VersionIndependentWindow*>(self);
NSView* chromeWindowView = [window chromeWindowView];
if (chromeWindowView)
return chromeWindowView;
}
return [[self contentView] superview];
}
@end
@implementation VersionIndependentWindow
#pragma mark - Lifecycle
- (instancetype)init {
NOTREACHED();
return nil;
}
- (instancetype)initWithContentRect:(NSRect)contentRect
styleMask:(NSUInteger)windowStyle
backing:(NSBackingStoreType)bufferingType
defer:(BOOL)deferCreation {
self = [super initWithContentRect:contentRect
styleMask:windowStyle
backing:bufferingType
defer:deferCreation];
if (self) {
if ([VersionIndependentWindow
shouldUseFullSizeContentViewForStyle:windowStyle]) {
chromeWindowView_.reset([[FullSizeContentView alloc] init]);
[chromeWindowView_
setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[self setContentView:chromeWindowView_];
[chromeWindowView_ setFrame:[[[self contentView] superview] bounds]];
// Move the content view to the back.
// In Yosemite, the content view takes up the full size of the window,
// and when it is in front of the zoom/fullscreen button, alt-clicking
// the button has the wrong effect.
// Adding subviews to the NSThemeFrame provokes a warning in Yosemite, so
// we sort the subviews in place.
// http://crbug.com/393808
NSView* superview = [[self contentView] superview];
base::scoped_nsobject<NSArray> subviews([[superview subviews] copy]);
[superview sortSubviewsUsingFunction:&ReorderContentViewToBack
context:subviews.get()];
}
}
return self;
}
#pragma mark - Private Methods
+ (BOOL)shouldUseFullSizeContentViewForStyle:(NSUInteger)windowStyle {
return (windowStyle & NSTitledWindowMask) && base::mac::IsOSYosemiteOrLater();
}
- (NSView*)chromeWindowView {
return chromeWindowView_;
}
#pragma mark - NSWindow Overrides
#ifndef NDEBUG
- (void)setContentSize:(NSSize)size {
DCHECK(!chromeWindowView_);
[super setContentSize:size];
}
- (void)setContentMinSize:(NSSize)size {
DCHECK(!chromeWindowView_);
[super setContentMinSize:size];
}
- (void)setContentMaxSize:(NSSize)size {
DCHECK(!chromeWindowView_);
[super setContentMaxSize:size];
}
- (void)setContentAspectRatio:(NSSize)ratio {
DCHECK(!chromeWindowView_);
[super setContentAspectRatio:ratio];
}
#endif // NDEBUG
+ (NSRect)frameRectForContentRect:(NSRect)cRect styleMask:(NSUInteger)aStyle {
if ([self shouldUseFullSizeContentViewForStyle:aStyle])
return cRect;
return [super frameRectForContentRect:cRect styleMask:aStyle];
}
- (NSRect)frameRectForContentRect:(NSRect)contentRect {
if (chromeWindowView_)
return contentRect;
return [super frameRectForContentRect:contentRect];
}
+ (NSRect)contentRectForFrameRect:(NSRect)fRect styleMask:(NSUInteger)aStyle {
if ([self shouldUseFullSizeContentViewForStyle:aStyle])
return fRect;
return [super contentRectForFrameRect:fRect styleMask:aStyle];
}
- (NSRect)contentRectForFrameRect:(NSRect)frameRect {
if (chromeWindowView_)
return frameRect;
return [super contentRectForFrameRect:frameRect];
}
@end