-
Notifications
You must be signed in to change notification settings - Fork 6k
Adds Support for system dpi awareness for older versions of Windows #12735
Changes from 3 commits
b4f720e
e6db1e6
c9b6c58
a1ff82e
924e8ce
2b900a0
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 |
|---|---|---|
| @@ -1,5 +1,7 @@ | ||
| #include "flutter/shell/platform/windows/win32_dpi_helper.h" | ||
|
|
||
| #include <iostream> | ||
|
|
||
| namespace flutter { | ||
|
|
||
| namespace { | ||
|
|
@@ -18,7 +20,6 @@ Win32DpiHelper::Win32DpiHelper() { | |
| if (user32_module_ == nullptr) { | ||
| return; | ||
| } | ||
|
|
||
| if (!AssignProcAddress(user32_module_, "EnableNonClientDpiScaling", | ||
| enable_non_client_dpi_scaling_)) { | ||
| return; | ||
|
|
@@ -33,7 +34,6 @@ Win32DpiHelper::Win32DpiHelper() { | |
| set_process_dpi_awareness_context_)) { | ||
| return; | ||
| } | ||
|
|
||
| permonitorv2_supported_ = true; | ||
| } | ||
|
|
||
|
|
@@ -43,6 +43,20 @@ Win32DpiHelper::~Win32DpiHelper() { | |
| } | ||
| } | ||
|
|
||
| void Win32DpiHelper::SetDpiAwerenessAllVersions() { | ||
| if (permonitorv2_supported_) { | ||
| SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); | ||
| } else { | ||
| std::cerr << "Per Monitor V2 DPI awareness is not supported on this " | ||
| "version of Windows. Setting System DPI awareness\n"; | ||
| AssignProcAddress(user32_module_, "GetDpiForSystem", get_dpi_for_system_); | ||
| AssignProcAddress(user32_module_, "SetProcessDpiAware", | ||
| set_process_dpi_aware_); | ||
|
|
||
| SetProcessDPIAware(); | ||
|
||
| } | ||
| } | ||
|
|
||
| bool Win32DpiHelper::IsPerMonitorV2Available() { | ||
| return permonitorv2_supported_; | ||
| } | ||
|
|
@@ -61,6 +75,10 @@ UINT Win32DpiHelper::GetDpiForWindow(HWND hwnd) { | |
| return get_dpi_for_window_(hwnd); | ||
| } | ||
|
|
||
| UINT Win32DpiHelper::GetDpiForSystem() { | ||
| return get_dpi_for_system_(); | ||
| } | ||
|
|
||
| BOOL Win32DpiHelper::SetProcessDpiAwarenessContext( | ||
| DPI_AWARENESS_CONTEXT context) { | ||
| if (!permonitorv2_supported_) { | ||
|
|
@@ -69,4 +87,8 @@ BOOL Win32DpiHelper::SetProcessDpiAwarenessContext( | |
| return set_process_dpi_awareness_context_(context); | ||
| } | ||
|
|
||
| BOOL Win32DpiHelper::SetProcessDpiAware() { | ||
| return set_process_dpi_aware_(); | ||
| } | ||
|
|
||
| } // namespace flutter | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,17 +28,35 @@ class Win32DpiHelper { | |
| // Wrapper for OS functionality to return the DPI for |HWND| | ||
| UINT GetDpiForWindow(HWND); | ||
|
|
||
| // Wrapper for OS functionality to return the DPI for the System. Only used if | ||
| // Per Monitor V2 is not supported by the current Windows version. | ||
| UINT GetDpiForSystem(); | ||
|
||
|
|
||
| // Sets the current process to a specified DPI awareness context. | ||
| BOOL SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT); | ||
|
||
|
|
||
| // Sets the current process to System-level DPI awareness. | ||
| BOOL SetProcessDpiAware(); | ||
|
|
||
| // Sets the DPI awareness for the application. For versions >= Windows 1703, | ||
| // use Per Monitor V2. For any older versions, use System. | ||
| // | ||
| // This call is overriden if DPI awareness is stated in the application | ||
| // manifest. | ||
| void SetDpiAwerenessAllVersions(); | ||
|
||
|
|
||
| private: | ||
| using EnableNonClientDpiScaling_ = BOOL __stdcall(HWND); | ||
| using GetDpiForWindow_ = UINT __stdcall(HWND); | ||
| using SetProcessDpiAwarenessContext_ = BOOL __stdcall(DPI_AWARENESS_CONTEXT); | ||
| using SetProcessDpiAware_ = BOOL __stdcall(); | ||
| using GetDpiForSystem_ = UINT __stdcall(); | ||
|
|
||
| EnableNonClientDpiScaling_* enable_non_client_dpi_scaling_ = nullptr; | ||
| GetDpiForWindow_* get_dpi_for_window_ = nullptr; | ||
| SetProcessDpiAwarenessContext_* set_process_dpi_awareness_context_ = nullptr; | ||
| SetProcessDpiAware_* set_process_dpi_aware_ = nullptr; | ||
| GetDpiForSystem_* get_dpi_for_system_ = nullptr; | ||
|
|
||
| HMODULE user32_module_ = nullptr; | ||
| bool permonitorv2_supported_ = false; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,16 +6,8 @@ | |
|
|
||
| namespace flutter { | ||
|
|
||
| Win32Window::Win32Window() { | ||
| // Assume Windows 10 1703 or greater for DPI handling. When running on a | ||
| // older release of Windows where this context doesn't exist, DPI calls will | ||
| // fail and Flutter rendering will be impacted until this is fixed. | ||
| // To handle downlevel correctly, dpi_helper must use the most recent DPI | ||
| // context available should be used: Windows 1703: Per-Monitor V2, 8.1: | ||
| // Per-Monitor V1, Windows 7: System See | ||
| // https://docs.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows | ||
| // for more information. | ||
| } | ||
| Win32Window::Win32Window() {} | ||
|
|
||
| Win32Window::~Win32Window() { | ||
| Destroy(); | ||
| } | ||
|
|
@@ -26,7 +18,11 @@ void Win32Window::InitializeChild(const char* title, | |
| Destroy(); | ||
| std::wstring converted_title = NarrowToWide(title); | ||
|
|
||
| WNDCLASS window_class = ResgisterWindowClass(converted_title); | ||
| // Set DPI awareness for all Windows versions. This call has to be made before | ||
| // the HWND is created. | ||
| dpi_helper_->SetDpiAwerenessAllVersions(); | ||
|
||
|
|
||
| WNDCLASS window_class = RegisterWindowClass(converted_title); | ||
|
|
||
| auto* result = CreateWindowEx( | ||
| 0, window_class.lpszClassName, converted_title.c_str(), | ||
|
|
@@ -54,7 +50,7 @@ std::wstring Win32Window::NarrowToWide(const char* source) { | |
| return wideTitle; | ||
| } | ||
|
|
||
| WNDCLASS Win32Window::ResgisterWindowClass(std::wstring& title) { | ||
| WNDCLASS Win32Window::RegisterWindowClass(std::wstring& title) { | ||
| window_class_name_ = title; | ||
|
|
||
| WNDCLASS window_class{}; | ||
|
|
@@ -83,13 +79,17 @@ LRESULT CALLBACK Win32Window::WndProc(HWND const window, | |
|
|
||
| auto that = static_cast<Win32Window*>(cs->lpCreateParams); | ||
|
|
||
| // Since the application is running in Per-monitor V2 mode, turn on | ||
| // automatic titlebar scaling | ||
| BOOL result = that->dpi_helper_->EnableNonClientDpiScaling(window); | ||
| if (result != TRUE) { | ||
| OutputDebugString(L"Failed to enable non-client area autoscaling"); | ||
| if (that->dpi_helper_->IsPerMonitorV2Available()) { | ||
|
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. Assuming you move the DPI mode setting logic into the client app, this would become a getter for the current DPI mode |
||
| // Since the application is running in Per-monitor V2 mode, turn on | ||
| // automatic titlebar scaling | ||
| BOOL result = that->dpi_helper_->EnableNonClientDpiScaling(window); | ||
| if (result != TRUE) { | ||
| OutputDebugString(L"Failed to enable non-client area autoscaling"); | ||
| } | ||
| that->current_dpi_ = that->dpi_helper_->GetDpiForWindow(window); | ||
| } else { | ||
| that->current_dpi_ = that->dpi_helper_->GetDpiForSystem(); | ||
| } | ||
| that->current_dpi_ = that->dpi_helper_->GetDpiForWindow(window); | ||
| that->window_handle_ = window; | ||
| } else if (Win32Window* that = GetThisFromHandle(window)) { | ||
| return that->MessageHandler(window, message, wparam, lparam); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this logged? It's not an error case, unless I'm not understanding the PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw it as more of a fringe case, but it's true it's not an error. Makes sense to remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done