Browse Source

fix: maximized frameless window bleeding to other monitors (#25980)

Co-authored-by: Cheng Zhao <[email protected]>
trop[bot] 4 years ago
parent
commit
04548770fb

+ 0 - 29
shell/browser/ui/views/win_frame_view.cc

@@ -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() {}
@@ -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);

+ 0 - 1
shell/browser/ui/views/win_frame_view.h

@@ -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;

+ 26 - 31
shell/browser/ui/win/electron_desktop_window_tree_host_win.cc

@@ -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.
+    //
+    // 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;