Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions filenames.gni
Expand Up @@ -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",
Expand Down
10 changes: 4 additions & 6 deletions shell/browser/native_window_mac.h
Expand Up @@ -23,7 +23,7 @@
@class ElectronNSWindowDelegate;
@class ElectronPreviewItem;
@class ElectronTouchBar;
@class WindowButtonsView;
@class WindowButtonsProxy;

namespace electron {

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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);

Expand All @@ -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_;
Expand Down Expand Up @@ -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;

Expand Down
152 changes: 57 additions & 95 deletions shell/browser/native_window_mac.mm
Expand Up @@ -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"
Expand Down Expand Up @@ -380,8 +380,26 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
[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
Expand Down Expand Up @@ -460,9 +478,6 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
set_content_view(view);
root_view->AddChildView(content_view());

if (buttons_view_)
ReorderButtonsView();

root_view->Layout();
}

Expand Down Expand Up @@ -805,8 +820,6 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {

void NativeWindowMac::SetMinimizable(bool minimizable) {
SetStyleMask(minimizable, NSMiniaturizableWindowMask);
if (buttons_view_)
[[buttons_view_ viewWithTag:1] setEnabled:minimizable];
}

bool NativeWindowMac::IsMinimizable() {
Expand All @@ -828,8 +841,6 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
// 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() {
Expand All @@ -839,8 +850,6 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {

void NativeWindowMac::SetClosable(bool closable) {
SetStyleMask(closable, NSWindowStyleMaskClosable);
if (buttons_view_)
[[buttons_view_ viewWithTag:0] setEnabled:closable];
}

bool NativeWindowMac::IsClosable() {
Expand Down Expand Up @@ -946,6 +955,8 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {

void NativeWindowMac::SetTitle(const std::string& title) {
[window_ setTitle:base::SysUTF8ToNSString(title)];
if (buttons_proxy_)
[buttons_proxy_ redraw];
}

std::string NativeWindowMac::GetTitle() {
Expand Down Expand Up @@ -1181,8 +1192,6 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
}

[CATransaction commit];

ReorderButtonsView();
}

void NativeWindowMac::RemoveBrowserView(NativeBrowserView* view) {
Expand Down Expand Up @@ -1224,8 +1233,6 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
}

[CATransaction commit];

ReorderButtonsView();
}

void NativeWindowMac::SetParentWindow(NativeWindow* parent) {
Expand Down Expand Up @@ -1487,25 +1494,26 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {

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();
}
}
Expand All @@ -1515,8 +1523,8 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
}

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.
Expand Down Expand Up @@ -1648,35 +1656,30 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
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);
}

Expand All @@ -1688,13 +1691,6 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
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);
Expand Down Expand Up @@ -1790,37 +1786,10 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
(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];
Expand Down Expand Up @@ -1860,24 +1829,17 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) {
}

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
Expand Down
1 change: 1 addition & 0 deletions shell/browser/ui/cocoa/electron_ns_window_delegate.mm
Expand Up @@ -157,6 +157,7 @@ - (NSSize)windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize {
- (void)windowDidResize:(NSNotification*)notification {
[super windowDidResize:notification];
shell_->NotifyWindowResize();
shell_->RedrawTrafficLights();
}

- (void)windowWillMove:(NSNotification*)notification {
Expand Down