| Index: chrome/browser/ui/cocoa/framed_browser_window.mm
|
| diff --git a/chrome/browser/ui/cocoa/framed_browser_window.mm b/chrome/browser/ui/cocoa/framed_browser_window.mm
|
| index d99f8642207e9c6f166d0faa7af2036d57de0c1c..c79a99675ba7adbf7b8043ad6e516163c50a7cfe 100644
|
| --- a/chrome/browser/ui/cocoa/framed_browser_window.mm
|
| +++ b/chrome/browser/ui/cocoa/framed_browser_window.mm
|
| @@ -4,6 +4,8 @@
|
|
|
| #import "chrome/browser/ui/cocoa/framed_browser_window.h"
|
|
|
| +#include <math.h>
|
| +#include <objc/runtime.h>
|
| #include <stddef.h>
|
|
|
| #include "base/logging.h"
|
| @@ -13,6 +15,7 @@
|
| #include "chrome/browser/themes/theme_properties.h"
|
| #include "chrome/browser/themes/theme_service.h"
|
| #import "chrome/browser/ui/cocoa/browser_window_controller.h"
|
| +#import "chrome/browser/ui/cocoa/browser_window_layout.h"
|
| #import "chrome/browser/ui/cocoa/browser_window_utils.h"
|
| #include "chrome/browser/ui/cocoa/l10n_util.h"
|
| #import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h"
|
| @@ -40,6 +43,28 @@ const CGFloat kWindowGradientHeight = 24.0;
|
|
|
| @interface FramedBrowserWindow (Private)
|
|
|
| +// Updates the title bar's frame so it moves the windows buttons to correct
|
| +// location (frame bottom is moved down so the buttons are moved down as well).
|
| +- (void)adjustTitlebarContainer:(NSView*)titlebarContainer;
|
| +// Adds layout constraints to window buttons, respecting flag returned by
|
| +// |ShouldDoExperimentalRTLLayout| method.
|
| +- (void)setWindowButtonsConstraints;
|
| +// Replaces -[NSThemeFrame addTrackingArea:] with implementation that ignores
|
| +// tracking rect if its size is the same as the size of window buttons rect
|
| +// (rect where close, miniaturize and zoom buttons are located). This is
|
| +// needed to workaround macOS bug (rdar://28535344) which unnecessarily adds
|
| +// window buttons tracking rect even if those buttons were moved.
|
| +// TODO(crbug.com/651287): Remove this workaround once macOS bug is fixed.
|
| +- (void)forbidAddingWindowButtonsTrackingArea;
|
| +// Called when titlebar container changes its frame. This method adjusts
|
| +// titlebar container with correct frame.
|
| +- (void)titlebarDidChangeFrameNotification:(NSNotification*)notification;
|
| +// Adds layout constraints to the given window button so it displayed at correct
|
| +// location. This respects flag returned by |ShouldDoExperimentalRTLLayout|
|
| +// method.
|
| +- (void)setLeadingOffset:(CGFloat)leadingOffset
|
| + toButton:(NSWindowButton)buttonType;
|
| +
|
| - (void)adjustCloseButton:(NSNotification*)notification;
|
| - (void)adjustMiniaturizeButton:(NSNotification*)notification;
|
| - (void)adjustZoomButton:(NSNotification*)notification;
|
| @@ -51,6 +76,11 @@ const CGFloat kWindowGradientHeight = 24.0;
|
|
|
| @implementation FramedBrowserWindow
|
|
|
| ++ (CGFloat)browserFrameViewPaintHeight {
|
| + return chrome::ShouldUseFullSizeContentView() ? chrome::kTabStripHeight
|
| + : 60.0;
|
| +}
|
| +
|
| - (void)setStyleMask:(NSUInteger)styleMask {
|
| if (styleMaskLock_)
|
| return;
|
| @@ -64,6 +94,12 @@ const CGFloat kWindowGradientHeight = 24.0;
|
| NSMiniaturizableWindowMask |
|
| NSResizableWindowMask |
|
| NSTexturedBackgroundWindowMask;
|
| + bool shouldUseFullSizeContentView =
|
| + chrome::ShouldUseFullSizeContentView() && hasTabStrip;
|
| + if (shouldUseFullSizeContentView) {
|
| + styleMask |= NSFullSizeContentViewWindowMask;
|
| + }
|
| +
|
| if ((self = [super initWithContentRect:contentRect
|
| styleMask:styleMask
|
| backing:NSBackingStoreBuffered
|
| @@ -83,32 +119,55 @@ const CGFloat kWindowGradientHeight = 24.0;
|
|
|
| hasTabStrip_ = hasTabStrip;
|
| closeButton_ = [self standardWindowButton:NSWindowCloseButton];
|
| - [closeButton_ setPostsFrameChangedNotifications:YES];
|
| miniaturizeButton_ = [self standardWindowButton:NSWindowMiniaturizeButton];
|
| - [miniaturizeButton_ setPostsFrameChangedNotifications:YES];
|
| zoomButton_ = [self standardWindowButton:NSWindowZoomButton];
|
| - [zoomButton_ setPostsFrameChangedNotifications:YES];
|
|
|
| windowButtonsInterButtonSpacing_ =
|
| NSMinX([miniaturizeButton_ frame]) - NSMaxX([closeButton_ frame]);
|
|
|
| - [self adjustButton:closeButton_ ofKind:NSWindowCloseButton];
|
| - [self adjustButton:miniaturizeButton_ ofKind:NSWindowMiniaturizeButton];
|
| - [self adjustButton:zoomButton_ ofKind:NSWindowZoomButton];
|
| -
|
| NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
|
| - [center addObserver:self
|
| - selector:@selector(adjustCloseButton:)
|
| - name:NSViewFrameDidChangeNotification
|
| - object:closeButton_];
|
| - [center addObserver:self
|
| - selector:@selector(adjustMiniaturizeButton:)
|
| - name:NSViewFrameDidChangeNotification
|
| - object:miniaturizeButton_];
|
| - [center addObserver:self
|
| - selector:@selector(adjustZoomButton:)
|
| - name:NSViewFrameDidChangeNotification
|
| - object:zoomButton_];
|
| + if (shouldUseFullSizeContentView) {
|
| + // If Chrome uses full sized content view then window buttons are placed
|
| + // inside titlebar (which height is 22 points). In order to move window
|
| + // buttons down the whole toolbar should be moved down.
|
| + DCHECK(closeButton_);
|
| + NSView* titlebarContainer = [[closeButton_ superview] superview];
|
| + [self adjustTitlebarContainer:titlebarContainer];
|
| + [center addObserver:self
|
| + selector:@selector(titlebarDidChangeFrameNotification:)
|
| + name:NSViewFrameDidChangeNotification
|
| + object:titlebarContainer];
|
| + // Window buttons are not movable unless their positioning is forced via
|
| + // layout constraints.
|
| + [self setWindowButtonsConstraints];
|
| + // Remove an extra tracking rect unnecessarily added by AppKit which
|
| + // highlights the buttons on mouse enter event. That rect is added where
|
| + // buttons used to be previously.
|
| + [self forbidAddingWindowButtonsTrackingArea];
|
| + } else {
|
| + // If Chrome does not use a full sized content view then AppKit adds the
|
| + // window buttons to the root view, where they must be manually
|
| + // re-positioned.
|
| + [self adjustButton:closeButton_ ofKind:NSWindowCloseButton];
|
| + [self adjustButton:miniaturizeButton_ ofKind:NSWindowMiniaturizeButton];
|
| + [self adjustButton:zoomButton_ ofKind:NSWindowZoomButton];
|
| + [closeButton_ setPostsFrameChangedNotifications:YES];
|
| + [miniaturizeButton_ setPostsFrameChangedNotifications:YES];
|
| + [zoomButton_ setPostsFrameChangedNotifications:YES];
|
| +
|
| + [center addObserver:self
|
| + selector:@selector(adjustCloseButton:)
|
| + name:NSViewFrameDidChangeNotification
|
| + object:closeButton_];
|
| + [center addObserver:self
|
| + selector:@selector(adjustMiniaturizeButton:)
|
| + name:NSViewFrameDidChangeNotification
|
| + object:miniaturizeButton_];
|
| + [center addObserver:self
|
| + selector:@selector(adjustZoomButton:)
|
| + name:NSViewFrameDidChangeNotification
|
| + object:zoomButton_];
|
| + }
|
| }
|
|
|
| return self;
|
| @@ -119,6 +178,97 @@ const CGFloat kWindowGradientHeight = 24.0;
|
| [super dealloc];
|
| }
|
|
|
| +- (void)adjustTitlebarContainer:(NSView*)titlebarContainer {
|
| + DCHECK(chrome::ShouldUseFullSizeContentView());
|
| + DCHECK([NSStringFromClass([titlebarContainer class])
|
| + isEqual:@"NSTitlebarContainerView"]);
|
| +
|
| + NSRect newFrame = [titlebarContainer frame];
|
| + NSRect superviewFrame = [[titlebarContainer superview] frame];
|
| + // Increase toolbar height to move window buttons down where they should be.
|
| + newFrame.size.height =
|
| + floor((chrome::kTabStripHeight + NSHeight([closeButton_ frame])) / 2.0);
|
| + newFrame.size.width = NSWidth(superviewFrame);
|
| + newFrame.origin.y = NSHeight(superviewFrame) - NSHeight(newFrame);
|
| + newFrame.origin.x = NSMinX(superviewFrame);
|
| + [titlebarContainer setFrame:newFrame];
|
| +}
|
| +
|
| +- (void)setWindowButtonsConstraints {
|
| + DCHECK(chrome::ShouldUseFullSizeContentView());
|
| +
|
| + CGFloat leadingOffset =
|
| + hasTabStrip_ ? kFramedWindowButtonsWithTabStripOffsetFromLeft
|
| + : kFramedWindowButtonsWithoutTabStripOffsetFromLeft;
|
| + [self setLeadingOffset:leadingOffset toButton:NSWindowCloseButton];
|
| +
|
| + leadingOffset +=
|
| + windowButtonsInterButtonSpacing_ + NSWidth([closeButton_ frame]);
|
| + [self setLeadingOffset:leadingOffset toButton:NSWindowMiniaturizeButton];
|
| +
|
| + leadingOffset +=
|
| + windowButtonsInterButtonSpacing_ + NSWidth([miniaturizeButton_ frame]);
|
| + [self setLeadingOffset:leadingOffset toButton:NSWindowZoomButton];
|
| +}
|
| +
|
| +- (void)forbidAddingWindowButtonsTrackingArea {
|
| + DCHECK(chrome::ShouldUseFullSizeContentView());
|
| +
|
| + static dispatch_once_t onceToken;
|
| + dispatch_once(&onceToken, ^{
|
| + NSView* themeFrame = [[[closeButton_ superview] superview] superview];
|
| + Class themeFrameClass = [themeFrame class];
|
| + DCHECK([NSStringFromClass(themeFrameClass) isEqual:@"NSThemeFrame"]);
|
| + SEL addTrackingAreaSelector = @selector(addTrackingArea:);
|
| + Method originalMethod =
|
| + class_getInstanceMethod(themeFrameClass, addTrackingAreaSelector);
|
| + IMP originalImp = method_getImplementation(originalMethod);
|
| + NSRect windowButtonsRect = NSUnionRect(
|
| + NSUnionRect([closeButton_ frame], [miniaturizeButton_ frame]),
|
| + [zoomButton_ frame]);
|
| + NSSize buttonsAreaSize = NSIntegralRect(windowButtonsRect).size;
|
| +
|
| + // |newImp| is never released with |imp_removeBlock|.
|
| + IMP newImp = imp_implementationWithBlock(^(id self, id area) {
|
| + // There is no other way to ensure that |area| is responsible for buttons
|
| + // highlighting except by relying on its size.
|
| + if (!NSEqualSizes(buttonsAreaSize, NSIntegralRect([area rect]).size)) {
|
| + originalImp(self, addTrackingAreaSelector, area);
|
| + }
|
| + });
|
| +
|
| + // Do not use base::mac::ScopedObjCClassSwizzler as it replaces existing
|
| + // implementation which is defined in NSView and will affect the whole app
|
| + // performance.
|
| + class_replaceMethod(themeFrameClass, addTrackingAreaSelector, newImp,
|
| + method_getTypeEncoding(originalMethod));
|
| + });
|
| +}
|
| +
|
| +- (void)titlebarDidChangeFrameNotification:(NSNotification*)notification {
|
| + [self adjustTitlebarContainer:[notification object]];
|
| +}
|
| +
|
| +- (void)setLeadingOffset:(CGFloat)leadingOffset
|
| + toButton:(NSWindowButton)buttonType {
|
| + DCHECK(chrome::ShouldUseFullSizeContentView());
|
| +
|
| + NSButton* button = [self standardWindowButton:buttonType];
|
| + [button setTranslatesAutoresizingMaskIntoConstraints:NO];
|
| +
|
| + // Do not use leadingAnchor because |ShouldDoExperimentalRTLLayout|
|
| + // should determine if current locale is RTL.
|
| + NSLayoutXAxisAnchor* leadingSourceAnchor = [button leftAnchor];
|
| + NSLayoutXAxisAnchor* leadingTargetAnchor = [[button superview] leftAnchor];
|
| + if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout()) {
|
| + leadingSourceAnchor = [button rightAnchor];
|
| + leadingTargetAnchor = [[button superview] rightAnchor];
|
| + leadingOffset = -leadingOffset;
|
| + }
|
| + [[leadingSourceAnchor constraintEqualToAnchor:leadingTargetAnchor
|
| + constant:leadingOffset] setActive:YES];
|
| +}
|
| +
|
| - (void)adjustCloseButton:(NSNotification*)notification {
|
| [self adjustButton:[notification object]
|
| ofKind:NSWindowCloseButton];
|
|
|