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

@ -222,16 +222,14 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
the top left.
* `hiddenInset` - Results in a hidden title bar with an alternative look
where the traffic light buttons are slightly more inset from the window edge.
* `customButtonsOnHover` Boolean (optional) - Draw custom close,
and minimize buttons on macOS frameless windows. These buttons will not display
unless hovered over in the top left of the window. These custom buttons prevent
issues with mouse events that occur with the standard window toolbar buttons.
**Note:** This option is currently experimental.
* `customButtonsOnHover` - Results in a hidden title bar and a full size
content window, the traffic light buttons will display when being hovered
over in the top left of the window. **Note:** This option is currently
experimental.
* `trafficLightPosition` [Point](structures/point.md) (optional) - Set a
custom position for the traffic light buttons. Can only be used with
`titleBarStyle` set to `hidden` or `customButtonsOnHover`.
* `fullscreenWindowTitle` Boolean (optional) - Shows the title in the
title bar in full screen mode on macOS for all `titleBarStyle` options.
custom position for the traffic light buttons in frameless windows.
* `fullscreenWindowTitle` Boolean (optional) _Deprecated_ - Shows the title in
the title bar in full screen mode on macOS for `hiddenInset` titleBarStyle.
Default is `false`.
* `thickFrame` Boolean (optional) - Use `WS_THICKFRAME` style for frameless windows on
Windows, which adds standard window frame. Setting it to `false` will remove
@ -1740,13 +1738,12 @@ deprecated and will be removed in an upcoming version of macOS.
* `position` [Point](structures/point.md)
Set a custom position for the traffic light buttons. Can only be used with
`titleBarStyle` set to `hidden` or `customButtonsOnHover`.
Set a custom position for the traffic light buttons in frameless window.
#### `win.getTrafficLightPosition()` _macOS_
Returns `Point` - The current position for the traffic light buttons. Can only
be used with `titleBarStyle` set to `hidden` or `customButtonsOnHover`.
Returns `Point` - The custom position for the traffic light buttons in
frameless window.
#### `win.setTouchBar(touchBar)` _macOS_

View file

@ -180,6 +180,8 @@ filenames = {
"shell/browser/ui/cocoa/root_view_mac.mm",
"shell/browser/ui/cocoa/views_delegate_mac.h",
"shell/browser/ui/cocoa/views_delegate_mac.mm",
"shell/browser/ui/cocoa/window_buttons_view.h",
"shell/browser/ui/cocoa/window_buttons_view.mm",
"shell/browser/ui/drag_util_mac.mm",
"shell/browser/ui/file_dialog_mac.mm",
"shell/browser/ui/inspectable_web_contents_view_mac.h",

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