Skip to content

Commit 4a924bd

Browse files
authored
Merge pull request flutter#12 from canonical/bugfix/window-size
Create windows that accomodate the requested client area
2 parents 0fe23c2 + ffc4bb6 commit 4a924bd

File tree

1 file changed

+73
-14
lines changed

1 file changed

+73
-14
lines changed

shell/platform/windows/client_wrapper/win32_window.cc

Lines changed: 73 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,54 @@ auto getLastErrorAsString() -> std::string {
4545
return oss.str();
4646
}
4747

48+
// Calculates the required window rectangle, in physical coordinates, that
49+
// will accomodate the requested client size given in logical coordinates.
50+
// The window rectangle accounts for window borders and non-client areas.
51+
auto calculateWindowRect(flutter::Win32Window::Size client_size,
52+
DWORD window_style,
53+
DWORD extended_window_style,
54+
UINT dpi) -> RECT {
55+
auto const scale_factor{static_cast<double>(dpi) / USER_DEFAULT_SCREEN_DPI};
56+
RECT rect{.left = 0,
57+
.top = 0,
58+
.right = static_cast<LONG>(client_size.width * scale_factor),
59+
.bottom = static_cast<LONG>(client_size.height * scale_factor)};
60+
61+
HMODULE const user32_module{LoadLibraryA("User32.dll")};
62+
if (user32_module) {
63+
using AdjustWindowRectExForDpi = BOOL __stdcall(
64+
LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi);
65+
66+
auto* const adjust_window_rect_ext_for_dpi{
67+
reinterpret_cast<AdjustWindowRectExForDpi*>(
68+
GetProcAddress(user32_module, "AdjustWindowRectExForDpi"))};
69+
if (adjust_window_rect_ext_for_dpi) {
70+
if (adjust_window_rect_ext_for_dpi(&rect, window_style, FALSE,
71+
extended_window_style, dpi)) {
72+
FreeLibrary(user32_module);
73+
return rect;
74+
} else {
75+
std::cerr << "Failed to run AdjustWindowRectExForDpi: "
76+
<< getLastErrorAsString() << '\n';
77+
}
78+
} else {
79+
std::cerr << "Failed to retrieve AdjustWindowRectExForDpi address from "
80+
"User32.dll.\n";
81+
}
82+
FreeLibrary(user32_module);
83+
} else {
84+
std::cerr << "Failed to load User32.dll.\n";
85+
}
86+
87+
if (!AdjustWindowRectEx(&rect, window_style, FALSE, extended_window_style)) {
88+
std::cerr << "Failed to run AdjustWindowRectEx: " << getLastErrorAsString()
89+
<< '\n';
90+
return rect;
91+
}
92+
93+
return rect;
94+
}
95+
4896
// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module.
4997
// This API is only needed for PerMonitor V1 awareness mode.
5098
void EnableFullDpiSupportIfAvailable(HWND hwnd) {
@@ -216,7 +264,7 @@ Win32Window::~Win32Window() {
216264
}
217265

218266
bool Win32Window::Create(std::wstring const& title,
219-
Size const& size,
267+
Size const& client_size,
220268
FlutterWindowArchetype archetype,
221269
std::optional<Point> origin,
222270
std::optional<HWND> parent) {
@@ -274,7 +322,11 @@ bool Win32Window::Create(std::wstring const& title,
274322
auto const* window_class{
275323
WindowClassRegistrar::GetInstance()->GetWindowClass()};
276324

277-
auto const dpi{[&origin]() -> double {
325+
// Get the DPI for the monitor that is nearest to the specified origin point.
326+
// If no origin point is provided, use the monitor that is nearest to the
327+
// currently active window. If no active window is found, fall back to the
328+
// monitor that contains the point (0, 0).
329+
auto const dpi{[&origin]() -> UINT {
278330
auto const monitor{[&]() -> HMONITOR {
279331
if (origin) {
280332
POINT const target_point{static_cast<LONG>(origin->x),
@@ -289,28 +341,35 @@ bool Win32Window::Create(std::wstring const& title,
289341
return MonitorFromPoint({0, 0}, MONITOR_DEFAULTTOPRIMARY);
290342
}
291343
}()};
292-
return static_cast<double>(FlutterDesktopGetDpiForMonitor(monitor));
344+
return FlutterDesktopGetDpiForMonitor(monitor);
293345
}()};
294-
auto const scale_factor{dpi / USER_DEFAULT_SCREEN_DPI};
295-
296-
// Scale helper to convert logical scaler values to physical using passed in
297-
// scale factor
298-
auto const scale{[](int source, double scale_factor) {
299-
return static_cast<int>(source * scale_factor);
300-
}};
301346

347+
// Compute the x and y coordinates of the window, in physical coordinates.
348+
// Default positioning values (CW_USEDEFAULT) are used if the window
349+
// has no parent or if the origin point is not provided.
302350
auto const [x, y]{[&]() -> std::tuple<int, int> {
303351
if (parent && origin) {
304-
return {scale(static_cast<LONG>(origin->x), scale_factor),
305-
scale(static_cast<LONG>(origin->y), scale_factor)};
352+
auto const scale_factor{static_cast<double>(dpi) /
353+
USER_DEFAULT_SCREEN_DPI};
354+
return {static_cast<int>(origin->x * scale_factor),
355+
static_cast<int>(origin->y * scale_factor)};
306356
}
307357
return {CW_USEDEFAULT, CW_USEDEFAULT};
308358
}()};
309359

360+
// Get the physical coordinates of the top-left and bottom-right corners
361+
// of the window to accomodate the desired client area
362+
auto const window_size{[&]() -> SIZE {
363+
auto const window_rect{calculateWindowRect(client_size, window_style,
364+
extended_window_style, dpi)};
365+
return {window_rect.right - window_rect.left,
366+
window_rect.bottom - window_rect.top};
367+
}()};
368+
310369
auto const window{CreateWindowEx(
311370
extended_window_style, window_class, title.c_str(), window_style, x, y,
312-
scale(size.width, scale_factor), scale(size.height, scale_factor),
313-
parent.value_or(nullptr), nullptr, GetModuleHandle(nullptr), this)};
371+
window_size.cx, window_size.cy, parent.value_or(nullptr), nullptr,
372+
GetModuleHandle(nullptr), this)};
314373

315374
if (!window) {
316375
auto const error_message{getLastErrorAsString()};

0 commit comments

Comments
 (0)