diff --git a/shell/browser/native_window_views.cc b/shell/browser/native_window_views.cc index a134dc4f45..a8d02c2c3d 100644 --- a/shell/browser/native_window_views.cc +++ b/shell/browser/native_window_views.cc @@ -682,11 +682,16 @@ void NativeWindowViews::Unmaximize() { if (transparent()) { SetBounds(restore_bounds_, false); NotifyWindowUnmaximize(); + UpdateThickFrame(); return; } #endif widget()->Restore(); + +#if BUILDFLAG(IS_WIN) + UpdateThickFrame(); +#endif } } @@ -719,6 +724,10 @@ void NativeWindowViews::Minimize() { void NativeWindowViews::Restore() { widget()->Restore(); + +#if BUILDFLAG(IS_WIN) + UpdateThickFrame(); +#endif } bool NativeWindowViews::IsMinimized() { @@ -892,12 +901,13 @@ void NativeWindowViews::SetResizable(bool resizable) { extensions::SizeConstraints(content_size, content_size)); } } -#if BUILDFLAG(IS_WIN) - if (has_frame() && thick_frame_) - FlipWindowStyle(GetAcceleratedWidget(), resizable, WS_THICKFRAME); -#endif + resizable_ = resizable; SetCanResize(resizable_); + +#if BUILDFLAG(IS_WIN) + UpdateThickFrame(); +#endif } bool NativeWindowViews::MoveAbove(const std::string& sourceId) { @@ -1644,6 +1654,22 @@ void NativeWindowViews::SetIcon(const gfx::ImageSkia& icon) { } #endif +#if BUILDFLAG(IS_WIN) +void NativeWindowViews::UpdateThickFrame() { + if (!thick_frame_) + return; + + if (IsMaximized() && !transparent()) { + // For maximized window add thick frame always, otherwise it will be removed + // in HWNDMessageHandler::SizeConstraintsChanged() which will result in + // maximized window bounds change. + FlipWindowStyle(GetAcceleratedWidget(), true, WS_THICKFRAME); + } else if (has_frame()) { + FlipWindowStyle(GetAcceleratedWidget(), resizable_, WS_THICKFRAME); + } +} +#endif + void NativeWindowViews::OnWidgetActivationChanged(views::Widget* changed_widget, bool active) { if (changed_widget != widget()) diff --git a/shell/browser/native_window_views.h b/shell/browser/native_window_views.h index 7be1cf3f4f..37985da794 100644 --- a/shell/browser/native_window_views.h +++ b/shell/browser/native_window_views.h @@ -190,6 +190,8 @@ class NativeWindowViews : public NativeWindow, void set_overlay_symbol_color(SkColor color) { overlay_symbol_color_ = color; } + + void UpdateThickFrame(); #endif private: diff --git a/shell/browser/ui/win/electron_desktop_native_widget_aura.cc b/shell/browser/ui/win/electron_desktop_native_widget_aura.cc index 91eb7d71b0..fef641a50a 100644 --- a/shell/browser/ui/win/electron_desktop_native_widget_aura.cc +++ b/shell/browser/ui/win/electron_desktop_native_widget_aura.cc @@ -30,6 +30,16 @@ void ElectronDesktopNativeWidgetAura::InitNativeWidget( views::DesktopNativeWidgetAura::InitNativeWidget(std::move(params)); } +#if BUILDFLAG(IS_WIN) +void ElectronDesktopNativeWidgetAura::OnSizeConstraintsChanged() { + views::DesktopNativeWidgetAura::OnSizeConstraintsChanged(); + + // OnSizeConstraintsChanged can remove thick frame depending from + // resizable state, so add it if needed. + native_window_view_->UpdateThickFrame(); +} +#endif + void ElectronDesktopNativeWidgetAura::Activate() { // Activate can cause the focused window to be blurred so only // call when the window being activated is visible. This prevents diff --git a/shell/browser/ui/win/electron_desktop_native_widget_aura.h b/shell/browser/ui/win/electron_desktop_native_widget_aura.h index 57def339c1..2279a26d40 100644 --- a/shell/browser/ui/win/electron_desktop_native_widget_aura.h +++ b/shell/browser/ui/win/electron_desktop_native_widget_aura.h @@ -27,6 +27,9 @@ class ElectronDesktopNativeWidgetAura : public views::DesktopNativeWidgetAura { // views::DesktopNativeWidgetAura: void InitNativeWidget(views::Widget::InitParams params) override; +#if BUILDFLAG(IS_WIN) + void OnSizeConstraintsChanged() override; +#endif // internal::NativeWidgetPrivate: void Activate() override; diff --git a/spec/api-browser-window-spec.ts b/spec/api-browser-window-spec.ts index 5111dc3b83..2ee8c229d8 100644 --- a/spec/api-browser-window-spec.ts +++ b/spec/api-browser-window-spec.ts @@ -5091,6 +5091,55 @@ describe('BrowserWindow module', () => { w.setContentSize(10, 10); expectBoundsEqual(w.getContentSize(), [10, 10]); }); + + ifit(process.platform === 'win32')('do not change window with frame bounds when maximized', () => { + const w = new BrowserWindow({ + show: true, + frame: true, + thickFrame: true + }); + expect(w.isResizable()).to.be.true('resizable'); + w.maximize(); + expect(w.isMaximized()).to.be.true('maximized'); + const bounds = w.getBounds(); + w.setResizable(false); + expectBoundsEqual(w.getBounds(), bounds); + w.setResizable(true); + expectBoundsEqual(w.getBounds(), bounds); + }); + + ifit(process.platform === 'win32')('do not change window without frame bounds when maximized', () => { + const w = new BrowserWindow({ + show: true, + frame: false, + thickFrame: true + }); + expect(w.isResizable()).to.be.true('resizable'); + w.maximize(); + expect(w.isMaximized()).to.be.true('maximized'); + const bounds = w.getBounds(); + w.setResizable(false); + expectBoundsEqual(w.getBounds(), bounds); + w.setResizable(true); + expectBoundsEqual(w.getBounds(), bounds); + }); + + ifit(process.platform === 'win32')('do not change window transparent without frame bounds when maximized', () => { + const w = new BrowserWindow({ + show: true, + frame: false, + thickFrame: true, + transparent: true + }); + expect(w.isResizable()).to.be.true('resizable'); + w.maximize(); + expect(w.isMaximized()).to.be.true('maximized'); + const bounds = w.getBounds(); + w.setResizable(false); + expectBoundsEqual(w.getBounds(), bounds); + w.setResizable(true); + expectBoundsEqual(w.getBounds(), bounds); + }); }); describe('loading main frame state', () => {