fix: clean up implementations of titleBarStyle (#27489)

* Rewrite titleBarStyle impls with WindowButtonsView

* Remove fullscreenWindowTitle option

* Make buttons show correctly under RTL

* Fix docs about traffic lights position

* Fix test on fullscreen resizable

* Fix button states with closabe/minimizable/fullscreenable

* Fix typo

* Deprecate the fullscreenWindowTitle option
This commit is contained in:
Cheng Zhao 2021-01-31 08:15:10 +09:00 committed by GitHub
parent 6edf6c6a95
commit 8bf66f8974
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 262 additions and 304 deletions

View file

@ -280,8 +280,8 @@ class NativeWindow : public base::SupportsUserData,
void NotifyWindowRotateGesture(float rotation);
void NotifyWindowSheetBegin();
void NotifyWindowSheetEnd();
void NotifyWindowEnterFullScreen();
void NotifyWindowLeaveFullScreen();
virtual void NotifyWindowEnterFullScreen();
virtual void NotifyWindowLeaveFullScreen();
void NotifyWindowEnterHtmlFullScreen();
void NotifyWindowLeaveHtmlFullScreen();
void NotifyWindowAlwaysOnTopChanged();

View file

@ -21,7 +21,7 @@
@class ElectronNSWindowDelegate;
@class ElectronPreviewItem;
@class ElectronTouchBar;
@class CustomWindowButtonView;
@class WindowButtonsView;
namespace electron {
@ -139,6 +139,11 @@ class NativeWindowMac : public NativeWindow, public ui::NativeThemeObserver {
void CloseFilePreview() override;
gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) const override;
gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) const override;
void NotifyWindowEnterFullScreen() override;
void NotifyWindowLeaveFullScreen() override;
void NotifyWindowWillEnterFullScreen();
void NotifyWindowWillLeaveFullScreen();
// Cleanup observers when window is getting closed. Note that the destructor
// can be called much later after window gets closed, so we should not do
@ -153,8 +158,6 @@ class NativeWindowMac : public NativeWindow, public ui::NativeThemeObserver {
void SetCollectionBehavior(bool on, NSUInteger flag);
void SetWindowLevel(int level);
void SetExitingFullScreen(bool flag);
enum class VisualEffectState {
kFollowWindow,
kActive,
@ -172,7 +175,6 @@ class NativeWindowMac : public NativeWindow, public ui::NativeThemeObserver {
ElectronPreviewItem* preview_item() const { return preview_item_.get(); }
ElectronTouchBar* touch_bar() const { return touch_bar_.get(); }
bool zoom_to_page_width() const { return zoom_to_page_width_; }
bool fullscreen_window_title() const { return fullscreen_window_title_; }
bool always_simple_fullscreen() const { return always_simple_fullscreen_; }
bool exiting_fullscreen() const { return exiting_fullscreen_; }
@ -186,9 +188,10 @@ class NativeWindowMac : public NativeWindow, public ui::NativeThemeObserver {
private:
// Add custom layers to the content view.
void AddContentViewLayers(bool minimizable, bool closable);
void AddContentViewLayers();
void InternalSetWindowButtonVisibility(bool visible);
void InternalSetStandardButtonsVisibility(bool visible);
void InternalSetParentWindow(NativeWindow* parent, bool attach);
void SetForwardMouseMessages(bool forward);
@ -197,7 +200,7 @@ class NativeWindowMac : public NativeWindow, public ui::NativeThemeObserver {
base::scoped_nsobject<ElectronNSWindowDelegate> window_delegate_;
base::scoped_nsobject<ElectronPreviewItem> preview_item_;
base::scoped_nsobject<ElectronTouchBar> touch_bar_;
base::scoped_nsobject<CustomWindowButtonView> buttons_view_;
base::scoped_nsobject<WindowButtonsView> buttons_view_;
// Event monitor for scroll wheel event.
id wheel_event_monitor_;
@ -213,7 +216,6 @@ class NativeWindowMac : public NativeWindow, public ui::NativeThemeObserver {
bool is_kiosk_ = false;
bool was_fullscreen_ = false;
bool zoom_to_page_width_ = false;
bool fullscreen_window_title_ = false;
bool resizable_ = true;
bool exiting_fullscreen_ = false;
base::Optional<gfx::Point> traffic_light_position_;

View file

@ -29,6 +29,7 @@
#include "shell/browser/ui/cocoa/electron_preview_item.h"
#include "shell/browser/ui/cocoa/electron_touch_bar.h"
#include "shell/browser/ui/cocoa/root_view_mac.h"
#include "shell/browser/ui/cocoa/window_buttons_view.h"
#include "shell/browser/ui/inspectable_web_contents.h"
#include "shell/browser/ui/inspectable_web_contents_view.h"
#include "shell/browser/window_list.h"
@ -119,106 +120,6 @@
@end
// Custom Quit, Minimize and Full Screen button container for frameless
// windows.
@interface CustomWindowButtonView : NSView {
@private
BOOL mouse_inside_;
gfx::Point margin_;
}
- (id)initWithMargin:(const base::Optional<gfx::Point>&)margin;
- (void)setMargin:(const base::Optional<gfx::Point>&)margin;
@end
@implementation CustomWindowButtonView
- (id)initWithMargin:(const base::Optional<gfx::Point>&)margin {
self = [super initWithFrame:NSZeroRect];
[self setMargin:margin];
NSButton* close_button =
[NSWindow standardWindowButton:NSWindowCloseButton
forStyleMask:NSWindowStyleMaskTitled];
[close_button setTag:1];
NSButton* miniaturize_button =
[NSWindow standardWindowButton:NSWindowMiniaturizeButton
forStyleMask:NSWindowStyleMaskTitled];
[miniaturize_button setTag:2];
CGFloat x = 0;
const CGFloat space_between = 20;
[close_button setFrameOrigin:NSMakePoint(x, 0)];
x += space_between;
[self addSubview:close_button];
[miniaturize_button setFrameOrigin:NSMakePoint(x, 0)];
x += space_between;
[self addSubview:miniaturize_button];
const auto last_button_frame = miniaturize_button.frame;
[self setFrameSize:NSMakeSize(last_button_frame.origin.x +
last_button_frame.size.width,
last_button_frame.size.height)];
mouse_inside_ = NO;
[self setNeedsDisplayForButtons];
return self;
}
- (void)setMargin:(const base::Optional<gfx::Point>&)margin {
margin_ = margin.value_or(gfx::Point(7, 3));
}
- (void)viewDidMoveToWindow {
if (!self.window) {
return;
}
// Stay in upper left corner.
[self setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
[self setFrameOrigin:NSMakePoint(margin_.x(), self.window.frame.size.height -
self.frame.size.height -
margin_.y())];
}
- (BOOL)_mouseInGroup:(NSButton*)button {
return mouse_inside_;
}
- (void)updateTrackingAreas {
auto tracking_area = [[[NSTrackingArea alloc]
initWithRect:NSZeroRect
options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways |
NSTrackingInVisibleRect
owner:self
userInfo:nil] autorelease];
[self addTrackingArea:tracking_area];
}
- (void)mouseEntered:(NSEvent*)event {
[super mouseEntered:event];
mouse_inside_ = YES;
[self setNeedsDisplayForButtons];
}
- (void)mouseExited:(NSEvent*)event {
[super mouseExited:event];
mouse_inside_ = NO;
[self setNeedsDisplayForButtons];
}
- (void)setNeedsDisplayForButtons {
for (NSView* subview in self.subviews) {
[subview setHidden:!mouse_inside_];
[subview setNeedsDisplay:YES];
}
}
@end
@interface ElectronProgressBar : NSProgressIndicator
@end
@ -370,11 +271,17 @@ NativeWindowMac::NativeWindowMac(const gin_helper::Dictionary& options,
options.Get(options::kResizable, &resizable_);
options.Get(options::kTitleBarStyle, &title_bar_style_);
options.Get(options::kZoomToPageWidth, &zoom_to_page_width_);
options.Get(options::kFullscreenWindowTitle, &fullscreen_window_title_);
options.Get(options::kSimpleFullScreen, &always_simple_fullscreen_);
options.GetOptional(options::kTrafficLightPosition, &traffic_light_position_);
options.Get(options::kVisualEffectState, &visual_effect_state_);
if (options.Has(options::kFullscreenWindowTitle)) {
EmitWarning(node::Environment::GetCurrent(v8::Isolate::GetCurrent()),
"\"fullscreenWindowTitle\" option has been deprecated and is "
"no-op now.",
"electron");
}
bool minimizable = true;
options.Get(options::kMinimizable, &minimizable);
@ -457,6 +364,8 @@ NativeWindowMac::NativeWindowMac(const gin_helper::Dictionary& options,
[window_ setTitleVisibility:NSWindowTitleHidden];
// Remove non-transparent corners, see http://git.io/vfonD.
[window_ setOpaque:NO];
// Hide the window buttons.
InternalSetStandardButtonsVisibility(false);
}
// Create a tab only if tabbing identifier is specified and window has
@ -471,14 +380,6 @@ NativeWindowMac::NativeWindowMac(const gin_helper::Dictionary& options,
}
}
// Hide the title bar.
if (title_bar_style_ == TitleBarStyle::kHiddenInset) {
base::scoped_nsobject<NSToolbar> toolbar(
[[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]);
[toolbar setShowsBaselineSeparator:NO];
[window_ setToolbar:toolbar];
}
// Resize to content bounds.
bool use_content_size = false;
options.Get(options::kUseContentSize, &use_content_size);
@ -527,7 +428,7 @@ NativeWindowMac::NativeWindowMac(const gin_helper::Dictionary& options,
// Default content view.
SetContentView(new views::View());
AddContentViewLayers(minimizable, closable);
AddContentViewLayers();
original_frame_ = [window_ frame];
original_level_ = [window_ level];
@ -830,6 +731,8 @@ bool NativeWindowMac::IsMovable() {
void NativeWindowMac::SetMinimizable(bool minimizable) {
SetStyleMask(minimizable, NSMiniaturizableWindowMask);
if (buttons_view_)
[[buttons_view_ viewWithTag:1] setEnabled:minimizable];
}
bool NativeWindowMac::IsMinimizable() {
@ -851,6 +754,8 @@ void NativeWindowMac::SetFullScreenable(bool fullscreenable) {
// On EL Capitan this flag is required to hide fullscreen button.
SetCollectionBehavior(!fullscreenable,
NSWindowCollectionBehaviorFullScreenAuxiliary);
if (buttons_view_)
[[buttons_view_ viewWithTag:2] setEnabled:fullscreenable];
}
bool NativeWindowMac::IsFullScreenable() {
@ -860,6 +765,8 @@ bool NativeWindowMac::IsFullScreenable() {
void NativeWindowMac::SetClosable(bool closable) {
SetStyleMask(closable, NSWindowStyleMaskClosable);
if (buttons_view_)
[[buttons_view_ viewWithTag:0] setEnabled:closable];
}
bool NativeWindowMac::IsClosable() {
@ -940,9 +847,6 @@ void NativeWindowMac::Invalidate() {
void NativeWindowMac::SetTitle(const std::string& title) {
[window_ setTitle:base::SysUTF8ToNSString(title)];
if (title_bar_style_ == TitleBarStyle::kHidden) {
RedrawTrafficLights();
}
}
std::string NativeWindowMac::GetTitle() {
@ -1004,14 +908,7 @@ void NativeWindowMac::SetSimpleFullScreen(bool simple_fullscreen) {
window.level = NSPopUpMenuWindowLevel;
}
if (!fullscreen_window_title()) {
// Hide the titlebar
SetStyleMask(false, NSWindowStyleMaskTitled);
// Resize the window to accommodate the _entire_ screen size
fullscreenFrame.size.height -=
[[[NSApplication sharedApplication] mainMenu] menuBarHeight];
} else if (!window_button_visibility_.has_value()) {
if (!window_button_visibility_.has_value()) {
// Lets keep previous behaviour - hide window controls in titled
// fullscreen mode when not specified otherwise.
InternalSetWindowButtonVisibility(false);
@ -1027,11 +924,6 @@ void NativeWindowMac::SetSimpleFullScreen(bool simple_fullscreen) {
} else if (!simple_fullscreen && is_simple_fullscreen_) {
is_simple_fullscreen_ = false;
if (!fullscreen_window_title()) {
// Restore the titlebar
SetStyleMask(true, NSWindowStyleMaskTitled);
}
// Restore default window controls visibility state.
if (!window_button_visibility_.has_value()) {
bool visibility;
@ -1450,9 +1342,7 @@ bool NativeWindowMac::GetWindowButtonVisibility() const {
void NativeWindowMac::SetTrafficLightPosition(
base::Optional<gfx::Point> position) {
traffic_light_position_ = std::move(position);
if (title_bar_style_ == TitleBarStyle::kHidden) {
RedrawTrafficLights();
} else if (title_bar_style_ == TitleBarStyle::kCustomButtonsOnHover) {
if (buttons_view_) {
[buttons_view_ setMargin:position];
[buttons_view_ viewDidMoveToWindow];
}
@ -1463,64 +1353,8 @@ base::Optional<gfx::Point> NativeWindowMac::GetTrafficLightPosition() const {
}
void NativeWindowMac::RedrawTrafficLights() {
// Ensure maximizable options retain pre-existing state.
SetMaximizable(maximizable_);
// Changing system titlebar is only allowed for "hidden" titleBarStyle.
if (!traffic_light_position_ || title_bar_style_ != TitleBarStyle::kHidden)
return;
if (IsFullscreen())
return;
NSWindow* window = window_;
NSButton* close = [window standardWindowButton:NSWindowCloseButton];
NSButton* miniaturize =
[window standardWindowButton:NSWindowMiniaturizeButton];
NSButton* zoom = [window standardWindowButton:NSWindowZoomButton];
// Safety check just in case apple changes the view structure in a macOS
// update
DCHECK(close.superview);
DCHECK(close.superview.superview);
if (!close.superview || !close.superview.superview)
return;
NSView* titleBarContainerView = close.superview.superview;
// Hide the container when exiting fullscreen, otherwise traffic light buttons
// jump
if (exiting_fullscreen_) {
[titleBarContainerView setHidden:YES];
return;
}
[titleBarContainerView setHidden:NO];
CGFloat buttonHeight = [close frame].size.height;
CGFloat titleBarFrameHeight = buttonHeight + traffic_light_position_->y();
CGRect titleBarRect = titleBarContainerView.frame;
CGFloat titleBarWidth = NSWidth(titleBarRect);
titleBarRect.size.height = titleBarFrameHeight;
titleBarRect.origin.y = window.frame.size.height - titleBarFrameHeight;
[titleBarContainerView setFrame:titleBarRect];
BOOL isRTL = [titleBarContainerView userInterfaceLayoutDirection] ==
NSUserInterfaceLayoutDirectionRightToLeft;
NSArray* windowButtons = @[ close, miniaturize, zoom ];
const CGFloat space_between =
[miniaturize frame].origin.x - [close frame].origin.x;
for (NSUInteger i = 0; i < windowButtons.count; i++) {
NSView* view = [windowButtons objectAtIndex:i];
CGRect rect = [view frame];
if (isRTL) {
CGFloat buttonWidth = NSWidth(rect);
// origin is always top-left, even in RTL
rect.origin.x = titleBarWidth - traffic_light_position_->x() +
(i * space_between) - buttonWidth;
} else {
rect.origin.x = traffic_light_position_->x() + (i * space_between);
}
rect.origin.y = (titleBarFrameHeight - rect.size.height) / 2;
[view setFrameOrigin:rect.origin];
}
if (buttons_view_)
[buttons_view_ setNeedsDisplayForButtons];
}
void NativeWindowMac::SetTouchBar(
@ -1642,6 +1476,41 @@ gfx::Rect NativeWindowMac::WindowBoundsToContentBounds(
}
}
void NativeWindowMac::NotifyWindowEnterFullScreen() {
NativeWindow::NotifyWindowEnterFullScreen();
// Restore the window title under fullscreen mode.
if (buttons_view_)
[window_ setTitleVisibility:NSWindowTitleVisible];
RedrawTrafficLights();
}
void NativeWindowMac::NotifyWindowLeaveFullScreen() {
NativeWindow::NotifyWindowLeaveFullScreen();
exiting_fullscreen_ = false;
// Add back buttonsView after leaving fullscreen mode.
if (buttons_view_) {
InternalSetStandardButtonsVisibility(false);
[[window_ contentView] addSubview:buttons_view_];
}
}
void NativeWindowMac::NotifyWindowWillEnterFullScreen() {
// Remove the buttonsView otherwise window buttons won't show under
// fullscreen mode.
if (buttons_view_) {
[buttons_view_ removeFromSuperview];
InternalSetStandardButtonsVisibility(true);
}
}
void NativeWindowMac::NotifyWindowWillLeaveFullScreen() {
// Hide window title after leaving fullscreen.
if (buttons_view_)
[window_ setTitleVisibility:NSWindowTitleHidden];
exiting_fullscreen_ = true;
RedrawTrafficLights();
}
void NativeWindowMac::Cleanup() {
DCHECK(!IsClosed());
ui::NativeTheme::GetInstanceForNativeUi()->RemoveObserver(this);
@ -1663,7 +1532,7 @@ void NativeWindowMac::OverrideNSWindowContentView() {
[container_view_
setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[window_ setContentView:container_view_];
AddContentViewLayers(IsMinimizable(), IsClosable());
AddContentViewLayers();
}
void NativeWindowMac::SetStyleMask(bool on, NSUInteger flag) {
@ -1692,10 +1561,6 @@ void NativeWindowMac::SetCollectionBehavior(bool on, NSUInteger flag) {
SetMaximizable(was_maximizable);
}
void NativeWindowMac::SetExitingFullScreen(bool flag) {
exiting_fullscreen_ = flag;
}
bool NativeWindowMac::CanResize() const {
return resizable_;
}
@ -1710,7 +1575,7 @@ void NativeWindowMac::OnNativeThemeUpdated(ui::NativeTheme* observed_theme) {
base::BindOnce(&NativeWindow::RedrawTrafficLights, GetWeakPtr()));
}
void NativeWindowMac::AddContentViewLayers(bool minimizable, bool closable) {
void NativeWindowMac::AddContentViewLayers() {
// Make sure the bottom corner is rounded for non-modal windows:
// http://crbug.com/396264.
if (!is_modal()) {
@ -1742,46 +1607,39 @@ void NativeWindowMac::AddContentViewLayers(bool minimizable, bool closable) {
[[window_ contentView] viewDidMoveToWindow];
}
// The fullscreen button should always be hidden for frameless window.
[[window_ standardWindowButton:NSWindowFullScreenButton] setHidden:YES];
// Create a custom window buttons view.
if (title_bar_style_ != TitleBarStyle::kNormal) {
buttons_view_.reset(
[[WindowButtonsView alloc] initWithMargin:traffic_light_position_]);
if (title_bar_style_ == TitleBarStyle::kCustomButtonsOnHover)
[buttons_view_ setShowOnHover:YES];
if (title_bar_style_ == TitleBarStyle::kHiddenInset &&
!traffic_light_position_)
[buttons_view_ setMargin:gfx::Point(12, 11)];
// Create a custom window buttons view for kCustomButtonsOnHover.
if (title_bar_style_ == TitleBarStyle::kCustomButtonsOnHover) {
buttons_view_.reset([[CustomWindowButtonView alloc]
initWithMargin:traffic_light_position_]);
if (!minimizable)
[[buttons_view_ viewWithTag:2] removeFromSuperview];
if (!closable)
[[buttons_view_ viewWithTag:1] removeFromSuperview];
if (!IsClosable())
[[buttons_view_ viewWithTag:0] setEnabled:NO];
if (!IsMinimizable())
[[buttons_view_ viewWithTag:1] setEnabled:NO];
if (!IsFullScreenable())
[[buttons_view_ viewWithTag:2] setEnabled:NO];
[[window_ contentView] addSubview:buttons_view_];
}
// Hide the window buttons except for kHidden and kHiddenInset.
if (title_bar_style_ == TitleBarStyle::kNormal ||
title_bar_style_ == TitleBarStyle::kCustomButtonsOnHover) {
[[window_ standardWindowButton:NSWindowZoomButton] setHidden:YES];
[[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
[[window_ standardWindowButton:NSWindowCloseButton] setHidden:YES];
// Some third-party macOS utilities check the zoom button's enabled state
// to determine whether to show custom UI on hover, so we disable it here
// to prevent them from doing so in a frameless app window.
SetMaximizable(false);
}
}
}
void NativeWindowMac::InternalSetWindowButtonVisibility(bool visible) {
if (buttons_view_) {
if (buttons_view_)
[buttons_view_ setHidden:!visible];
} else {
[[window_ standardWindowButton:NSWindowCloseButton] setHidden:!visible];
[[window_ standardWindowButton:NSWindowMiniaturizeButton]
setHidden:!visible];
[[window_ standardWindowButton:NSWindowZoomButton] setHidden:!visible];
}
else
InternalSetStandardButtonsVisibility(visible);
}
void NativeWindowMac::InternalSetStandardButtonsVisibility(bool visible) {
[[window_ standardWindowButton:NSWindowCloseButton] setHidden:!visible];
[[window_ standardWindowButton:NSWindowMiniaturizeButton] setHidden:!visible];
[[window_ standardWindowButton:NSWindowZoomButton] setHidden:!visible];
}
void NativeWindowMac::InternalSetParentWindow(NativeWindow* parent,

View file

@ -91,14 +91,17 @@ using TitleBarStyle = electron::NativeWindowMac::TitleBarStyle;
- (void)windowDidBecomeMain:(NSNotification*)notification {
shell_->NotifyWindowFocus();
shell_->RedrawTrafficLights();
}
- (void)windowDidResignMain:(NSNotification*)notification {
shell_->NotifyWindowBlur();
shell_->RedrawTrafficLights();
}
- (void)windowDidBecomeKey:(NSNotification*)notification {
shell_->NotifyWindowIsKeyChanged(true);
shell_->RedrawTrafficLights();
}
- (void)windowDidResignKey:(NSNotification*)notification {
@ -110,6 +113,7 @@ using TitleBarStyle = electron::NativeWindowMac::TitleBarStyle;
return;
shell_->NotifyWindowIsKeyChanged(false);
shell_->RedrawTrafficLights();
}
- (NSSize)windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize {
@ -151,9 +155,6 @@ using TitleBarStyle = electron::NativeWindowMac::TitleBarStyle;
- (void)windowDidResize:(NSNotification*)notification {
[super windowDidResize:notification];
shell_->NotifyWindowResize();
if (shell_->title_bar_style() == TitleBarStyle::kHidden) {
shell_->RedrawTrafficLights();
}
}
- (void)windowWillMove:(NSNotification*)notification {
@ -212,75 +213,23 @@ using TitleBarStyle = electron::NativeWindowMac::TitleBarStyle;
}
- (void)windowWillEnterFullScreen:(NSNotification*)notification {
// Setting resizable to true before entering fullscreen
shell_->NotifyWindowWillEnterFullScreen();
// Setting resizable to true before entering fullscreen.
is_resizable_ = shell_->IsResizable();
shell_->SetResizable(true);
// Hide the native toolbar before entering fullscreen, so there is no visual
// artifacts.
if (shell_->title_bar_style() == TitleBarStyle::kHiddenInset) {
NSWindow* window = shell_->GetNativeWindow().GetNativeNSWindow();
[window setToolbar:nil];
}
}
- (void)windowDidEnterFullScreen:(NSNotification*)notification {
shell_->NotifyWindowEnterFullScreen();
// For frameless window we don't show set title for normal mode since the
// titlebar is expected to be empty, but after entering fullscreen mode we
// have to set one, because title bar is visible here.
NSWindow* window = shell_->GetNativeWindow().GetNativeNSWindow();
if ((shell_->transparent() || !shell_->has_frame()) &&
// FIXME(zcbenz): Showing titlebar for hiddenInset window is weird under
// fullscreen mode.
// Show title if fullscreen_window_title flag is set
(shell_->title_bar_style() != TitleBarStyle::kHiddenInset ||
shell_->fullscreen_window_title())) {
[window setTitleVisibility:NSWindowTitleVisible];
}
// Restore the native toolbar immediately after entering fullscreen, if we
// do this before leaving fullscreen, traffic light buttons will be jumping.
if (shell_->title_bar_style() == TitleBarStyle::kHiddenInset) {
base::scoped_nsobject<NSToolbar> toolbar(
[[NSToolbar alloc] initWithIdentifier:@"titlebarStylingToolbar"]);
[toolbar setShowsBaselineSeparator:NO];
[window setToolbar:toolbar];
// Set window style to hide the toolbar, otherwise the toolbar will show
// in fullscreen mode.
[window setTitlebarAppearsTransparent:NO];
shell_->SetStyleMask(true, NSWindowStyleMaskFullSizeContentView);
}
}
- (void)windowWillExitFullScreen:(NSNotification*)notification {
// Restore the titlebar visibility.
NSWindow* window = shell_->GetNativeWindow().GetNativeNSWindow();
if ((shell_->transparent() || !shell_->has_frame()) &&
(shell_->title_bar_style() != TitleBarStyle::kHiddenInset ||
shell_->fullscreen_window_title())) {
[window setTitleVisibility:NSWindowTitleHidden];
}
// Turn off the style for toolbar.
if (shell_->title_bar_style() == TitleBarStyle::kHiddenInset) {
shell_->SetStyleMask(false, NSWindowStyleMaskFullSizeContentView);
[window setTitlebarAppearsTransparent:YES];
}
shell_->SetExitingFullScreen(true);
if (shell_->title_bar_style() == TitleBarStyle::kHidden) {
shell_->RedrawTrafficLights();
}
shell_->NotifyWindowWillLeaveFullScreen();
}
- (void)windowDidExitFullScreen:(NSNotification*)notification {
shell_->SetResizable(is_resizable_);
shell_->NotifyWindowLeaveFullScreen();
shell_->SetExitingFullScreen(false);
if (shell_->title_bar_style() == TitleBarStyle::kHidden) {
shell_->RedrawTrafficLights();
}
}
- (void)windowWillClose:(NSNotification*)notification {

View file

@ -0,0 +1,31 @@
// Copyright (c) 2021 Microsoft, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef SHELL_BROWSER_UI_COCOA_WINDOW_BUTTONS_VIEW_H_
#define SHELL_BROWSER_UI_COCOA_WINDOW_BUTTONS_VIEW_H_
#import <Cocoa/Cocoa.h>
#include "base/mac/scoped_nsobject.h"
#include "base/optional.h"
#include "ui/gfx/geometry/point.h"
// Custom Quit, Minimize and Full Screen button container for frameless
// windows.
@interface WindowButtonsView : NSView {
@private
BOOL mouse_inside_;
BOOL show_on_hover_;
BOOL is_rtl_;
gfx::Point margin_;
base::scoped_nsobject<NSTrackingArea> tracking_area_;
}
- (id)initWithMargin:(const base::Optional<gfx::Point>&)margin;
- (void)setMargin:(const base::Optional<gfx::Point>&)margin;
- (void)setShowOnHover:(BOOL)yes;
- (void)setNeedsDisplayForButtons;
@end
#endif // SHELL_BROWSER_UI_COCOA_WINDOW_BUTTONS_VIEW_H_

View file

@ -0,0 +1,119 @@
// Copyright (c) 2021 Microsoft, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "shell/browser/ui/cocoa/window_buttons_view.h"
#include "base/i18n/rtl.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "ui/gfx/mac/coordinate_conversion.h"
namespace {
const CGFloat kButtonPadding = 20.;
const NSWindowButton kButtonTypes[] = {
NSWindowCloseButton,
NSWindowMiniaturizeButton,
NSWindowZoomButton,
};
} // namespace
@implementation WindowButtonsView
- (id)initWithMargin:(const base::Optional<gfx::Point>&)margin {
self = [super initWithFrame:NSZeroRect];
[self setMargin:margin];
mouse_inside_ = false;
show_on_hover_ = false;
is_rtl_ = base::i18n::IsRTL();
for (size_t i = 0; i < base::size(kButtonTypes); ++i) {
NSButton* button = [NSWindow standardWindowButton:kButtonTypes[i]
forStyleMask:NSWindowStyleMaskTitled];
[button setTag:i];
int left_index = is_rtl_ ? base::size(kButtonTypes) - i - 1 : i;
[button setFrameOrigin:NSMakePoint(left_index * kButtonPadding, 0)];
[self addSubview:button];
}
NSView* last_button =
is_rtl_ ? [[self subviews] firstObject] : [[self subviews] lastObject];
[self setFrameSize:NSMakeSize(last_button.frame.origin.x +
last_button.frame.size.width,
last_button.frame.size.height)];
[self setNeedsDisplayForButtons];
return self;
}
- (void)setMargin:(const base::Optional<gfx::Point>&)margin {
margin_ = margin.value_or(gfx::Point(7, 3));
}
- (void)setShowOnHover:(BOOL)yes {
show_on_hover_ = yes;
[self setNeedsDisplayForButtons];
}
- (void)setNeedsDisplayForButtons {
for (NSView* subview in self.subviews) {
[subview setHidden:(show_on_hover_ && !mouse_inside_)];
[subview setNeedsDisplay:YES];
}
}
- (void)removeFromSuperview {
[super removeFromSuperview];
mouse_inside_ = NO;
}
- (void)viewDidMoveToWindow {
// Stay in upper left corner.
CGFloat y =
self.superview.frame.size.height - self.frame.size.height - margin_.y();
if (is_rtl_) {
CGFloat x =
self.superview.frame.size.width - self.frame.size.width - margin_.x();
[self setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
[self setFrameOrigin:NSMakePoint(x, y)];
} else {
[self setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
[self setFrameOrigin:NSMakePoint(margin_.x(), y)];
}
}
- (BOOL)_mouseInGroup:(NSButton*)button {
return mouse_inside_;
}
- (void)updateTrackingAreas {
[super updateTrackingAreas];
if (tracking_area_)
[self removeTrackingArea:tracking_area_.get()];
tracking_area_.reset([[NSTrackingArea alloc]
initWithRect:NSZeroRect
options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways |
NSTrackingInVisibleRect
owner:self
userInfo:nil]);
[self addTrackingArea:tracking_area_.get()];
}
- (void)mouseEntered:(NSEvent*)event {
[super mouseEntered:event];
mouse_inside_ = YES;
[self setNeedsDisplayForButtons];
}
- (void)mouseExited:(NSEvent*)event {
[super mouseExited:event];
mouse_inside_ = NO;
[self setNeedsDisplayForButtons];
}
@end