-
Notifications
You must be signed in to change notification settings - Fork 16.2k
fix: maximized frameless window bleeding to other monitors #25940
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 { | ||
|
||
|
@@ -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; | ||
|
@@ -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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. surprising find, should this be reported to upstream ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This only seems to be a problem for maximized frameless window, which Chrome only uses for deprecated Chrome Apps APIs. I can't find other way to reproduce it in Chrome . |
||
// | ||
// 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; | ||
|
Uh oh!
There was an error while loading. Please reload this page.