Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3832)

Unified Diff: chrome/browser/ui/cocoa/framed_browser_window.mm

Issue 2404783002: [Mac] Avoid "adding unknown subview" warning. (Closed)
Patch Set: Merged with head Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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];

Powered by Google App Engine
This is Rietveld 408576698