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

Side by Side 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import "chrome/browser/ui/cocoa/framed_browser_window.h" 5 #import "chrome/browser/ui/cocoa/framed_browser_window.h"
6 6
7 #include <math.h>
8 #include <objc/runtime.h>
7 #include <stddef.h> 9 #include <stddef.h>
8 10
9 #include "base/logging.h" 11 #include "base/logging.h"
10 #include "base/mac/sdk_forward_declarations.h" 12 #include "base/mac/sdk_forward_declarations.h"
11 #include "chrome/browser/global_keyboard_shortcuts_mac.h" 13 #include "chrome/browser/global_keyboard_shortcuts_mac.h"
12 #include "chrome/browser/profiles/profile_avatar_icon_util.h" 14 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
13 #include "chrome/browser/themes/theme_properties.h" 15 #include "chrome/browser/themes/theme_properties.h"
14 #include "chrome/browser/themes/theme_service.h" 16 #include "chrome/browser/themes/theme_service.h"
15 #import "chrome/browser/ui/cocoa/browser_window_controller.h" 17 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
18 #import "chrome/browser/ui/cocoa/browser_window_layout.h"
16 #import "chrome/browser/ui/cocoa/browser_window_utils.h" 19 #import "chrome/browser/ui/cocoa/browser_window_utils.h"
17 #include "chrome/browser/ui/cocoa/l10n_util.h" 20 #include "chrome/browser/ui/cocoa/l10n_util.h"
18 #import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h" 21 #import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h"
19 #import "chrome/browser/ui/cocoa/themed_window.h" 22 #import "chrome/browser/ui/cocoa/themed_window.h"
20 #include "chrome/grit/theme_resources.h" 23 #include "chrome/grit/theme_resources.h"
21 #include "ui/base/cocoa/cocoa_base_utils.h" 24 #include "ui/base/cocoa/cocoa_base_utils.h"
22 #include "ui/base/cocoa/nsgraphics_context_additions.h" 25 #include "ui/base/cocoa/nsgraphics_context_additions.h"
23 #import "ui/base/cocoa/nsview_additions.h" 26 #import "ui/base/cocoa/nsview_additions.h"
24 #include "ui/base/material_design/material_design_controller.h" 27 #include "ui/base/material_design/material_design_controller.h"
25 28
26 // Implementer's note: Moving the window controls is tricky. When altering the 29 // Implementer's note: Moving the window controls is tricky. When altering the
27 // code, ensure that: 30 // code, ensure that:
28 // - accessibility hit testing works 31 // - accessibility hit testing works
29 // - the accessibility hierarchy is correct 32 // - the accessibility hierarchy is correct
30 // - close/min in the background don't bring the window forward 33 // - close/min in the background don't bring the window forward
31 // - rollover effects work correctly 34 // - rollover effects work correctly
32 35
33 namespace { 36 namespace {
34 37
35 // Size of the gradient. Empirically determined so that the gradient looks 38 // Size of the gradient. Empirically determined so that the gradient looks
36 // like what the heuristic does when there are just a few tabs. 39 // like what the heuristic does when there are just a few tabs.
37 const CGFloat kWindowGradientHeight = 24.0; 40 const CGFloat kWindowGradientHeight = 24.0;
38 41
39 } 42 }
40 43
41 @interface FramedBrowserWindow (Private) 44 @interface FramedBrowserWindow (Private)
42 45
46 // Updates the title bar's frame so it moves the windows buttons to correct
47 // location (frame bottom is moved down so the buttons are moved down as well).
48 - (void)adjustTitlebarContainer:(NSView*)titlebarContainer;
49 // Adds layout constraints to window buttons, respecting flag returned by
50 // |ShouldDoExperimentalRTLLayout| method.
51 - (void)setWindowButtonsConstraints;
52 // Replaces -[NSThemeFrame addTrackingArea:] with implementation that ignores
53 // tracking rect if its size is the same as the size of window buttons rect
54 // (rect where close, miniaturize and zoom buttons are located). This is
55 // needed to workaround macOS bug (rdar://28535344) which unnecessarily adds
56 // window buttons tracking rect even if those buttons were moved.
57 // TODO(crbug.com/651287): Remove this workaround once macOS bug is fixed.
58 - (void)forbidAddingWindowButtonsTrackingArea;
59 // Called when titlebar container changes its frame. This method adjusts
60 // titlebar container with correct frame.
61 - (void)titlebarDidChangeFrameNotification:(NSNotification*)notification;
62 // Adds layout constraints to the given window button so it displayed at correct
63 // location. This respects flag returned by |ShouldDoExperimentalRTLLayout|
64 // method.
65 - (void)setLeadingOffset:(CGFloat)leadingOffset
66 toButton:(NSWindowButton)buttonType;
67
43 - (void)adjustCloseButton:(NSNotification*)notification; 68 - (void)adjustCloseButton:(NSNotification*)notification;
44 - (void)adjustMiniaturizeButton:(NSNotification*)notification; 69 - (void)adjustMiniaturizeButton:(NSNotification*)notification;
45 - (void)adjustZoomButton:(NSNotification*)notification; 70 - (void)adjustZoomButton:(NSNotification*)notification;
46 - (void)adjustButton:(NSButton*)button 71 - (void)adjustButton:(NSButton*)button
47 ofKind:(NSWindowButton)kind; 72 ofKind:(NSWindowButton)kind;
48 - (void)childWindowsDidChange; 73 - (void)childWindowsDidChange;
49 74
50 @end 75 @end
51 76
52 @implementation FramedBrowserWindow 77 @implementation FramedBrowserWindow
53 78
79 + (CGFloat)browserFrameViewPaintHeight {
80 return chrome::ShouldUseFullSizeContentView() ? chrome::kTabStripHeight
81 : 60.0;
82 }
83
54 - (void)setStyleMask:(NSUInteger)styleMask { 84 - (void)setStyleMask:(NSUInteger)styleMask {
55 if (styleMaskLock_) 85 if (styleMaskLock_)
56 return; 86 return;
57 [super setStyleMask:styleMask]; 87 [super setStyleMask:styleMask];
58 } 88 }
59 89
60 - (id)initWithContentRect:(NSRect)contentRect 90 - (id)initWithContentRect:(NSRect)contentRect
61 hasTabStrip:(BOOL)hasTabStrip{ 91 hasTabStrip:(BOOL)hasTabStrip{
62 NSUInteger styleMask = NSTitledWindowMask | 92 NSUInteger styleMask = NSTitledWindowMask |
63 NSClosableWindowMask | 93 NSClosableWindowMask |
64 NSMiniaturizableWindowMask | 94 NSMiniaturizableWindowMask |
65 NSResizableWindowMask | 95 NSResizableWindowMask |
66 NSTexturedBackgroundWindowMask; 96 NSTexturedBackgroundWindowMask;
97 bool shouldUseFullSizeContentView =
98 chrome::ShouldUseFullSizeContentView() && hasTabStrip;
99 if (shouldUseFullSizeContentView) {
100 styleMask |= NSFullSizeContentViewWindowMask;
101 }
102
67 if ((self = [super initWithContentRect:contentRect 103 if ((self = [super initWithContentRect:contentRect
68 styleMask:styleMask 104 styleMask:styleMask
69 backing:NSBackingStoreBuffered 105 backing:NSBackingStoreBuffered
70 defer:YES 106 defer:YES
71 wantsViewsOverTitlebar:hasTabStrip])) { 107 wantsViewsOverTitlebar:hasTabStrip])) {
72 // The 10.6 fullscreen code copies the title to a different window, which 108 // The 10.6 fullscreen code copies the title to a different window, which
73 // will assert if it's nil. 109 // will assert if it's nil.
74 [self setTitle:@""]; 110 [self setTitle:@""];
75 111
76 // The following two calls fix http://crbug.com/25684 by preventing the 112 // The following two calls fix http://crbug.com/25684 by preventing the
77 // window from recalculating the border thickness as the window is 113 // window from recalculating the border thickness as the window is
78 // resized. 114 // resized.
79 // This was causing the window tint to change for the default system theme 115 // This was causing the window tint to change for the default system theme
80 // when the window was being resized. 116 // when the window was being resized.
81 [self setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge]; 117 [self setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge];
82 [self setContentBorderThickness:kWindowGradientHeight forEdge:NSMaxYEdge]; 118 [self setContentBorderThickness:kWindowGradientHeight forEdge:NSMaxYEdge];
83 119
84 hasTabStrip_ = hasTabStrip; 120 hasTabStrip_ = hasTabStrip;
85 closeButton_ = [self standardWindowButton:NSWindowCloseButton]; 121 closeButton_ = [self standardWindowButton:NSWindowCloseButton];
86 [closeButton_ setPostsFrameChangedNotifications:YES];
87 miniaturizeButton_ = [self standardWindowButton:NSWindowMiniaturizeButton]; 122 miniaturizeButton_ = [self standardWindowButton:NSWindowMiniaturizeButton];
88 [miniaturizeButton_ setPostsFrameChangedNotifications:YES];
89 zoomButton_ = [self standardWindowButton:NSWindowZoomButton]; 123 zoomButton_ = [self standardWindowButton:NSWindowZoomButton];
90 [zoomButton_ setPostsFrameChangedNotifications:YES];
91 124
92 windowButtonsInterButtonSpacing_ = 125 windowButtonsInterButtonSpacing_ =
93 NSMinX([miniaturizeButton_ frame]) - NSMaxX([closeButton_ frame]); 126 NSMinX([miniaturizeButton_ frame]) - NSMaxX([closeButton_ frame]);
94 127
95 [self adjustButton:closeButton_ ofKind:NSWindowCloseButton]; 128 NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
96 [self adjustButton:miniaturizeButton_ ofKind:NSWindowMiniaturizeButton]; 129 if (shouldUseFullSizeContentView) {
97 [self adjustButton:zoomButton_ ofKind:NSWindowZoomButton]; 130 // If Chrome uses full sized content view then window buttons are placed
131 // inside titlebar (which height is 22 points). In order to move window
132 // buttons down the whole toolbar should be moved down.
133 DCHECK(closeButton_);
134 NSView* titlebarContainer = [[closeButton_ superview] superview];
135 [self adjustTitlebarContainer:titlebarContainer];
136 [center addObserver:self
137 selector:@selector(titlebarDidChangeFrameNotification:)
138 name:NSViewFrameDidChangeNotification
139 object:titlebarContainer];
140 // Window buttons are not movable unless their positioning is forced via
141 // layout constraints.
142 [self setWindowButtonsConstraints];
143 // Remove an extra tracking rect unnecessarily added by AppKit which
144 // highlights the buttons on mouse enter event. That rect is added where
145 // buttons used to be previously.
146 [self forbidAddingWindowButtonsTrackingArea];
147 } else {
148 // If Chrome does not use a full sized content view then AppKit adds the
149 // window buttons to the root view, where they must be manually
150 // re-positioned.
151 [self adjustButton:closeButton_ ofKind:NSWindowCloseButton];
152 [self adjustButton:miniaturizeButton_ ofKind:NSWindowMiniaturizeButton];
153 [self adjustButton:zoomButton_ ofKind:NSWindowZoomButton];
154 [closeButton_ setPostsFrameChangedNotifications:YES];
155 [miniaturizeButton_ setPostsFrameChangedNotifications:YES];
156 [zoomButton_ setPostsFrameChangedNotifications:YES];
98 157
99 NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; 158 [center addObserver:self
100 [center addObserver:self 159 selector:@selector(adjustCloseButton:)
101 selector:@selector(adjustCloseButton:) 160 name:NSViewFrameDidChangeNotification
102 name:NSViewFrameDidChangeNotification 161 object:closeButton_];
103 object:closeButton_]; 162 [center addObserver:self
104 [center addObserver:self 163 selector:@selector(adjustMiniaturizeButton:)
105 selector:@selector(adjustMiniaturizeButton:) 164 name:NSViewFrameDidChangeNotification
106 name:NSViewFrameDidChangeNotification 165 object:miniaturizeButton_];
107 object:miniaturizeButton_]; 166 [center addObserver:self
108 [center addObserver:self 167 selector:@selector(adjustZoomButton:)
109 selector:@selector(adjustZoomButton:) 168 name:NSViewFrameDidChangeNotification
110 name:NSViewFrameDidChangeNotification 169 object:zoomButton_];
111 object:zoomButton_]; 170 }
112 } 171 }
113 172
114 return self; 173 return self;
115 } 174 }
116 175
117 - (void)dealloc { 176 - (void)dealloc {
118 [[NSNotificationCenter defaultCenter] removeObserver:self]; 177 [[NSNotificationCenter defaultCenter] removeObserver:self];
119 [super dealloc]; 178 [super dealloc];
120 } 179 }
121 180
181 - (void)adjustTitlebarContainer:(NSView*)titlebarContainer {
182 DCHECK(chrome::ShouldUseFullSizeContentView());
183 DCHECK([NSStringFromClass([titlebarContainer class])
184 isEqual:@"NSTitlebarContainerView"]);
185
186 NSRect newFrame = [titlebarContainer frame];
187 NSRect superviewFrame = [[titlebarContainer superview] frame];
188 // Increase toolbar height to move window buttons down where they should be.
189 newFrame.size.height =
190 floor((chrome::kTabStripHeight + NSHeight([closeButton_ frame])) / 2.0);
191 newFrame.size.width = NSWidth(superviewFrame);
192 newFrame.origin.y = NSHeight(superviewFrame) - NSHeight(newFrame);
193 newFrame.origin.x = NSMinX(superviewFrame);
194 [titlebarContainer setFrame:newFrame];
195 }
196
197 - (void)setWindowButtonsConstraints {
198 DCHECK(chrome::ShouldUseFullSizeContentView());
199
200 CGFloat leadingOffset =
201 hasTabStrip_ ? kFramedWindowButtonsWithTabStripOffsetFromLeft
202 : kFramedWindowButtonsWithoutTabStripOffsetFromLeft;
203 [self setLeadingOffset:leadingOffset toButton:NSWindowCloseButton];
204
205 leadingOffset +=
206 windowButtonsInterButtonSpacing_ + NSWidth([closeButton_ frame]);
207 [self setLeadingOffset:leadingOffset toButton:NSWindowMiniaturizeButton];
208
209 leadingOffset +=
210 windowButtonsInterButtonSpacing_ + NSWidth([miniaturizeButton_ frame]);
211 [self setLeadingOffset:leadingOffset toButton:NSWindowZoomButton];
212 }
213
214 - (void)forbidAddingWindowButtonsTrackingArea {
215 DCHECK(chrome::ShouldUseFullSizeContentView());
216
217 static dispatch_once_t onceToken;
218 dispatch_once(&onceToken, ^{
219 NSView* themeFrame = [[[closeButton_ superview] superview] superview];
220 Class themeFrameClass = [themeFrame class];
221 DCHECK([NSStringFromClass(themeFrameClass) isEqual:@"NSThemeFrame"]);
222 SEL addTrackingAreaSelector = @selector(addTrackingArea:);
223 Method originalMethod =
224 class_getInstanceMethod(themeFrameClass, addTrackingAreaSelector);
225 IMP originalImp = method_getImplementation(originalMethod);
226 NSRect windowButtonsRect = NSUnionRect(
227 NSUnionRect([closeButton_ frame], [miniaturizeButton_ frame]),
228 [zoomButton_ frame]);
229 NSSize buttonsAreaSize = NSIntegralRect(windowButtonsRect).size;
230
231 // |newImp| is never released with |imp_removeBlock|.
232 IMP newImp = imp_implementationWithBlock(^(id self, id area) {
233 // There is no other way to ensure that |area| is responsible for buttons
234 // highlighting except by relying on its size.
235 if (!NSEqualSizes(buttonsAreaSize, NSIntegralRect([area rect]).size)) {
236 originalImp(self, addTrackingAreaSelector, area);
237 }
238 });
239
240 // Do not use base::mac::ScopedObjCClassSwizzler as it replaces existing
241 // implementation which is defined in NSView and will affect the whole app
242 // performance.
243 class_replaceMethod(themeFrameClass, addTrackingAreaSelector, newImp,
244 method_getTypeEncoding(originalMethod));
245 });
246 }
247
248 - (void)titlebarDidChangeFrameNotification:(NSNotification*)notification {
249 [self adjustTitlebarContainer:[notification object]];
250 }
251
252 - (void)setLeadingOffset:(CGFloat)leadingOffset
253 toButton:(NSWindowButton)buttonType {
254 DCHECK(chrome::ShouldUseFullSizeContentView());
255
256 NSButton* button = [self standardWindowButton:buttonType];
257 [button setTranslatesAutoresizingMaskIntoConstraints:NO];
258
259 // Do not use leadingAnchor because |ShouldDoExperimentalRTLLayout|
260 // should determine if current locale is RTL.
261 NSLayoutXAxisAnchor* leadingSourceAnchor = [button leftAnchor];
262 NSLayoutXAxisAnchor* leadingTargetAnchor = [[button superview] leftAnchor];
263 if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout()) {
264 leadingSourceAnchor = [button rightAnchor];
265 leadingTargetAnchor = [[button superview] rightAnchor];
266 leadingOffset = -leadingOffset;
267 }
268 [[leadingSourceAnchor constraintEqualToAnchor:leadingTargetAnchor
269 constant:leadingOffset] setActive:YES];
270 }
271
122 - (void)adjustCloseButton:(NSNotification*)notification { 272 - (void)adjustCloseButton:(NSNotification*)notification {
123 [self adjustButton:[notification object] 273 [self adjustButton:[notification object]
124 ofKind:NSWindowCloseButton]; 274 ofKind:NSWindowCloseButton];
125 } 275 }
126 276
127 - (void)adjustMiniaturizeButton:(NSNotification*)notification { 277 - (void)adjustMiniaturizeButton:(NSNotification*)notification {
128 [self adjustButton:[notification object] 278 [self adjustButton:[notification object]
129 ofKind:NSWindowMiniaturizeButton]; 279 ofKind:NSWindowMiniaturizeButton];
130 } 280 }
131 281
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 [self childWindowsDidChange]; 498 [self childWindowsDidChange];
349 } 499 }
350 500
351 - (void)childWindowsDidChange { 501 - (void)childWindowsDidChange {
352 id delegate = [self delegate]; 502 id delegate = [self delegate];
353 if ([delegate respondsToSelector:@selector(childWindowsDidChange)]) 503 if ([delegate respondsToSelector:@selector(childWindowsDidChange)])
354 [delegate childWindowsDidChange]; 504 [delegate childWindowsDidChange];
355 } 505 }
356 506
357 @end 507 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698