diff --git a/filenames.gni b/filenames.gni index ce70e310412f..5714fc520c07 100644 --- a/filenames.gni +++ b/filenames.gni @@ -180,8 +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/cocoa/window_buttons_proxy.h", + "shell/browser/ui/cocoa/window_buttons_proxy.mm", "shell/browser/ui/drag_util_mac.mm", "shell/browser/ui/file_dialog_mac.mm", "shell/browser/ui/inspectable_web_contents_view_mac.h", diff --git a/shell/browser/native_window_mac.h b/shell/browser/native_window_mac.h index 343acd4adbe6..e9adf8acff0b 100644 --- a/shell/browser/native_window_mac.h +++ b/shell/browser/native_window_mac.h @@ -22,7 +22,7 @@ @class ElectronNSWindowDelegate; @class ElectronPreviewItem; @class ElectronTouchBar; -@class WindowButtonsView; +@class WindowButtonsProxy; namespace electron { @@ -156,9 +156,6 @@ class NativeWindowMac : public NativeWindow, void NotifyWindowWillEnterFullScreen(); void NotifyWindowWillLeaveFullScreen(); - // Ensure the buttons view are always floated on the top. - void ReorderButtonsView(); - // 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 // cleanup in destructor. @@ -215,7 +212,6 @@ class NativeWindowMac : public NativeWindow, void AddContentViewLayers(); void InternalSetWindowButtonVisibility(bool visible); - void InternalSetStandardButtonsVisibility(bool visible); void InternalSetParentWindow(NativeWindow* parent, bool attach); void SetForwardMouseMessages(bool forward); @@ -224,7 +220,6 @@ class NativeWindowMac : public NativeWindow, base::scoped_nsobject window_delegate_; base::scoped_nsobject preview_item_; base::scoped_nsobject touch_bar_; - base::scoped_nsobject buttons_view_; // Event monitor for scroll wheel event. id wheel_event_monitor_; @@ -263,6 +258,9 @@ class NativeWindowMac : public NativeWindow, // setWindowButtonVisibility(). absl::optional window_button_visibility_; + // Controls the position and visibility of window buttons. + base::scoped_nsobject buttons_proxy_; + // Maximizable window state; necessary for persistence through redraws. bool maximizable_ = true; diff --git a/shell/browser/native_window_mac.mm b/shell/browser/native_window_mac.mm index fbedeb287643..43891c73c939 100644 --- a/shell/browser/native_window_mac.mm +++ b/shell/browser/native_window_mac.mm @@ -32,7 +32,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/cocoa/window_buttons_proxy.h" #include "shell/browser/ui/inspectable_web_contents.h" #include "shell/browser/ui/inspectable_web_contents_view.h" #include "shell/browser/window_list.h" @@ -381,8 +381,26 @@ 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); + // Show window buttons if titleBarStyle is not "normal". + if (title_bar_style_ == TitleBarStyle::kNormal) { + InternalSetWindowButtonVisibility(false); + } else { + buttons_proxy_.reset([[WindowButtonsProxy alloc] initWithWindow:window_]); + if (traffic_light_position_) { + [buttons_proxy_ setMargin:*traffic_light_position_]; + } else if (title_bar_style_ == TitleBarStyle::kHiddenInset) { + // For macOS >= 11, while this value does not match offical macOS apps + // like Safari or Notes, it matches titleBarStyle's old implementation + // before Electron <= 12. + [buttons_proxy_ setMargin:gfx::Point(12, 11)]; + } + if (title_bar_style_ == TitleBarStyle::kCustomButtonsOnHover) { + [buttons_proxy_ setShowOnHover:YES]; + } else { + // customButtonsOnHover does not show buttons initialiy. + InternalSetWindowButtonVisibility(true); + } + } } // Create a tab only if tabbing identifier is specified and window has @@ -461,9 +479,6 @@ void NativeWindowMac::SetContentView(views::View* view) { set_content_view(view); root_view->AddChildView(content_view()); - if (buttons_view_) - ReorderButtonsView(); - root_view->Layout(); } @@ -806,8 +821,6 @@ bool NativeWindowMac::IsMovable() { void NativeWindowMac::SetMinimizable(bool minimizable) { SetStyleMask(minimizable, NSMiniaturizableWindowMask); - if (buttons_view_) - [[buttons_view_ viewWithTag:1] setEnabled:minimizable]; } bool NativeWindowMac::IsMinimizable() { @@ -829,8 +842,6 @@ 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() { @@ -840,8 +851,6 @@ bool NativeWindowMac::IsFullScreenable() { void NativeWindowMac::SetClosable(bool closable) { SetStyleMask(closable, NSWindowStyleMaskClosable); - if (buttons_view_) - [[buttons_view_ viewWithTag:0] setEnabled:closable]; } bool NativeWindowMac::IsClosable() { @@ -947,6 +956,8 @@ void NativeWindowMac::Invalidate() { void NativeWindowMac::SetTitle(const std::string& title) { [window_ setTitle:base::SysUTF8ToNSString(title)]; + if (buttons_proxy_) + [buttons_proxy_ redraw]; } std::string NativeWindowMac::GetTitle() { @@ -1182,8 +1193,6 @@ void NativeWindowMac::AddBrowserView(NativeBrowserView* view) { } [CATransaction commit]; - - ReorderButtonsView(); } void NativeWindowMac::RemoveBrowserView(NativeBrowserView* view) { @@ -1225,8 +1234,6 @@ void NativeWindowMac::SetTopBrowserView(NativeBrowserView* view) { } [CATransaction commit]; - - ReorderButtonsView(); } void NativeWindowMac::SetParentWindow(NativeWindow* parent) { @@ -1488,25 +1495,26 @@ void NativeWindowMac::SetVibrancy(const std::string& type) { void NativeWindowMac::SetWindowButtonVisibility(bool visible) { window_button_visibility_ = visible; - InternalSetWindowButtonVisibility(visible); + // The visibility of window buttons are managed by |buttons_proxy_| if the + // style is customButtonsOnHover. + if (title_bar_style_ == TitleBarStyle::kCustomButtonsOnHover) + [buttons_proxy_ setVisible:visible]; + else + InternalSetWindowButtonVisibility(visible); NotifyLayoutWindowControlsOverlay(); } bool NativeWindowMac::GetWindowButtonVisibility() const { - if (buttons_view_) - return ![buttons_view_ isHidden]; - else - return ![window_ standardWindowButton:NSWindowZoomButton].hidden || - ![window_ standardWindowButton:NSWindowMiniaturizeButton].hidden || - ![window_ standardWindowButton:NSWindowCloseButton].hidden; + return ![window_ standardWindowButton:NSWindowZoomButton].hidden || + ![window_ standardWindowButton:NSWindowMiniaturizeButton].hidden || + ![window_ standardWindowButton:NSWindowCloseButton].hidden; } void NativeWindowMac::SetTrafficLightPosition( absl::optional position) { traffic_light_position_ = std::move(position); - if (buttons_view_) { - [buttons_view_ setMargin:traffic_light_position_]; - [buttons_view_ viewDidMoveToWindow]; + if (buttons_proxy_) { + [buttons_proxy_ setMargin:traffic_light_position_]; NotifyLayoutWindowControlsOverlay(); } } @@ -1516,8 +1524,8 @@ absl::optional NativeWindowMac::GetTrafficLightPosition() const { } void NativeWindowMac::RedrawTrafficLights() { - if (buttons_view_) - [buttons_view_ setNeedsDisplayForButtons]; + if (buttons_proxy_ && !IsFullscreen()) + [buttons_proxy_ redraw]; } // In simpleFullScreen mode, update the frame for new bounds. @@ -1649,35 +1657,30 @@ gfx::Rect NativeWindowMac::WindowBoundsToContentBounds( void NativeWindowMac::NotifyWindowEnterFullScreen() { NativeWindow::NotifyWindowEnterFullScreen(); // Restore the window title under fullscreen mode. - if (buttons_view_) + if (buttons_proxy_) [window_ setTitleVisibility:NSWindowTitleVisible]; - RedrawTrafficLights(); } void NativeWindowMac::NotifyWindowLeaveFullScreen() { NativeWindow::NotifyWindowLeaveFullScreen(); + // Restore window buttons. + if (buttons_proxy_ && window_button_visibility_.value_or(true)) { + [buttons_proxy_ redraw]; + [buttons_proxy_ setVisible:YES]; + } } void NativeWindowMac::NotifyWindowWillEnterFullScreen() { - // Remove the buttonsView otherwise window buttons won't show under - // fullscreen mode. - if (buttons_view_) { - [buttons_view_ removeFromSuperview]; - InternalSetStandardButtonsVisibility(true); - } - UpdateVibrancyRadii(true); } void NativeWindowMac::NotifyWindowWillLeaveFullScreen() { - // Hide window title and restore buttonsView when leaving fullscreen. - if (buttons_view_) { + if (buttons_proxy_) { + // Hide window title when leaving fullscreen. [window_ setTitleVisibility:NSWindowTitleHidden]; - InternalSetStandardButtonsVisibility(false); - [[window_ contentView] addSubview:buttons_view_]; + // Hide the container otherwise traffic light buttons jump. + [buttons_proxy_ setVisible:NO]; } - - RedrawTrafficLights(); UpdateVibrancyRadii(false); } @@ -1689,13 +1692,6 @@ bool NativeWindowMac::IsActive() const { return is_active_; } -void NativeWindowMac::ReorderButtonsView() { - if (buttons_view_ && !IsFullscreen()) { - [buttons_view_ removeFromSuperview]; - [[window_ contentView] addSubview:buttons_view_]; - } -} - void NativeWindowMac::Cleanup() { DCHECK(!IsClosed()); ui::NativeTheme::GetInstanceForNativeUi()->RemoveObserver(this); @@ -1791,37 +1787,10 @@ void NativeWindowMac::AddContentViewLayers() { (IMP)ViewDidMoveToSuperview, "v@:"); [[window_ contentView] viewDidMoveToWindow]; } - - // 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:[WindowButtonsView hiddenInsetMargin]]; - - 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_]; - } } } void NativeWindowMac::InternalSetWindowButtonVisibility(bool visible) { - if (buttons_view_) - [buttons_view_ 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]; @@ -1861,24 +1830,17 @@ void NativeWindowMac::SetForwardMouseMessages(bool forward) { } gfx::Rect NativeWindowMac::GetWindowControlsOverlayRect() { - gfx::Rect bounding_rect; - if (titlebar_overlay_ && !has_frame() && buttons_view_ && - ![buttons_view_ isHidden]) { - NSRect button_frame = [buttons_view_ frame]; - gfx::Point buttons_view_margin = [buttons_view_ getMargin]; - const int overlay_width = GetContentSize().width() - NSWidth(button_frame) - - buttons_view_margin.x(); - CGFloat overlay_height = - NSHeight(button_frame) + buttons_view_margin.y() * 2; - if (base::i18n::IsRTL()) { - bounding_rect = gfx::Rect(0, 0, overlay_width, overlay_height); - } else { - bounding_rect = - gfx::Rect(button_frame.size.width + buttons_view_margin.x(), 0, - overlay_width, overlay_height); - } + if (titlebar_overlay_ && buttons_proxy_ && + window_button_visibility_.value_or(true)) { + NSRect buttons = [buttons_proxy_ getButtonsContainerBounds]; + gfx::Rect overlay; + overlay.set_width(GetContentSize().width() - NSWidth(buttons)); + overlay.set_height(NSHeight(buttons)); + if (!base::i18n::IsRTL()) + overlay.set_x(NSMaxX(buttons)); + return overlay; } - return bounding_rect; + return gfx::Rect(); } // static diff --git a/shell/browser/ui/cocoa/electron_ns_window_delegate.mm b/shell/browser/ui/cocoa/electron_ns_window_delegate.mm index 9cc74a8b9617..f78b9ccd277d 100644 --- a/shell/browser/ui/cocoa/electron_ns_window_delegate.mm +++ b/shell/browser/ui/cocoa/electron_ns_window_delegate.mm @@ -168,6 +168,7 @@ using FullScreenTransitionState = - (void)windowDidResize:(NSNotification*)notification { [super windowDidResize:notification]; shell_->NotifyWindowResize(); + shell_->RedrawTrafficLights(); } - (void)windowWillMove:(NSNotification*)notification { diff --git a/shell/browser/ui/cocoa/window_buttons_proxy.h b/shell/browser/ui/cocoa/window_buttons_proxy.h new file mode 100644 index 000000000000..5eb048779522 --- /dev/null +++ b/shell/browser/ui/cocoa/window_buttons_proxy.h @@ -0,0 +1,66 @@ +// 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_PROXY_H_ +#define SHELL_BROWSER_UI_COCOA_WINDOW_BUTTONS_PROXY_H_ + +#import + +#include "base/mac/scoped_nsobject.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "ui/gfx/geometry/point.h" + +@class WindowButtonsProxy; + +// A helper view that floats above the window buttons. +@interface ButtonsAreaHoverView : NSView { + @private + WindowButtonsProxy* proxy_; +} +- (id)initWithProxy:(WindowButtonsProxy*)proxy; +@end + +// Manipulating the window buttons. +@interface WindowButtonsProxy : NSObject { + @private + NSWindow* window_; + // The view that contains the window buttons and title. + NSView* titlebar_container_; + + // The window buttons. + NSButton* left_; + NSButton* right_; + NSButton* middle_; + + // Current left-top margin of buttons. + gfx::Point margin_; + // The default left-top margin. + gfx::Point default_margin_; + + // Track mouse moves above window buttons. + BOOL show_on_hover_; + BOOL mouse_inside_; + base::scoped_nsobject tracking_area_; + base::scoped_nsobject hover_view_; +} + +- (id)initWithWindow:(NSWindow*)window; + +- (void)setVisible:(BOOL)visible; +- (BOOL)isVisible; + +// Only show window buttons when mouse moves above them. +- (void)setShowOnHover:(BOOL)yes; + +// Set left-top margin of the window buttons.. +- (void)setMargin:(const absl::optional&)margin; + +// Return the bounds of all 3 buttons, with margin on all sides. +- (NSRect)getButtonsContainerBounds; + +- (void)redraw; +- (void)updateTrackingAreas; +@end + +#endif // SHELL_BROWSER_UI_COCOA_WINDOW_BUTTONS_PROXY_H_ diff --git a/shell/browser/ui/cocoa/window_buttons_proxy.mm b/shell/browser/ui/cocoa/window_buttons_proxy.mm new file mode 100644 index 000000000000..b306a4d73626 --- /dev/null +++ b/shell/browser/ui/cocoa/window_buttons_proxy.mm @@ -0,0 +1,200 @@ +// 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_proxy.h" + +#include "base/i18n/rtl.h" +#include "base/notreached.h" + +@implementation ButtonsAreaHoverView : NSView + +- (id)initWithProxy:(WindowButtonsProxy*)proxy { + if ((self = [super init])) { + proxy_ = proxy; + } + return self; +} + +// Ignore all mouse events. +- (NSView*)hitTest:(NSPoint)aPoint { + return nil; +} + +- (void)updateTrackingAreas { + [proxy_ updateTrackingAreas]; +} + +@end + +@implementation WindowButtonsProxy + +- (id)initWithWindow:(NSWindow*)window { + window_ = window; + show_on_hover_ = NO; + mouse_inside_ = NO; + + // Save the sequence of the buttons for later computation. + if (base::i18n::IsRTL()) { + left_ = [window_ standardWindowButton:NSWindowZoomButton]; + right_ = [window_ standardWindowButton:NSWindowCloseButton]; + } else { + left_ = [window_ standardWindowButton:NSWindowCloseButton]; + right_ = [window_ standardWindowButton:NSWindowZoomButton]; + } + middle_ = [window_ standardWindowButton:NSWindowMiniaturizeButton]; + + // Safety check just in case Apple changes the view structure in a macOS + // upgrade. + if (!left_.superview || !left_.superview.superview) { + NOTREACHED() << "macOS has changed its window buttons view structure."; + titlebar_container_ = nullptr; + return self; + } + titlebar_container_ = left_.superview.superview; + + // Remember the default margin. + margin_ = default_margin_ = [self getCurrentMargin]; + + return self; +} + +- (void)dealloc { + if (hover_view_) + [hover_view_ removeFromSuperview]; + [super dealloc]; +} + +- (void)setVisible:(BOOL)visible { + if (!titlebar_container_) + return; + [titlebar_container_ setHidden:!visible]; +} + +- (BOOL)isVisible { + if (!titlebar_container_) + return YES; + return ![titlebar_container_ isHidden]; +} + +- (void)setShowOnHover:(BOOL)yes { + if (!titlebar_container_) + return; + show_on_hover_ = yes; + // Put a transparent view above the window buttons so we can track mouse + // events when mouse enter/leave the window buttons. + if (show_on_hover_) { + hover_view_.reset([[ButtonsAreaHoverView alloc] initWithProxy:self]); + [hover_view_ setFrame:[self getButtonsBounds]]; + [titlebar_container_ addSubview:hover_view_.get()]; + } else { + [hover_view_ removeFromSuperview]; + hover_view_.reset(); + } + [self updateButtonsVisibility]; +} + +- (void)setMargin:(const absl::optional&)margin { + if (margin) + margin_ = *margin; + else + margin_ = default_margin_; + [self redraw]; +} + +- (NSRect)getButtonsContainerBounds { + return NSInsetRect([self getButtonsBounds], -margin_.x(), -margin_.y()); +} + +- (void)redraw { + if (!titlebar_container_) + return; + + float button_width = NSWidth(left_.frame); + float button_height = NSHeight(left_.frame); + float padding = NSMinX(middle_.frame) - NSMaxX(left_.frame); + float start; + if (base::i18n::IsRTL()) + start = + NSWidth(window_.frame) - 3 * button_width - 2 * padding - margin_.x(); + else + start = margin_.x(); + + NSRect cbounds = titlebar_container_.frame; + cbounds.size.height = button_height + 2 * margin_.y(); + cbounds.origin.y = NSHeight(window_.frame) - NSHeight(cbounds); + [titlebar_container_ setFrame:cbounds]; + + [left_ setFrameOrigin:NSMakePoint(start, margin_.y())]; + start += button_width + padding; + [middle_ setFrameOrigin:NSMakePoint(start, margin_.y())]; + start += button_width + padding; + [right_ setFrameOrigin:NSMakePoint(start, margin_.y())]; + + if (hover_view_) + [hover_view_ setFrame:[self getButtonsBounds]]; +} + +- (void)updateTrackingAreas { + if (tracking_area_) + [hover_view_ removeTrackingArea:tracking_area_.get()]; + tracking_area_.reset([[NSTrackingArea alloc] + initWithRect:NSZeroRect + options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | + NSTrackingInVisibleRect + owner:self + userInfo:nil]); + [hover_view_ addTrackingArea:tracking_area_.get()]; +} + +- (void)mouseEntered:(NSEvent*)event { + mouse_inside_ = YES; + [self updateButtonsVisibility]; +} + +- (void)mouseExited:(NSEvent*)event { + mouse_inside_ = NO; + [self updateButtonsVisibility]; +} + +- (void)updateButtonsVisibility { + NSArray* buttons = @[ + [window_ standardWindowButton:NSWindowCloseButton], + [window_ standardWindowButton:NSWindowMiniaturizeButton], + [window_ standardWindowButton:NSWindowZoomButton], + ]; + // Show buttons when mouse hovers above them. + BOOL hidden = show_on_hover_ && !mouse_inside_; + // Always show buttons under fullscreen. + if ([window_ styleMask] & NSWindowStyleMaskFullScreen) + hidden = NO; + for (NSView* button in buttons) { + [button setHidden:hidden]; + [button setNeedsDisplay:YES]; + } +} + +// Return the bounds of all 3 buttons. +- (NSRect)getButtonsBounds { + return NSMakeRect(NSMinX(left_.frame), NSMinY(left_.frame), + NSMaxX(right_.frame) - NSMinX(left_.frame), + NSHeight(left_.frame)); +} + +// Compute margin from position of current buttons. +- (gfx::Point)getCurrentMargin { + gfx::Point result; + if (!titlebar_container_) + return result; + + result.set_y((NSHeight(titlebar_container_.frame) - NSHeight(left_.frame)) / + 2); + + if (base::i18n::IsRTL()) + result.set_x(NSWidth(window_.frame) - NSMaxX(right_.frame)); + else + result.set_x(NSMinX(left_.frame)); + return result; +} + +@end diff --git a/shell/browser/ui/cocoa/window_buttons_view.h b/shell/browser/ui/cocoa/window_buttons_view.h deleted file mode 100644 index 7786f83c42fe..000000000000 --- a/shell/browser/ui/cocoa/window_buttons_view.h +++ /dev/null @@ -1,34 +0,0 @@ -// 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 - -#include "base/mac/scoped_nsobject.h" -#include "third_party/abseil-cpp/absl/types/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 tracking_area_; -} - -+ (gfx::Point)defaultMargin; -+ (gfx::Point)hiddenInsetMargin; -- (id)initWithMargin:(const absl::optional&)margin; -- (void)setMargin:(const absl::optional&)margin; -- (void)setShowOnHover:(BOOL)yes; -- (void)setNeedsDisplayForButtons; -- (gfx::Point)getMargin; -@end - -#endif // SHELL_BROWSER_UI_COCOA_WINDOW_BUTTONS_VIEW_H_ diff --git a/shell/browser/ui/cocoa/window_buttons_view.mm b/shell/browser/ui/cocoa/window_buttons_view.mm deleted file mode 100644 index 3d52dd7fdcd1..000000000000 --- a/shell/browser/ui/cocoa/window_buttons_view.mm +++ /dev/null @@ -1,138 +0,0 @@ -// 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/cxx17_backports.h" -#include "base/i18n/rtl.h" -#include "base/logging.h" -#include "ui/gfx/mac/coordinate_conversion.h" - -namespace { - -const CGFloat kButtonPadding = 20.; - -const NSWindowButton kButtonTypes[] = { - NSWindowCloseButton, - NSWindowMiniaturizeButton, - NSWindowZoomButton, -}; - -} // namespace - -@implementation WindowButtonsView - -+ (gfx::Point)defaultMargin { - if (@available(macOS 11.0, *)) { - return gfx::Point(7, 6); - } else { - return gfx::Point(7, 3); - } -} - -+ (gfx::Point)hiddenInsetMargin { - // For macOS >= 11, while this value does not match offical macOS apps like - // Safari or Notes, it matches titleBarStyle's old implementation before - // Electron <= 12. - return gfx::Point(12, 11); -} - -- (id)initWithMargin:(const absl::optional&)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 absl::optional&)margin { - margin_ = margin.value_or([WindowButtonsView defaultMargin]); -} - -- (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]; -} - -- (gfx::Point)getMargin { - return margin_; -} - -@end diff --git a/spec-main/api-browser-window-spec.ts b/spec-main/api-browser-window-spec.ts index 82cdff3c5e85..7360f023920f 100644 --- a/spec-main/api-browser-window-spec.ts +++ b/spec-main/api-browser-window-spec.ts @@ -1593,13 +1593,14 @@ describe('BrowserWindow module', () => { expect(w._getWindowButtonVisibility()).to.equal(true); }); - it('changes window button visibility for customButtonsOnHover window', () => { + // Buttons of customButtonsOnHover are always hidden unless hovered. + it('does not change window button visibility for customButtonsOnHover window', () => { const w = new BrowserWindow({ show: false, frame: false, titleBarStyle: 'customButtonsOnHover' }); - expect(w._getWindowButtonVisibility()).to.equal(true); - w.setWindowButtonVisibility(false); expect(w._getWindowButtonVisibility()).to.equal(false); w.setWindowButtonVisibility(true); - expect(w._getWindowButtonVisibility()).to.equal(true); + expect(w._getWindowButtonVisibility()).to.equal(false); + w.setWindowButtonVisibility(false); + expect(w._getWindowButtonVisibility()).to.equal(false); }); });