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:
parent
6edf6c6a95
commit
8bf66f8974
8 changed files with 262 additions and 304 deletions
|
@ -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_
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
31
shell/browser/ui/cocoa/window_buttons_view.h
Normal file
31
shell/browser/ui/cocoa/window_buttons_view.h
Normal 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_
|
119
shell/browser/ui/cocoa/window_buttons_view.mm
Normal file
119
shell/browser/ui/cocoa/window_buttons_view.mm
Normal 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
|
Loading…
Reference in a new issue