Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Gets the DPI for all awareness mode and older Windows versions #15951

Merged
merged 10 commits into from
Jan 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 30 additions & 31 deletions shell/platform/windows/win32_dpi_helper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ namespace flutter {

namespace {

constexpr UINT kDefaultDpi = 96;

template <typename T>
bool AssignProcAddress(HMODULE comBaseModule, const char* name, T*& outProc) {
outProc = reinterpret_cast<T*>(GetProcAddress(comBaseModule, name));
Expand All @@ -13,60 +15,57 @@ bool AssignProcAddress(HMODULE comBaseModule, const char* name, T*& outProc) {
} // namespace

Win32DpiHelper::Win32DpiHelper() {
// TODO ensure that this helper works correctly on downlevel builds.
user32_module_ = LoadLibraryA("User32.dll");
if (user32_module_ == nullptr) {
return;
}

if (!AssignProcAddress(user32_module_, "EnableNonClientDpiScaling",
enable_non_client_dpi_scaling_)) {
if (AssignProcAddress(user32_module_, "GetDpiForWindow",
get_dpi_for_window_)) {
dpi_for_window_supported_ = true;
return;
}

if (!AssignProcAddress(user32_module_, "GetDpiForWindow",
get_dpi_for_window_)) {
shlib_module_ = LoadLibraryA("Shcore.dll");
if (shlib_module_ == nullptr) {
return;
}

if (!AssignProcAddress(user32_module_, "SetProcessDpiAwarenessContext",
set_process_dpi_awareness_context_)) {
return;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SetProcessDpiAwarenessContext is the most recent version of the API.. any reason why you chose not to use this if available?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just removed it since it's not being used anywhere, and we would want the dpi awareness to be set by the runner app, in the manifest anyway. Is there any reason to keep it?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, yes good point :-)

if (AssignProcAddress(shlib_module_, "GetDpiForMonitor",
get_dpi_for_monitor_) &&
AssignProcAddress(user32_module_, "MonitorFromWindow",
monitor_from_window_)) {
dpi_for_monitor_supported_ = true;
}

permonitorv2_supported_ = true;
}

Win32DpiHelper::~Win32DpiHelper() {
if (user32_module_ != nullptr) {
FreeLibrary(user32_module_);
}
}

bool Win32DpiHelper::IsPerMonitorV2Available() {
return permonitorv2_supported_;
}

BOOL Win32DpiHelper::EnableNonClientDpiScaling(HWND hwnd) {
if (!permonitorv2_supported_) {
return false;
if (shlib_module_ != nullptr) {
FreeLibrary(shlib_module_);
}
return enable_non_client_dpi_scaling_(hwnd);
}

UINT Win32DpiHelper::GetDpiForWindow(HWND hwnd) {
if (!permonitorv2_supported_) {
return false;
UINT Win32DpiHelper::GetDpi(HWND hwnd) {
// GetDpiForWindow returns the DPI for any awareness mode. If not available,
// fallback to a per monitor, system, or default DPI.
if (dpi_for_window_supported_) {
return get_dpi_for_window_(hwnd);
}
return get_dpi_for_window_(hwnd);
}

BOOL Win32DpiHelper::SetProcessDpiAwarenessContext(
DPI_AWARENESS_CONTEXT context) {
if (!permonitorv2_supported_) {
return false;
if (dpi_for_monitor_supported_) {
HMONITOR monitor = monitor_from_window_(hwnd, MONITOR_DEFAULTTONEAREST);
UINT dpi_x = 0, dpi_y = 0;
HRESULT result =
get_dpi_for_monitor_(monitor, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y);
return SUCCEEDED(result) ? dpi_x : kDefaultDpi;
}
return set_process_dpi_awareness_context_(context);
}

HDC hdc = GetDC(hwnd);
UINT dpi = GetDeviceCaps(hdc, LOGPIXELSX);
ReleaseDC(hwnd, hdc);
return dpi;
}
} // namespace flutter
34 changes: 15 additions & 19 deletions shell/platform/windows/win32_dpi_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,38 +10,34 @@

namespace flutter {

// A helper class for abstracting various Windows DPI related functions across
// Windows OS versions.
/// A helper class for abstracting various Windows DPI related functions across
/// Windows OS versions.
class Win32DpiHelper {
public:
Win32DpiHelper();

~Win32DpiHelper();

// Check if Windows Per Monitor V2 DPI scaling functionality is available on
// current system.
bool IsPerMonitorV2Available();

// Wrapper for OS functionality to turn on automatic window non-client scaling
BOOL EnableNonClientDpiScaling(HWND);

// Wrapper for OS functionality to return the DPI for |HWND|
UINT GetDpiForWindow(HWND);

// Sets the current process to a specified DPI awareness context.
BOOL SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT);
/// Returns the current DPI. Supports all DPI awareness modes, and is backward
/// compatible down to Windows Vista.
UINT GetDpi(HWND);

private:
using EnableNonClientDpiScaling_ = BOOL __stdcall(HWND);
using GetDpiForWindow_ = UINT __stdcall(HWND);
using SetProcessDpiAwarenessContext_ = BOOL __stdcall(DPI_AWARENESS_CONTEXT);
using GetDpiForMonitor_ = HRESULT __stdcall(HMONITOR hmonitor,
MONITOR_DPI_TYPE dpiType,
UINT* dpiX,
UINT* dpiY);
using MonitorFromWindow_ = HMONITOR __stdcall(HWND hwnd, DWORD dwFlags);

EnableNonClientDpiScaling_* enable_non_client_dpi_scaling_ = nullptr;
GetDpiForWindow_* get_dpi_for_window_ = nullptr;
SetProcessDpiAwarenessContext_* set_process_dpi_awareness_context_ = nullptr;
GetDpiForMonitor_* get_dpi_for_monitor_ = nullptr;
MonitorFromWindow_* monitor_from_window_ = nullptr;

HMODULE user32_module_ = nullptr;
bool permonitorv2_supported_ = false;
HMODULE shlib_module_ = nullptr;
bool dpi_for_window_supported_ = false;
bool dpi_for_monitor_supported_ = false;
};

} // namespace flutter
Expand Down
27 changes: 6 additions & 21 deletions shell/platform/windows/win32_window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand All @@ -26,7 +18,7 @@ void Win32Window::InitializeChild(const char* title,
Destroy();
std::wstring converted_title = NarrowToWide(title);

WNDCLASS window_class = ResgisterWindowClass(converted_title);
WNDCLASS window_class = RegisterWindowClass(converted_title);

auto* result = CreateWindowEx(
0, window_class.lpszClassName, converted_title.c_str(),
Expand Down Expand Up @@ -54,7 +46,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{};
Expand Down Expand Up @@ -82,14 +74,7 @@ LRESULT CALLBACK Win32Window::WndProc(HWND const window,
reinterpret_cast<LONG_PTR>(cs->lpCreateParams));

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");
}
that->current_dpi_ = that->dpi_helper_->GetDpiForWindow(window);
that->current_dpi_ = that->dpi_helper_->GetDpi(window);
that->window_handle_ = window;
} else if (Win32Window* that = GetThisFromHandle(window)) {
return that->MessageHandler(window, message, wparam, lparam);
Expand Down Expand Up @@ -282,7 +267,7 @@ Win32Window::HandleDpiChange(HWND hwnd,
// The DPI is only passed for DPI change messages on top level windows,
// hence call function to get DPI if needed.
if (uDpi == 0) {
uDpi = dpi_helper_->GetDpiForWindow(hwnd);
uDpi = dpi_helper_->GetDpi(hwnd);
}
current_dpi_ = uDpi;
window->OnDpiScale(uDpi);
Expand Down
2 changes: 1 addition & 1 deletion shell/platform/windows/win32_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class Win32Window {

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

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