Skip to content

Commit 195f88c

Browse files
trop[bot]zcbenz
andauthored
fix: maximized frameless window bleeding to other monitors (electron#25979)
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
1 parent 4d5e0ad commit 195f88c

File tree

3 files changed

+26
-61
lines changed

3 files changed

+26
-61
lines changed

shell/browser/ui/views/win_frame_view.cc

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,11 @@
66

77
#include "base/win/windows_version.h"
88
#include "shell/browser/native_window_views.h"
9-
#include "ui/display/win/screen_win.h"
109
#include "ui/views/widget/widget.h"
1110
#include "ui/views/win/hwnd_util.h"
1211

1312
namespace electron {
1413

15-
namespace {
16-
17-
gfx::Insets GetGlassInsets() {
18-
int frame_height =
19-
display::win::ScreenWin::GetSystemMetricsInDIP(SM_CYSIZEFRAME) +
20-
display::win::ScreenWin::GetSystemMetricsInDIP(SM_CXPADDEDBORDER);
21-
22-
int frame_size =
23-
base::win::GetVersion() < base::win::Version::WIN8
24-
? display::win::ScreenWin::GetSystemMetricsInDIP(SM_CXSIZEFRAME)
25-
: 0;
26-
27-
return gfx::Insets(frame_height, frame_size, frame_size, frame_size);
28-
}
29-
30-
} // namespace
31-
3214
const char WinFrameView::kViewClassName[] = "WinFrameView";
3315

3416
WinFrameView::WinFrameView() {}
@@ -42,17 +24,6 @@ gfx::Rect WinFrameView::GetWindowBoundsForClientBounds(
4224
client_bounds);
4325
}
4426

45-
gfx::Rect WinFrameView::GetBoundsForClientView() const {
46-
if (window_->IsMaximized() && !window_->has_frame()) {
47-
gfx::Insets insets = GetGlassInsets();
48-
gfx::Rect result(width(), height());
49-
result.Inset(insets);
50-
return result;
51-
} else {
52-
return bounds();
53-
}
54-
}
55-
5627
int WinFrameView::NonClientHitTest(const gfx::Point& point) {
5728
if (window_->has_frame())
5829
return frame_->client_view()->NonClientHitTest(point);

shell/browser/ui/views/win_frame_view.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ class WinFrameView : public FramelessView {
1616
~WinFrameView() override;
1717

1818
// views::NonClientFrameView:
19-
gfx::Rect GetBoundsForClientView() const override;
2019
gfx::Rect GetWindowBoundsForClientBounds(
2120
const gfx::Rect& client_bounds) const override;
2221
int NonClientHitTest(const gfx::Point& point) override;

shell/browser/ui/win/electron_desktop_window_tree_host_win.cc

Lines changed: 26 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@
66

77
#include "base/win/windows_version.h"
88
#include "shell/browser/ui/views/win_frame_view.h"
9-
#include "ui/base/win/hwnd_metrics.h"
109
#include "ui/base/win/shell.h"
11-
#include "ui/display/win/screen_win.h"
12-
#include "ui/views/win/hwnd_util.h"
1310

1411
namespace electron {
1512

@@ -41,23 +38,25 @@ bool ElectronDesktopWindowTreeHostWin::HasNativeFrame() const {
4138
// Since we never use chromium's titlebar implementation, we can just say
4239
// that we use a native titlebar. This will disable the repaint locking when
4340
// DWM composition is disabled.
41+
// See also https://github.com/electron/electron/issues/1821.
4442
return !ui::win::IsAeroGlassEnabled();
4543
}
4644

4745
bool ElectronDesktopWindowTreeHostWin::GetDwmFrameInsetsInPixels(
4846
gfx::Insets* insets) const {
47+
// Set DWMFrameInsets to prevent maximized frameless window from bleeding
48+
// into other monitors.
4949
if (IsMaximized() && !native_window_view_->has_frame()) {
50-
HMONITOR monitor = ::MonitorFromWindow(
51-
native_window_view_->GetAcceleratedWidget(), MONITOR_DEFAULTTONEAREST);
52-
int frame_height = display::win::ScreenWin::GetSystemMetricsForMonitor(
53-
monitor, SM_CYSIZEFRAME) +
54-
display::win::ScreenWin::GetSystemMetricsForMonitor(
55-
monitor, SM_CXPADDEDBORDER);
56-
int frame_size = base::win::GetVersion() < base::win::Version::WIN8
57-
? display::win::ScreenWin::GetSystemMetricsForMonitor(
58-
monitor, SM_CXSIZEFRAME)
59-
: 0;
60-
insets->Set(frame_height, frame_size, frame_size, frame_size);
50+
// This would be equivalent to calling:
51+
// DwmExtendFrameIntoClientArea({0, 0, 0, 0});
52+
//
53+
// which means do not extend window frame into client area. It is almost
54+
// a no-op, but it can tell Windows to not extend the window frame to be
55+
// larger than current workspace.
56+
//
57+
// See also:
58+
// https://devblogs.microsoft.com/oldnewthing/20150304-00/?p=44543
59+
*insets = gfx::Insets();
6160
return true;
6261
}
6362
return false;
@@ -66,24 +65,20 @@ bool ElectronDesktopWindowTreeHostWin::GetDwmFrameInsetsInPixels(
6665
bool ElectronDesktopWindowTreeHostWin::GetClientAreaInsets(
6766
gfx::Insets* insets,
6867
HMONITOR monitor) const {
68+
// Windows by deafult extends the maximized window slightly larger than
69+
// current workspace, for frameless window since the standard frame has been
70+
// removed, the client area would then be drew outside current workspace.
71+
//
72+
// Indenting the client area can fix this behavior.
6973
if (IsMaximized() && !native_window_view_->has_frame()) {
70-
if (base::win::GetVersion() < base::win::Version::WIN8) {
71-
// This tells Windows that most of the window is a client area, meaning
72-
// Chrome will draw it. Windows still fills in the glass bits because of
73-
// the // DwmExtendFrameIntoClientArea call in |UpdateDWMFrame|.
74-
// Without this 1 pixel offset on the right and bottom:
75-
// * windows paint in a more standard way, and
76-
// * we get weird black bars at the top when maximized in multiple
77-
// monitor configurations.
78-
int border_thickness = 1;
79-
insets->Set(0, 0, border_thickness, border_thickness);
80-
} else {
81-
const int frame_thickness = ui::GetFrameThickness(monitor);
82-
// Reduce the Windows non-client border size because we extend the border
83-
// into our client area in UpdateDWMFrame(). The top inset must be 0 or
84-
// else Windows will draw a full native titlebar outside the client area.
85-
insets->Set(0, frame_thickness, frame_thickness, frame_thickness);
86-
}
74+
// The insets would be eventually passed to WM_NCCALCSIZE, which takes
75+
// the metrics under the DPI of _main_ monitor instead of current moniotr.
76+
//
77+
// Please make sure you tested maximized frameless window under multiple
78+
// monitors with different DPIs before changing this code.
79+
const int thickness = ::GetSystemMetrics(SM_CXSIZEFRAME) +
80+
::GetSystemMetrics(SM_CXPADDEDBORDER);
81+
insets->Set(thickness, thickness, thickness, thickness);
8782
return true;
8883
}
8984
return false;

0 commit comments

Comments
 (0)