Skip to content

Commit d0bb4cd

Browse files
franciscojma86NoamDev
authored andcommitted
Gets the DPI for all awareness mode and older Windows versions (flutter#15951)
1 parent e6305de commit d0bb4cd

File tree

4 files changed

+52
-72
lines changed

4 files changed

+52
-72
lines changed

shell/platform/windows/win32_dpi_helper.cc

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ namespace flutter {
44

55
namespace {
66

7+
constexpr UINT kDefaultDpi = 96;
8+
79
template <typename T>
810
bool AssignProcAddress(HMODULE comBaseModule, const char* name, T*& outProc) {
911
outProc = reinterpret_cast<T*>(GetProcAddress(comBaseModule, name));
@@ -13,60 +15,57 @@ bool AssignProcAddress(HMODULE comBaseModule, const char* name, T*& outProc) {
1315
} // namespace
1416

1517
Win32DpiHelper::Win32DpiHelper() {
16-
// TODO ensure that this helper works correctly on downlevel builds.
1718
user32_module_ = LoadLibraryA("User32.dll");
1819
if (user32_module_ == nullptr) {
1920
return;
2021
}
2122

22-
if (!AssignProcAddress(user32_module_, "EnableNonClientDpiScaling",
23-
enable_non_client_dpi_scaling_)) {
23+
if (AssignProcAddress(user32_module_, "GetDpiForWindow",
24+
get_dpi_for_window_)) {
25+
dpi_for_window_supported_ = true;
2426
return;
2527
}
2628

27-
if (!AssignProcAddress(user32_module_, "GetDpiForWindow",
28-
get_dpi_for_window_)) {
29+
shlib_module_ = LoadLibraryA("Shcore.dll");
30+
if (shlib_module_ == nullptr) {
2931
return;
3032
}
3133

32-
if (!AssignProcAddress(user32_module_, "SetProcessDpiAwarenessContext",
33-
set_process_dpi_awareness_context_)) {
34-
return;
34+
if (AssignProcAddress(shlib_module_, "GetDpiForMonitor",
35+
get_dpi_for_monitor_) &&
36+
AssignProcAddress(user32_module_, "MonitorFromWindow",
37+
monitor_from_window_)) {
38+
dpi_for_monitor_supported_ = true;
3539
}
36-
37-
permonitorv2_supported_ = true;
3840
}
3941

4042
Win32DpiHelper::~Win32DpiHelper() {
4143
if (user32_module_ != nullptr) {
4244
FreeLibrary(user32_module_);
4345
}
44-
}
45-
46-
bool Win32DpiHelper::IsPerMonitorV2Available() {
47-
return permonitorv2_supported_;
48-
}
49-
50-
BOOL Win32DpiHelper::EnableNonClientDpiScaling(HWND hwnd) {
51-
if (!permonitorv2_supported_) {
52-
return false;
46+
if (shlib_module_ != nullptr) {
47+
FreeLibrary(shlib_module_);
5348
}
54-
return enable_non_client_dpi_scaling_(hwnd);
5549
}
5650

57-
UINT Win32DpiHelper::GetDpiForWindow(HWND hwnd) {
58-
if (!permonitorv2_supported_) {
59-
return false;
51+
UINT Win32DpiHelper::GetDpi(HWND hwnd) {
52+
// GetDpiForWindow returns the DPI for any awareness mode. If not available,
53+
// fallback to a per monitor, system, or default DPI.
54+
if (dpi_for_window_supported_) {
55+
return get_dpi_for_window_(hwnd);
6056
}
61-
return get_dpi_for_window_(hwnd);
62-
}
6357

64-
BOOL Win32DpiHelper::SetProcessDpiAwarenessContext(
65-
DPI_AWARENESS_CONTEXT context) {
66-
if (!permonitorv2_supported_) {
67-
return false;
58+
if (dpi_for_monitor_supported_) {
59+
HMONITOR monitor = monitor_from_window_(hwnd, MONITOR_DEFAULTTONEAREST);
60+
UINT dpi_x = 0, dpi_y = 0;
61+
HRESULT result =
62+
get_dpi_for_monitor_(monitor, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y);
63+
return SUCCEEDED(result) ? dpi_x : kDefaultDpi;
6864
}
69-
return set_process_dpi_awareness_context_(context);
70-
}
7165

66+
HDC hdc = GetDC(hwnd);
67+
UINT dpi = GetDeviceCaps(hdc, LOGPIXELSX);
68+
ReleaseDC(hwnd, hdc);
69+
return dpi;
70+
}
7271
} // namespace flutter

shell/platform/windows/win32_dpi_helper.h

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,38 +10,34 @@
1010

1111
namespace flutter {
1212

13-
// A helper class for abstracting various Windows DPI related functions across
14-
// Windows OS versions.
13+
/// A helper class for abstracting various Windows DPI related functions across
14+
/// Windows OS versions.
1515
class Win32DpiHelper {
1616
public:
1717
Win32DpiHelper();
1818

1919
~Win32DpiHelper();
2020

21-
// Check if Windows Per Monitor V2 DPI scaling functionality is available on
22-
// current system.
23-
bool IsPerMonitorV2Available();
24-
25-
// Wrapper for OS functionality to turn on automatic window non-client scaling
26-
BOOL EnableNonClientDpiScaling(HWND);
27-
28-
// Wrapper for OS functionality to return the DPI for |HWND|
29-
UINT GetDpiForWindow(HWND);
30-
31-
// Sets the current process to a specified DPI awareness context.
32-
BOOL SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT);
21+
/// Returns the current DPI. Supports all DPI awareness modes, and is backward
22+
/// compatible down to Windows Vista.
23+
UINT GetDpi(HWND);
3324

3425
private:
35-
using EnableNonClientDpiScaling_ = BOOL __stdcall(HWND);
3626
using GetDpiForWindow_ = UINT __stdcall(HWND);
37-
using SetProcessDpiAwarenessContext_ = BOOL __stdcall(DPI_AWARENESS_CONTEXT);
27+
using GetDpiForMonitor_ = HRESULT __stdcall(HMONITOR hmonitor,
28+
MONITOR_DPI_TYPE dpiType,
29+
UINT* dpiX,
30+
UINT* dpiY);
31+
using MonitorFromWindow_ = HMONITOR __stdcall(HWND hwnd, DWORD dwFlags);
3832

39-
EnableNonClientDpiScaling_* enable_non_client_dpi_scaling_ = nullptr;
4033
GetDpiForWindow_* get_dpi_for_window_ = nullptr;
41-
SetProcessDpiAwarenessContext_* set_process_dpi_awareness_context_ = nullptr;
34+
GetDpiForMonitor_* get_dpi_for_monitor_ = nullptr;
35+
MonitorFromWindow_* monitor_from_window_ = nullptr;
4236

4337
HMODULE user32_module_ = nullptr;
44-
bool permonitorv2_supported_ = false;
38+
HMODULE shlib_module_ = nullptr;
39+
bool dpi_for_window_supported_ = false;
40+
bool dpi_for_monitor_supported_ = false;
4541
};
4642

4743
} // namespace flutter

shell/platform/windows/win32_window.cc

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,8 @@
66

77
namespace flutter {
88

9-
Win32Window::Win32Window() {
10-
// Assume Windows 10 1703 or greater for DPI handling. When running on a
11-
// older release of Windows where this context doesn't exist, DPI calls will
12-
// fail and Flutter rendering will be impacted until this is fixed.
13-
// To handle downlevel correctly, dpi_helper must use the most recent DPI
14-
// context available should be used: Windows 1703: Per-Monitor V2, 8.1:
15-
// Per-Monitor V1, Windows 7: System See
16-
// https://docs.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows
17-
// for more information.
18-
}
9+
Win32Window::Win32Window() {}
10+
1911
Win32Window::~Win32Window() {
2012
Destroy();
2113
}
@@ -26,7 +18,7 @@ void Win32Window::InitializeChild(const char* title,
2618
Destroy();
2719
std::wstring converted_title = NarrowToWide(title);
2820

29-
WNDCLASS window_class = ResgisterWindowClass(converted_title);
21+
WNDCLASS window_class = RegisterWindowClass(converted_title);
3022

3123
auto* result = CreateWindowEx(
3224
0, window_class.lpszClassName, converted_title.c_str(),
@@ -54,7 +46,7 @@ std::wstring Win32Window::NarrowToWide(const char* source) {
5446
return wideTitle;
5547
}
5648

57-
WNDCLASS Win32Window::ResgisterWindowClass(std::wstring& title) {
49+
WNDCLASS Win32Window::RegisterWindowClass(std::wstring& title) {
5850
window_class_name_ = title;
5951

6052
WNDCLASS window_class{};
@@ -82,14 +74,7 @@ LRESULT CALLBACK Win32Window::WndProc(HWND const window,
8274
reinterpret_cast<LONG_PTR>(cs->lpCreateParams));
8375

8476
auto that = static_cast<Win32Window*>(cs->lpCreateParams);
85-
86-
// Since the application is running in Per-monitor V2 mode, turn on
87-
// automatic titlebar scaling
88-
BOOL result = that->dpi_helper_->EnableNonClientDpiScaling(window);
89-
if (result != TRUE) {
90-
OutputDebugString(L"Failed to enable non-client area autoscaling");
91-
}
92-
that->current_dpi_ = that->dpi_helper_->GetDpiForWindow(window);
77+
that->current_dpi_ = that->dpi_helper_->GetDpi(window);
9378
that->window_handle_ = window;
9479
} else if (Win32Window* that = GetThisFromHandle(window)) {
9580
return that->MessageHandler(window, message, wparam, lparam);
@@ -282,7 +267,7 @@ Win32Window::HandleDpiChange(HWND hwnd,
282267
// The DPI is only passed for DPI change messages on top level windows,
283268
// hence call function to get DPI if needed.
284269
if (uDpi == 0) {
285-
uDpi = dpi_helper_->GetDpiForWindow(hwnd);
270+
uDpi = dpi_helper_->GetDpi(hwnd);
286271
}
287272
current_dpi_ = uDpi;
288273
window->OnDpiScale(uDpi);

shell/platform/windows/win32_window.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class Win32Window {
5757

5858
// Registers a window class with default style attributes, cursor and
5959
// icon.
60-
WNDCLASS ResgisterWindowClass(std::wstring& title);
60+
WNDCLASS RegisterWindowClass(std::wstring& title);
6161

6262
// OS callback called by message pump. Handles the WM_NCCREATE message which
6363
// is passed when the non-client area is being created and enables automatic

0 commit comments

Comments
 (0)