feat: enable window controls overlay on macOS (#29253)

* feat: enable windows control overlay on macOS

* address review feedback

* chore: address review feedback

* Address review feedback

* update doc per review

* only enable WCO when titleBarStyle is overlay

* Revert "only enable WCO when titleBarStyle is overlay"

This reverts commit 1b58b5b1fcb8f091880a4e5d1f8855399c44afad.

* Add new titleBarOverlay property to manage feature

* spelling fix

* Update docs/api/frameless-window.md

Co-authored-by: Samuel Attard <sam@electronjs.org>

* Update shell/browser/api/electron_api_browser_window.cc

Co-authored-by: Samuel Attard <sam@electronjs.org>

* update per review feedback

Co-authored-by: Samuel Attard <sam@electronjs.org>
This commit is contained in:
John Kleinschmidt 2021-07-01 15:25:40 -04:00 committed by GitHub
parent 0fe2836151
commit 1f8a46c9c6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 223 additions and 0 deletions

View file

@ -57,6 +57,17 @@ BrowserWindow::BrowserWindow(gin::Arguments* args,
web_preferences.Set(options::kShow, show);
}
bool titleBarOverlay = false;
options.Get(options::ktitleBarOverlay, &titleBarOverlay);
if (titleBarOverlay) {
std::string enabled_features = "";
if (web_preferences.Get(options::kEnableBlinkFeatures, &enabled_features)) {
enabled_features += ",";
}
enabled_features += features::kWebAppWindowControlsOverlay.name;
web_preferences.Set(options::kEnableBlinkFeatures, enabled_features);
}
// Copy the webContents option to webPreferences. This is only used internally
// to implement nativeWindowOpen option.
if (options.Get("webContents", &value)) {
@ -312,6 +323,11 @@ void BrowserWindow::OnWindowLeaveFullScreen() {
BaseWindow::OnWindowLeaveFullScreen();
}
void BrowserWindow::UpdateWindowControlsOverlay(
const gfx::Rect& bounding_rect) {
web_contents()->UpdateWindowControlsOverlay(bounding_rect);
}
void BrowserWindow::CloseImmediately() {
// Close all child windows before closing current window.
v8::Locker locker(isolate());

View file

@ -69,6 +69,7 @@ class BrowserWindow : public BaseWindow,
void RequestPreferredWidth(int* width) override;
void OnCloseButtonClicked(bool* prevent_default) override;
void OnWindowIsKeyChanged(bool is_key) override;
void UpdateWindowControlsOverlay(const gfx::Rect& bounding_rect) override;
// BaseWindow:
void OnWindowBlur() override;

View file

@ -1675,6 +1675,10 @@ void WebContents::ReadyToCommitNavigation(
void WebContents::DidFinishNavigation(
content::NavigationHandle* navigation_handle) {
if (owner_window_) {
owner_window_->NotifyLayoutWindowControlsOverlay();
}
if (!navigation_handle->HasCommitted())
return;
bool is_main_frame = navigation_handle->IsInMainFrame();

View file

@ -53,6 +53,7 @@ NativeWindow::NativeWindow(const gin_helper::Dictionary& options,
options.Get(options::kFrame, &has_frame_);
options.Get(options::kTransparent, &transparent_);
options.Get(options::kEnableLargerThanScreen, &enable_larger_than_screen_);
options.Get(options::ktitleBarOverlay, &titlebar_overlay_);
if (parent)
options.Get("modal", &is_modal_);
@ -394,6 +395,14 @@ void NativeWindow::PreviewFile(const std::string& path,
void NativeWindow::CloseFilePreview() {}
gfx::Rect NativeWindow::GetWindowControlsOverlayRect() {
return overlay_rect_;
}
void NativeWindow::SetWindowControlsOverlayRect(const gfx::Rect& overlay_rect) {
overlay_rect_ = overlay_rect;
}
void NativeWindow::NotifyWindowRequestPreferredWith(int* width) {
for (NativeWindowObserver& observer : observers_)
observer.RequestPreferredWidth(width);
@ -493,6 +502,7 @@ void NativeWindow::NotifyWindowWillMove(const gfx::Rect& new_bounds,
}
void NativeWindow::NotifyWindowResize() {
NotifyLayoutWindowControlsOverlay();
for (NativeWindowObserver& observer : observers_)
observer.OnWindowResize();
}
@ -591,6 +601,14 @@ void NativeWindow::NotifyWindowSystemContextMenu(int x,
observer.OnSystemContextMenu(x, y, prevent_default);
}
void NativeWindow::NotifyLayoutWindowControlsOverlay() {
gfx::Rect bounding_rect = GetWindowControlsOverlayRect();
if (!bounding_rect.IsEmpty()) {
for (NativeWindowObserver& observer : observers_)
observer.UpdateWindowControlsOverlay(bounding_rect);
}
}
#if defined(OS_WIN)
void NativeWindow::NotifyWindowMessage(UINT message,
WPARAM w_param,

View file

@ -255,6 +255,9 @@ class NativeWindow : public base::SupportsUserData,
return weak_factory_.GetWeakPtr();
}
virtual gfx::Rect GetWindowControlsOverlayRect();
virtual void SetWindowControlsOverlayRect(const gfx::Rect& overlay_rect);
// Methods called by the WebContents.
virtual void HandleKeyboardEvent(
content::WebContents*,
@ -299,6 +302,7 @@ class NativeWindow : public base::SupportsUserData,
const base::DictionaryValue& details);
void NotifyNewWindowForTab();
void NotifyWindowSystemContextMenu(int x, int y, bool* prevent_default);
void NotifyLayoutWindowControlsOverlay();
#if defined(OS_WIN)
void NotifyWindowMessage(UINT message, WPARAM w_param, LPARAM l_param);
@ -343,6 +347,8 @@ class NativeWindow : public base::SupportsUserData,
[&browser_view](NativeBrowserView* n) { return (n == browser_view); });
}
bool titlebar_overlay_ = false;
private:
std::unique_ptr<views::Widget> widget_;
@ -391,6 +397,8 @@ class NativeWindow : public base::SupportsUserData,
// Accessible title.
std::u16string accessible_title_;
gfx::Rect overlay_rect_;
base::WeakPtrFactory<NativeWindow> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(NativeWindow);

View file

@ -147,6 +147,7 @@ class NativeWindowMac : public NativeWindow,
void CloseFilePreview() override;
gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) const override;
gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) const override;
gfx::Rect GetWindowControlsOverlayRect() override;
void NotifyWindowEnterFullScreen() override;
void NotifyWindowLeaveFullScreen() override;
void SetActive(bool is_key) override;

View file

@ -1488,6 +1488,7 @@ void NativeWindowMac::SetVibrancy(const std::string& type) {
void NativeWindowMac::SetWindowButtonVisibility(bool visible) {
window_button_visibility_ = visible;
InternalSetWindowButtonVisibility(visible);
NotifyLayoutWindowControlsOverlay();
}
bool NativeWindowMac::GetWindowButtonVisibility() const {
@ -1505,6 +1506,7 @@ void NativeWindowMac::SetTrafficLightPosition(
if (buttons_view_) {
[buttons_view_ setMargin:traffic_light_position_];
[buttons_view_ viewDidMoveToWindow];
NotifyLayoutWindowControlsOverlay();
}
}
@ -1859,6 +1861,27 @@ void NativeWindowMac::SetForwardMouseMessages(bool forward) {
[window_ setAcceptsMouseMovedEvents: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;
}
// static
NativeWindow* NativeWindow::Create(const gin_helper::Dictionary& options,
NativeWindow* parent) {

View file

@ -104,6 +104,8 @@ class NativeWindowObserver : public base::CheckedObserver {
// Called on Windows when App Commands arrive (WM_APPCOMMAND)
// Some commands are implemented on on other platforms as well
virtual void OnExecuteAppCommand(const std::string& command_name) {}
virtual void UpdateWindowControlsOverlay(const gfx::Rect& bounding_rect) {}
};
} // namespace electron

View file

@ -26,6 +26,7 @@
- (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_

View file

@ -116,4 +116,8 @@ const NSWindowButton kButtonTypes[] = {
[self setNeedsDisplayForButtons];
}
- (gfx::Point)getMargin {
return margin_;
}
@end

View file

@ -194,6 +194,8 @@ const char kEnableWebSQL[] = "enableWebSQL";
const char kEnablePreferredSizeMode[] = "enablePreferredSizeMode";
const char ktitleBarOverlay[] = "titleBarOverlay";
} // namespace options
namespace switches {

View file

@ -57,6 +57,7 @@ extern const char kVibrancyType[];
extern const char kVisualEffectState[];
extern const char kTrafficLightPosition[];
extern const char kRoundedCorners[];
extern const char ktitleBarOverlay[];
// WebPreferences.
extern const char kZoomFactor[];