diff --git a/example/windows/Runner.vcxproj b/example/windows/Runner.vcxproj index 220e5414a..3830d4177 100644 --- a/example/windows/Runner.vcxproj +++ b/example/windows/Runner.vcxproj @@ -99,7 +99,7 @@ 4100 - flutter_windows.dll.lib;Shcore.lib;%(AdditionalDependencies) + flutter_windows.dll.lib;%(AdditionalDependencies) @@ -197,7 +197,7 @@ true true - flutter_windows.dll.lib;Shcore.lib;%(AdditionalDependencies) + flutter_windows.dll.lib;%(AdditionalDependencies) diff --git a/example/windows/runner.exe.manifest b/example/windows/runner.exe.manifest index 41208def9..c977c4a42 100644 --- a/example/windows/runner.exe.manifest +++ b/example/windows/runner.exe.manifest @@ -17,4 +17,4 @@ - \ No newline at end of file + diff --git a/example/windows/win32_window.cc b/example/windows/win32_window.cc index 429216236..4c0a33c8c 100644 --- a/example/windows/win32_window.cc +++ b/example/windows/win32_window.cc @@ -4,33 +4,41 @@ #include "win32_window.h" +#include + #include "resource.h" -#include "shellscalingapi.h" namespace { -// the Windows DPI system is based on this +// The Windows DPI system is based on this // constant for machines running at 100% scaling. constexpr int kBaseDpi = 96; constexpr const wchar_t kClassName[] = L"CLASSNAME"; +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + // Scale helper to convert logical scaler values to physical using passed in // scale factor int Scale(int source, double scale_factor) { return static_cast(source * scale_factor); } -// Returns the DPI for the monitor containing, or closest to, |point|. -UINT GetDpiForMonitorAtPoint(const Win32Window::Point &point) { - const POINT target_point = {static_cast(point.x), - static_cast(point.y)}; - HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); - UINT dpi_x = 0, dpi_y = 0; - GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y); - return dpi_x; -} +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + + enable_non_client_dpi_scaling(hwnd); + FreeLibrary(user32_module); +} } // namespace Win32Window::Win32Window() {} @@ -43,8 +51,11 @@ bool Win32Window::CreateAndShow(const std::wstring &title, const Point &origin, WNDCLASS window_class = RegisterWindowClass(); - double scale_factor = - static_cast(GetDpiForMonitorAtPoint(origin)) / kBaseDpi; + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / kBaseDpi; HWND window = CreateWindow( window_class.lpszClassName, title.c_str(), @@ -81,6 +92,7 @@ LRESULT CALLBACK Win32Window::WndProc(HWND const window, UINT const message, reinterpret_cast(window_struct->lpCreateParams)); auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); that->window_handle_ = window; } else if (Win32Window *that = GetThisFromHandle(window)) { return that->MessageHandler(window, message, wparam, lparam); @@ -105,6 +117,16 @@ Win32Window::MessageHandler(HWND hwnd, UINT const message, WPARAM const wparam, Destroy(); return 0; + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } case WM_SIZE: RECT rect; GetClientRect(hwnd, &rect); diff --git a/plugins/window_size/windows/plugin.vcxproj b/plugins/window_size/windows/plugin.vcxproj index 8cc0adedc..fcc79f3ae 100644 --- a/plugins/window_size/windows/plugin.vcxproj +++ b/plugins/window_size/windows/plugin.vcxproj @@ -111,7 +111,7 @@ Windows true - flutter_windows.dll.lib;Shcore.lib;%(AdditionalDependencies) + flutter_windows.dll.lib;%(AdditionalDependencies) @@ -199,7 +199,7 @@ true true true - flutter_windows.dll.lib;Shcore.lib;%(AdditionalDependencies) + flutter_windows.dll.lib;%(AdditionalDependencies) diff --git a/plugins/window_size/windows/window_size_plugin.cpp b/plugins/window_size/windows/window_size_plugin.cpp index 40febb408..cac5b3ce8 100644 --- a/plugins/window_size/windows/window_size_plugin.cpp +++ b/plugins/window_size/windows/window_size_plugin.cpp @@ -13,12 +13,16 @@ // limitations under the License. #include "window_size_plugin.h" -#include +// windows.h must be imported before VersionHelpers.h or it will break +// compilation. +#include + +#include #include #include #include #include -#include +#include #include #include @@ -65,9 +69,8 @@ EncodableValue GetPlatformChannelRepresentationForMonitor(HMONITOR monitor) { MONITORINFO info; info.cbSize = sizeof(MONITORINFO); GetMonitorInfo(monitor, &info); - UINT dpi_x, dpi_y; - GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y); - double scale_factor = dpi_x / kBaseDpi; + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / kBaseDpi; return EncodableValue(EncodableMap{ {EncodableValue(kFrameKey), GetPlatformChannelRepresentationForRect(info.rcMonitor)}, @@ -94,8 +97,7 @@ EncodableValue GetPlatformChannelRepresentationForWindow(HWND window) { RECT frame; GetWindowRect(window, &frame); HMONITOR window_monitor = MonitorFromWindow(window, MONITOR_DEFAULTTOPRIMARY); - // TODO: Support fallback for systems older than Windows 10(1607). - double scale_factor = GetDpiForWindow(window) / kBaseDpi; + double scale_factor = FlutterDesktopGetDpiForHWND(window) / kBaseDpi; return EncodableValue(EncodableMap{ {EncodableValue(kFrameKey), diff --git a/testbed/windows/Runner.vcxproj b/testbed/windows/Runner.vcxproj index 220e5414a..3830d4177 100644 --- a/testbed/windows/Runner.vcxproj +++ b/testbed/windows/Runner.vcxproj @@ -99,7 +99,7 @@ 4100 - flutter_windows.dll.lib;Shcore.lib;%(AdditionalDependencies) + flutter_windows.dll.lib;%(AdditionalDependencies) @@ -197,7 +197,7 @@ true true - flutter_windows.dll.lib;Shcore.lib;%(AdditionalDependencies) + flutter_windows.dll.lib;%(AdditionalDependencies) diff --git a/testbed/windows/runner.exe.manifest b/testbed/windows/runner.exe.manifest index 41208def9..c977c4a42 100644 --- a/testbed/windows/runner.exe.manifest +++ b/testbed/windows/runner.exe.manifest @@ -17,4 +17,4 @@ - \ No newline at end of file + diff --git a/testbed/windows/win32_window.cc b/testbed/windows/win32_window.cc index 429216236..86b94705c 100644 --- a/testbed/windows/win32_window.cc +++ b/testbed/windows/win32_window.cc @@ -4,8 +4,9 @@ #include "win32_window.h" +#include + #include "resource.h" -#include "shellscalingapi.h" namespace { @@ -15,22 +16,29 @@ constexpr int kBaseDpi = 96; constexpr const wchar_t kClassName[] = L"CLASSNAME"; +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + // Scale helper to convert logical scaler values to physical using passed in // scale factor int Scale(int source, double scale_factor) { return static_cast(source * scale_factor); } -// Returns the DPI for the monitor containing, or closest to, |point|. -UINT GetDpiForMonitorAtPoint(const Win32Window::Point &point) { - const POINT target_point = {static_cast(point.x), - static_cast(point.y)}; - HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); - UINT dpi_x = 0, dpi_y = 0; - GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y); - return dpi_x; -} +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + + enable_non_client_dpi_scaling(hwnd); + FreeLibrary(user32_module); +} } // namespace Win32Window::Win32Window() {} @@ -43,8 +51,11 @@ bool Win32Window::CreateAndShow(const std::wstring &title, const Point &origin, WNDCLASS window_class = RegisterWindowClass(); - double scale_factor = - static_cast(GetDpiForMonitorAtPoint(origin)) / kBaseDpi; + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / kBaseDpi; HWND window = CreateWindow( window_class.lpszClassName, title.c_str(), @@ -81,6 +92,7 @@ LRESULT CALLBACK Win32Window::WndProc(HWND const window, UINT const message, reinterpret_cast(window_struct->lpCreateParams)); auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); that->window_handle_ = window; } else if (Win32Window *that = GetThisFromHandle(window)) { return that->MessageHandler(window, message, wparam, lparam); @@ -105,6 +117,16 @@ Win32Window::MessageHandler(HWND hwnd, UINT const message, WPARAM const wparam, Destroy(); return 0; + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } case WM_SIZE: RECT rect; GetClientRect(hwnd, &rect);