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:
parent
0fe2836151
commit
1f8a46c9c6
16 changed files with 223 additions and 0 deletions
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -116,4 +116,8 @@ const NSWindowButton kButtonTypes[] = {
|
|||
[self setNeedsDisplayForButtons];
|
||||
}
|
||||
|
||||
- (gfx::Point)getMargin {
|
||||
return margin_;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue