@@ -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.
5098void EnableFullDpiSupportIfAvailable (HWND hwnd) {
@@ -216,7 +264,7 @@ Win32Window::~Win32Window() {
216264}
217265
218266bool 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