1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
|
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "components/remote_cocoa/app_shim/browser_native_widget_window_mac.h"
#import <AppKit/AppKit.h>
#include "base/mac/mac_util.h"
#include "components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h"
#include "components/remote_cocoa/common/native_widget_ns_window_host.mojom.h"
namespace {
// Workaround for https://crbug.com/1369643
const double kThinControllerHeight = 0.5;
} // namespace
@interface NSWindow (PrivateBrowserNativeWidgetAPI)
+ (Class)frameViewClassForStyleMask:(NSUInteger)windowStyle;
@end
@interface NSThemeFrame (PrivateBrowserNativeWidgetAPI)
- (CGFloat)_titlebarHeight;
- (CGFloat)_minXTitlebarWidgetInset;
- (CGFloat)_getCachedWindowCornerRadius;
- (void)setStyleMask:(NSUInteger)styleMask;
- (void)setButtonRevealAmount:(double)amount;
@end
@interface BrowserWindowFrame : NativeWidgetMacNSWindowTitledFrame
@end
@implementation BrowserWindowFrame {
BOOL _inFullScreen;
BOOL _alwaysShowTrafficLights;
}
// NSThemeFrame overrides.
// Note that while this has an effect on the location of the window control
// widgets, this is also an important part of the functioning of immersive
// fullscreen and must not be removed lest that break.
- (CGFloat)_titlebarHeight {
auto* window = base::apple::ObjCCast<NativeWidgetMacNSWindow>(self.window);
remote_cocoa::NativeWidgetNSWindowBridge* bridge = window.bridge;
if (!bridge) {
return [super _titlebarHeight];
}
// The titlebar will be the same size during non-fullscreen and immersive
// fullscreen. During content fullscreen the toolbar is hidden and the
// titlebar will be smaller default height.
if (!_inFullScreen || bridge->ShouldUseCustomTitlebarHeightForFullscreen()) {
bool overrideTitlebarHeight = false;
float titlebarHeight = 0;
bridge->host()->GetWindowFrameTitlebarHeight(&overrideTitlebarHeight,
&titlebarHeight);
if (overrideTitlebarHeight) {
return titlebarHeight;
}
}
return [super _titlebarHeight];
}
- (CGFloat)_minXTitlebarWidgetInset {
if (@available(macOS 26, *)) {
// On macOS 26, position the leading window widget the same distance from
// the leading edge of the window as it is from the top of the window. That
// way the window corner can be adjusted to make the widget concentric.
return 13.0;
}
return [super _minXTitlebarWidgetInset];
}
// Override -_getCachedWindowCornerRadius rather than -_cornerRadius because the
// latter does fullscreen checks before calling down to the former, and other
// methods (-_topCornerSize, -_bottomCornerSize) also depend on
// _getCachedWindowCornerRadius.
- (CGFloat)_getCachedWindowCornerRadius {
if (@available(macOS 26, *)) {
return 13.0 /* widget position from top and left */ +
7.0 /* widget radius */;
}
// Don't mess with the window radius before macOS 26, as concentricity was not
// a design element for those releases.
return [super _getCachedWindowCornerRadius];
}
- (void)setStyleMask:(NSUInteger)styleMask {
_inFullScreen = (styleMask & NSWindowStyleMaskFullScreen) != 0;
[super setStyleMask:styleMask];
}
- (BOOL)_shouldCenterTrafficLights {
return YES;
}
- (void)setButtonRevealAmount:(double)amount {
// Don't override the reveal amount sent to `super`. `-[NSThemeFrame
// setButtonRevealAmount:]` performs layout operations in addition to
// adjusting the visibility of the traffic lights. The layout changes are
// desired and should be left intact.
[super setButtonRevealAmount:amount];
if (amount == 1.0) {
return;
}
[self maybeShowTrafficLights];
}
- (void)setAlwaysShowTrafficLights:(BOOL)alwaysShow {
_alwaysShowTrafficLights = alwaysShow;
[self maybeShowTrafficLights];
}
- (void)maybeShowTrafficLights {
if (!_alwaysShowTrafficLights) {
return;
}
NSWindow* window = [self window];
[[window standardWindowButton:NSWindowCloseButton] setAlphaValue:1.0];
[[window standardWindowButton:NSWindowMiniaturizeButton] setAlphaValue:1.0];
[[window standardWindowButton:NSWindowZoomButton] setAlphaValue:1.0];
}
@end
@implementation BrowserNativeWidgetWindow
@synthesize thinTitlebarViewController = _thinTitlebarViewController;
// NSWindow (PrivateAPI) overrides.
+ (Class)frameViewClassForStyleMask:(NSUInteger)windowStyle {
// - NSThemeFrame and its subclasses will be nil if it's missing at runtime.
if ([BrowserWindowFrame class])
return [BrowserWindowFrame class];
return [super frameViewClassForStyleMask:windowStyle];
}
- (instancetype)initWithContentRect:(NSRect)contentRect
styleMask:(NSUInteger)windowStyle
backing:(NSBackingStoreType)bufferingType
defer:(BOOL)deferCreation {
if ((self = [super initWithContentRect:contentRect
styleMask:windowStyle
backing:bufferingType
defer:deferCreation])) {
[NSNotificationCenter.defaultCenter
addObserver:self
selector:@selector(windowDidBecomeKey:)
name:NSWindowDidBecomeKeyNotification
object:nil];
if (base::mac::MacOSMajorVersion() >= 13) {
_thinTitlebarViewController =
[[NSTitlebarAccessoryViewController alloc] init];
NSView* thinView = [[NSView alloc] init];
thinView.wantsLayer = YES;
thinView.layer.backgroundColor = NSColor.blackColor.CGColor;
_thinTitlebarViewController.view = thinView;
_thinTitlebarViewController.layoutAttribute = NSLayoutAttributeBottom;
_thinTitlebarViewController.fullScreenMinHeight = kThinControllerHeight;
_thinTitlebarViewController.hidden = YES;
[self addTitlebarAccessoryViewController:_thinTitlebarViewController];
}
}
return self;
}
- (void)dealloc {
[NSNotificationCenter.defaultCenter removeObserver:self];
}
- (void)windowDidBecomeKey:(NSNotification*)notify {
// NSToolbarFullScreenWindow should never become the key window, otherwise
// the browser window will appear inactive. Activate the browser window
// when this happens.
NSWindow* toolbarWindow = notify.object;
if (toolbarWindow.parentWindow == self &&
remote_cocoa::IsNSToolbarFullScreenWindow(toolbarWindow)) {
[self makeKeyAndOrderFront:nil];
}
}
// The base implementation returns YES if the window's frame view is a custom
// class, which causes undesirable changes in behavior. AppKit NSWindow
// subclasses are known to override it and return NO.
- (BOOL)_usesCustomDrawing {
return NO;
}
// Handle "Move focus to the window toolbar" configured in System Preferences ->
// Keyboard -> Shortcuts -> Keyboard. Usually Ctrl+F5. The argument (|unknown|)
// tends to just be nil.
- (void)_handleFocusToolbarHotKey:(id)unknown {
remote_cocoa::NativeWidgetNSWindowBridge* bridge = [self bridge];
if (bridge)
bridge->host()->OnFocusWindowToolbar();
}
- (void)setAlwaysShowTrafficLights:(BOOL)alwaysShow {
[base::apple::ObjCCastStrict<BrowserWindowFrame>(self.contentView.superview)
setAlwaysShowTrafficLights:alwaysShow];
}
@end
|