[Bf-blender-cvs] [999f1f75045] master: Win32: Window Placement DPI and Scale Adjustment

Harley Acheson noreply at git.blender.org
Tue Jun 29 18:29:48 CEST 2021


Commit: 999f1f75045c38a63f960d29e8bc7b9fd19ad0e7
Author: Harley Acheson
Date:   Tue Jun 29 09:28:20 2021 -0700
Branches: master
https://developer.blender.org/rB999f1f75045c38a63f960d29e8bc7b9fd19ad0e7

Win32: Window Placement DPI and Scale Adjustment

When using multiple monitors that differ in scale and/or dpi, the
varying sizes of the window titles and borders can cause the placement
of those windows to be out by a small amount. This patch adjusts for
those differences on Windows 10 and newer.

see D10863 for details and examples.

Differential Revision: https://developer.blender.org/D10863

Reviewed by Ray Molenkamp

===================================================================

M	intern/ghost/intern/GHOST_WindowWin32.cpp
M	intern/ghost/intern/GHOST_WindowWin32.h

===================================================================

diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index a6666c9961c..4f85e2ea8d0 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -38,6 +38,7 @@
 
 #include <assert.h>
 #include <math.h>
+#include <shellscalingapi.h>
 #include <string.h>
 #include <windowsx.h>
 
@@ -80,13 +81,10 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
       m_wintab(NULL),
       m_lastPointerTabletData(GHOST_TABLET_DATA_NONE),
       m_normal_state(GHOST_kWindowStateNormal),
-      m_user32(NULL),
+      m_user32(::LoadLibrary("user32.dll")),
       m_parentWindowHwnd(parentwindow ? parentwindow->m_hWnd : HWND_DESKTOP),
       m_debug_context(is_debug)
 {
-  wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0);
-  RECT win_rect = {left, top, (long)(left + width), (long)(top + height)};
-
   DWORD style = parentwindow ?
                     WS_POPUPWINDOW | WS_CAPTION | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SIZEBOX :
                     WS_OVERLAPPEDWINDOW;
@@ -105,27 +103,10 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
      */
   }
 
-  /* Monitor details. */
-  MONITORINFOEX monitor;
-  monitor.cbSize = sizeof(MONITORINFOEX);
-  monitor.dwFlags = 0;
-  GetMonitorInfo(MonitorFromRect(&win_rect, MONITOR_DEFAULTTONEAREST), &monitor);
-
-  /* Constrain requested size and position to fit within this monitor. */
-  width = min(monitor.rcWork.right - monitor.rcWork.left, win_rect.right - win_rect.left);
-  height = min(monitor.rcWork.bottom - monitor.rcWork.top, win_rect.bottom - win_rect.top);
-  win_rect.left = min(max(monitor.rcWork.left, win_rect.left), monitor.rcWork.right - width);
-  win_rect.right = win_rect.left + width;
-  win_rect.top = min(max(monitor.rcWork.top, win_rect.top), monitor.rcWork.bottom - height);
-  win_rect.bottom = win_rect.top + height;
-
-  /* Adjust to allow for caption, borders, shadows, scaling, etc. Resulting values can be
-   * correctly outside of monitor bounds. Note: You cannot specify WS_OVERLAPPED when calling. */
-  AdjustWindowRectEx(&win_rect, style & ~WS_OVERLAPPED, FALSE, extended_style);
-
-  /* But never allow a top position that can hide part of the title bar. */
-  win_rect.top = max(monitor.rcWork.top, win_rect.top);
+  RECT win_rect = {left, top, (long)(left + width), (long)(top + height)};
+  adjustWindowRectForClosestMonitor(&win_rect, style, extended_style);
 
+  wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0);
   m_hWnd = ::CreateWindowExW(extended_style,                  // window extended style
                              s_windowClassName,               // pointer to registered class name
                              title_16,                        // pointer to window name
@@ -153,8 +134,6 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
     return;
   }
 
-  m_user32 = ::LoadLibrary("user32.dll");
-
   RegisterTouchWindow(m_hWnd, 0);
 
   /* Register as droptarget. OleInitialize(0) required first, done in GHOST_SystemWin32. */
@@ -187,22 +166,22 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
   ::ShowWindow(m_hWnd, nCmdShow);
 
 #ifdef WIN32_COMPOSITING
