Browse Source

fix: move window buttons in-place on macOS (#30391)

Co-authored-by: Cheng Zhao <[email protected]>
trop[bot] 3 years ago
parent
commit
c3403299fe

+ 2 - 2
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",

+ 4 - 6
shell/browser/native_window_mac.h

@@ -23,7 +23,7 @@
 @class ElectronNSWindowDelegate;
 @class ElectronPreviewItem;
 @class ElectronTouchBar;
-@class WindowButtonsView;
+@class WindowButtonsProxy;
 
 namespace electron {
 
@@ -157,9 +157,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.
@@ -216,7 +213,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);
 
@@ -225,7 +221,6 @@ class NativeWindowMac : public NativeWindow,
   base::scoped_nsobject<ElectronNSWindowDelegate> window_delegate_;
   base::scoped_nsobject<ElectronPreviewItem> preview_item_;
   base::scoped_nsobject<ElectronTouchBar> touch_bar_;
-  base::scoped_nsobject<WindowButtonsView> buttons_view_;
 
   // Event monitor for scroll wheel event.
   id wheel_event_monitor_;
@@ -264,6 +259,9 @@ class NativeWindowMac : public NativeWindow,
   // setWindowButtonVisibility().
   absl::optional<bool> window_button_visibility_;
 
+  // Controls the position and visibility of window buttons.
+  base::scoped_nsobject<WindowButtonsProxy> buttons_proxy_;
+
   // Maximizable window state; necessary for persistence through redraws.
   bool maximizable_ = true;
 

+ 57 - 95
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"
@@ -380,8 +380,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
@@ -460,9 +478,6 @@ void NativeWindowMac::SetContentView(views::View* view) {
   set_content_view(view);
   root_view->AddChildView(content_view());
 
-  if (buttons_view_)
-    ReorderButtonsView();
-
   root_view->Layout();
 }
 
@@ -805,8 +820,6 @@ bool NativeWindowMac::IsMovable() {
 
 void NativeWindowMac::SetMinimizable(bool minimizable) {
   SetStyleMask(minimizable, NSMiniaturizableWindowMask);
-  if (buttons_view_)
-    [[buttons_view_ viewWithTag:1] setEnabled:minimizable];
 }
 
 bool NativeWindowMac::IsMinimizable() {
@@ -828,8 +841,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() {
@@ -839,8 +850,6 @@ bool NativeWindowMac::IsFullScreenable() {
 
 void NativeWindowMac::SetClosable(bool closable) {
   SetStyleMask(closable, NSWindowStyleMaskClosable);
-  if (buttons_view_)
-    [[buttons_view_ viewWithTag:0] setEnabled:closable];
 }
 
 bool NativeWindowMac::IsClosable() {
@@ -946,6 +955,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() {
@@ -1181,8 +1192,6 @@ void NativeWindowMac::AddBrowserView(NativeBrowserView* view) {
   }
 
   [CATransaction commit];
-
-  ReorderButtonsView();
 }
 
 void NativeWindowMac::RemoveBrowserView(NativeBrowserView* view) {
@@ -1224,8 +1233,6 @@ void NativeWindowMac::SetTopBrowserView(NativeBrowserView* view) {
   }
 
   [CATransaction commit];
-
-  ReorderButtonsView();
 }
 
 void NativeWindowMac::SetParentWindow(NativeWindow* parent) {
@@ -1487,25 +1494,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<gfx::Point> 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();
   }
 }
@@ -1515,8 +1523,8 @@ absl::optional<gfx::Point> 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.
@@ -1648,35 +1656,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);
 }
 
@@ -1688,13 +1691,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);
@@ -1790,37 +1786,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];
@@ -1860,24 +1829,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);
-    }
-  }
-  return bounding_rect;
+  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 gfx::Rect();
 }
 
 // static

+ 1 - 0
shell/browser/ui/cocoa/electron_ns_window_delegate.mm

@@ -157,6 +157,7 @@ using FullScreenTransitionState =
 - (void)windowDidResize:(NSNotification*)notification {
   [super windowDidResize:notification];
   shell_->NotifyWindowResize();
+  shell_->RedrawTrafficLights();
 }
 
 - (void)windowWillMove:(NSNotification*)notification {

+ 66 - 0
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 <Cocoa/Cocoa.h>
+
+#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<NSTrackingArea> tracking_area_;
+  base::scoped_nsobject<ButtonsAreaHoverView> 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<gfx::Point>&)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_

+ 200 - 0
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<gfx::Point>&)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

+ 0 - 34
shell/browser/ui/cocoa/window_buttons_view.h

@@ -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 <Cocoa/Cocoa.h>
-
-#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<NSTrackingArea> tracking_area_;
-}
-
-+ (gfx::Point)defaultMargin;
-+ (gfx::Point)hiddenInsetMargin;
-- (id)initWithMargin:(const absl::optional<gfx::Point>&)margin;
-- (void)setMargin:(const absl::optional<gfx::Point>&)margin;
-- (void)setShowOnHover:(BOOL)yes;
-- (void)setNeedsDisplayForButtons;
-- (gfx::Point)getMargin;
-@end
-
-#endif  // SHELL_BROWSER_UI_COCOA_WINDOW_BUTTONS_VIEW_H_

+ 0 - 138
shell/browser/ui/cocoa/window_buttons_view.mm

@@ -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<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 absl::optional<gfx::Point>&)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

+ 5 - 4
spec-main/api-browser-window-spec.ts

@@ -1594,13 +1594,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);
     });
   });