@@ -45,6 +45,54 @@ auto getLastErrorAsString() -> std::string {
45
45
return oss.str ();
46
46
}
47
47
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
+
48
96
// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module.
49
97
// This API is only needed for PerMonitor V1 awareness mode.
50
98
void EnableFullDpiSupportIfAvailable (HWND hwnd) {
@@ -216,7 +264,7 @@ Win32Window::~Win32Window() {
216
264
}
217
265
218
266
bool Win32Window::Create (std::wstring const & title,
219
- Size const & size ,
267
+ Size const & client_size ,
220
268
FlutterWindowArchetype archetype,
221
269
std::optional<Point > origin,
222
270
std::optional<HWND> parent) {
@@ -274,7 +322,11 @@ bool Win32Window::Create(std::wstring const& title,
274
322
auto const * window_class{
275
323
WindowClassRegistrar::GetInstance ()->GetWindowClass ()};
276
324
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 {
278
330
auto const monitor{[&]() -> HMONITOR {
279
331
if (origin) {
280
332
POINT const target_point{static_cast <LONG>(origin->x ),
@@ -289,28 +341,35 @@ bool Win32Window::Create(std::wstring const& title,
289
341
return MonitorFromPoint ({0 , 0 }, MONITOR_DEFAULTTOPRIMARY);
290
342
}
291
343
}()};
292
- return static_cast < double >( FlutterDesktopGetDpiForMonitor (monitor) );
344
+ return FlutterDesktopGetDpiForMonitor (monitor);
293
345
}()};
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
- }};
301
346
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.
302
350
auto const [x, y]{[&]() -> std::tuple<int , int > {
303
351
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)};
306
356
}
307
357
return {CW_USEDEFAULT, CW_USEDEFAULT};
308
358
}()};
309
359
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
+
310
369
auto const window{CreateWindowEx (
311
370
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 )};
314
373
315
374
if (!window) {
316
375
auto const error_message{getLastErrorAsString ()};
0 commit comments