-      if (alphaBackground && parentwindowhwnd == 0) {
+  if (alphaBackground && parentwindowhwnd == 0) {
 
-        HRESULT hr = S_OK;
+    HRESULT hr = S_OK;
 
-        /* Create and populate the Blur Behind structure. */
-        DWM_BLURBEHIND bb = {0};
+    /* Create and populate the Blur Behind structure. */
+    DWM_BLURBEHIND bb = {0};
 
-        /* Enable Blur Behind and apply to the entire client area. */
-        bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
-        bb.fEnable = true;
-        bb.hRgnBlur = CreateRectRgn(0, 0, -1, -1);
+    /* Enable Blur Behind and apply to the entire client area. */
+    bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
+    bb.fEnable = true;
+    bb.hRgnBlur = CreateRectRgn(0, 0, -1, -1);
 
-        /* Apply Blur Behind. */
-        hr = DwmEnableBlurBehindWindow(m_hWnd, &bb);
-        DeleteObject(bb.hRgnBlur);
-      }
+    /* Apply Blur Behind. */
+    hr = DwmEnableBlurBehindWindow(m_hWnd, &bb);
+    DeleteObject(bb.hRgnBlur);
+  }
 #endif
 
   /* Force an initial paint of the window. */
@@ -267,6 +246,47 @@ GHOST_WindowWin32::~GHOST_WindowWin32()
   }
 }
 
+void GHOST_WindowWin32::adjustWindowRectForClosestMonitor(LPRECT win_rect,
+                                                          DWORD dwStyle,
+                                                          DWORD dwExStyle)
+{
+  /* Get Details of the closest monitor. */
+  HMONITOR hmonitor = MonitorFromRect(win_rect, MONITOR_DEFAULTTONEAREST);
+  MONITORINFOEX monitor;
+  monitor.cbSize = sizeof(MONITORINFOEX);
+  monitor.dwFlags = 0;
+  GetMonitorInfo(hmonitor, &monitor);
+
+  /* Constrain requested size and position to fit within this monitor. */
+  LONG width = min(monitor.rcWork.right - monitor.rcWork.left, win_rect->right - win_rect->left);
+  LONG height = min(monitor.rcWork.bottom - monitor.rcWork.top, win_rect->bottom - win_rect->top);
+  win_rect->left = min(max(monitor.rcWork.left, win_rect->left), monitor.rcWork.right - width);
+  win_rect->right = win_rect->left + width;
+  win_rect->top = min(max(monitor.rcWork.top, win_rect->top), monitor.rcWork.bottom - height);
+  win_rect->bottom = win_rect->top + height;
+
+  /* With Windows 10 and newer we can adjust for chrome that differs with DPI and scale. */
+  GHOST_WIN32_AdjustWindowRectExForDpi fpAdjustWindowRectExForDpi = nullptr;
+  if (m_user32) {
+    fpAdjustWindowRectExForDpi = (GHOST_WIN32_AdjustWindowRectExForDpi)::GetProcAddress(
+        m_user32, "AdjustWindowRectExForDpi");
+  }
+
+  /* Adjust to allow for caption, borders, shadows, scaling, etc. Resulting values can be
+   * correctly outside of monitor bounds. Note: You cannot specify WS_OVERLAPPED when calling. */
+  if (fpAdjustWindowRectExForDpi) {
+    UINT dpiX, dpiY;
+    GetDpiForMonitor(hmonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
+    fpAdjustWindowRectExForDpi(win_rect, dwStyle & ~WS_OVERLAPPED, FALSE, dwExStyle, dpiX);
+  }
+  else {
+    AdjustWindowRectEx(win_rect, dwStyle & ~WS_OVERLAPPED, FALSE, dwExStyle);
+  }
+
+  /* But never allow a top position that can hide part of the title bar. */
+  win_rect->top = max(monitor.rcWork.top, win_rect->top);
+}
+
 bool GHOST_WindowWin32::getValid() const
 {
   return GHOST_Window::getValid() && m_hWnd != 0 && m_hDC != 0;
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index f28ba266ed1..119092a001a 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -43,6 +43,9 @@ class GHOST_DropTargetWin32;
 // typedefs for user32 functions to allow dynamic loading of Windows 10 DPI scaling functions
 typedef UINT(API *GHOST_WIN32_GetDpiForWindow)(HWND);
 
+typedef BOOL(API *GHOST_WIN32_AdjustWindowRectExForDpi)(
+    LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi);
+
 struct GHOST_PointerInfoWin32 {
   GHOST_TInt32 pointerId;
   GHOST_TInt32 isPrimary;
@@ -98,6 +101,14 @@ class GHOST_WindowWin32 : public GHOST_Window {
    */
   ~GHOST_WindowWin32();
 
+  /**
+   * Adjusts a requested window rect to fit and position correctly in monitor.
+   * \param win_rect: pointer to rectangle that will be modified.
+   * \param dwStyle: The Window Style of the window whose required size is to be calculated.
+   * \param dwExStyle: The Extended Window Style of the window.
+   */
+  void adjustWindowRectForClosestMonitor(LPRECT win_rect, DWORD dwStyle, DWORD dwExStyle);
+
   /**
    * Returns indication as to whether the window is valid.
    * \return The validity of the window.



More information about the Bf-blender-cvs mailing list