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

* 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 1b58b5b1fc.

* 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>
(cherry picked from commit 1f8a46c9c6)
This commit is contained in:
John Kleinschmidt
2021-09-15 20:34:32 -04:00
committed by GitHub
parent 82679f4335
commit fa46c67bd3
16 changed files with 225 additions and 0 deletions

View File

@@ -59,6 +59,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)) {
@@ -326,6 +337,11 @@ void BrowserWindow::OnWindowLeaveFullScreen() {
BaseWindow::OnWindowLeaveFullScreen();
}
void BrowserWindow::UpdateWindowControlsOverlay(
const gfx::Rect& bounding_rect) {
web_contents()->UpdateWindowControlsOverlay(bounding_rect);
}
void BrowserWindow::Focus() {
if (api_web_contents_->IsOffScreen())
FocusOnWebView();

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 OnWindowClosed() override;

View File

@@ -1720,6 +1720,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

@@ -54,6 +54,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_);
@@ -391,6 +392,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);
@@ -489,6 +498,7 @@ void NativeWindow::NotifyWindowWillMove(const gfx::Rect& new_bounds,
}
void NativeWindow::NotifyWindowResize() {
NotifyLayoutWindowControlsOverlay();
for (NativeWindowObserver& observer : observers_)
observer.OnWindowResize();
}
@@ -587,6 +597,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*,
@@ -298,6 +301,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);
@@ -342,6 +346,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_;
@@ -390,6 +396,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

@@ -1505,6 +1505,7 @@ void NativeWindowMac::SetWindowButtonVisibility(bool visible) {
[buttons_proxy_ setVisible:visible];
else
InternalSetWindowButtonVisibility(visible);
NotifyLayoutWindowControlsOverlay();
}
bool NativeWindowMac::GetWindowButtonVisibility() const {
@@ -1518,6 +1519,7 @@ void NativeWindowMac::SetTrafficLightPosition(
traffic_light_position_ = std::move(position);
if (buttons_proxy_) {
[buttons_proxy_ setMargin:traffic_light_position_];
NotifyLayoutWindowControlsOverlay();
}
}
@@ -1835,6 +1837,27 @@ void NativeWindowMac::SetForwardMouseMessages(bool forward) {
[window_ setAcceptsMouseMovedEvents:forward];
}
gfx::Rect NativeWindowMac::GetWindowControlsOverlayRect() {
gfx::Rect bounding_rect;
if (titlebar_overlay_ && !has_frame() && buttons_proxy_ &&
[buttons_proxy_ isVisible]) {
NSRect button_frame = [buttons_proxy_ getButtonsBounds];
gfx::Point buttons_view_margin = [buttons_proxy_ 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

@@ -102,6 +102,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

@@ -54,6 +54,9 @@
- (void)redraw;
- (void)updateTrackingAreas;
- (gfx::Point)getMargin;
- (NSRect)getButtonsBounds;
@end
#endif // SHELL_BROWSER_UI_COCOA_WINDOW_BUTTONS_PROXY_H_

View File

@@ -191,6 +191,10 @@
return result;
}
- (gfx::Point)getMargin {
return margin_;
}
// Receive the titlebar container, which might be nil if the window does not
// have the NSWindowStyleMaskTitled style.
- (NSView*)titleBarContainer {

View File

@@ -201,6 +201,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[];