Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: maximized frameless window bleeding to other monitors #25978

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 0 additions & 29 deletions shell/browser/ui/views/win_frame_view.cc
Expand Up @@ -6,29 +6,11 @@

#include "base/win/windows_version.h"
#include "shell/browser/native_window_views.h"
#include "ui/display/win/screen_win.h"
#include "ui/views/widget/widget.h"
#include "ui/views/win/hwnd_util.h"

namespace electron {

namespace {

gfx::Insets GetGlassInsets() {
int frame_height =
display::win::ScreenWin::GetSystemMetricsInDIP(SM_CYSIZEFRAME) +
display::win::ScreenWin::GetSystemMetricsInDIP(SM_CXPADDEDBORDER);

int frame_size =
base::win::GetVersion() < base::win::Version::WIN8
? display::win::ScreenWin::GetSystemMetricsInDIP(SM_CXSIZEFRAME)
: 0;

return gfx::Insets(frame_height, frame_size, frame_size, frame_size);
}

} // namespace

const char WinFrameView::kViewClassName[] = "WinFrameView";

WinFrameView::WinFrameView() {}
Expand All @@ -42,17 +24,6 @@ gfx::Rect WinFrameView::GetWindowBoundsForClientBounds(
client_bounds);
}

gfx::Rect WinFrameView::GetBoundsForClientView() const {
if (window_->IsMaximized() && !window_->has_frame()) {
gfx::Insets insets = GetGlassInsets();
gfx::Rect result(width(), height());
result.Inset(insets);
return result;
} else {
return bounds();
}
}

int WinFrameView::NonClientHitTest(const gfx::Point& point) {
if (window_->has_frame())
return frame_->client_view()->NonClientHitTest(point);
Expand Down
1 change: 0 additions & 1 deletion shell/browser/ui/views/win_frame_view.h
Expand Up @@ -16,7 +16,6 @@ class WinFrameView : public FramelessView {
~WinFrameView() override;

// views::NonClientFrameView:
gfx::Rect GetBoundsForClientView() const override;
gfx::Rect GetWindowBoundsForClientBounds(
const gfx::Rect& client_bounds) const override;
int NonClientHitTest(const gfx::Point& point) override;
Expand Down
57 changes: 26 additions & 31 deletions shell/browser/ui/win/electron_desktop_window_tree_host_win.cc
Expand Up @@ -6,10 +6,7 @@

#include "base/win/windows_version.h"
#include "shell/browser/ui/views/win_frame_view.h"
#include "ui/base/win/hwnd_metrics.h"
#include "ui/base/win/shell.h"
#include "ui/display/win/screen_win.h"
#include "ui/views/win/hwnd_util.h"

namespace electron {

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

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