| Flutter Windows Embedder |

host_window.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "flutter/shell/platform/windows/host_window.h"
6 #include "flutter/shell/platform/windows/host_window_dialog.h"
7 #include "flutter/shell/platform/windows/host_window_regular.h"
8 #include "flutter/shell/platform/windows/host_window_tooltip.h"
9
10 #include <dwmapi.h>
11
12 #include "flutter/shell/platform/windows/display_manager.h"
13 #include "flutter/shell/platform/windows/dpi_utils.h"
14 #include "flutter/shell/platform/windows/flutter_window.h"
15 #include "flutter/shell/platform/windows/flutter_windows_view_controller.h"
16 #include "flutter/shell/platform/windows/rect_helper.h"
17 #include "flutter/shell/platform/windows/wchar_util.h"
18 #include "flutter/shell/platform/windows/window_manager.h"
19
20 namespace {
21
22 constexpr wchar_t kWindowClassName[] = L"FLUTTER_HOST_WINDOW";
23
24 // Clamps |size| to the size of the virtual screen. Both the parameter and
25 // return size are in physical coordinates.
26 flutter::Size ClampToVirtualScreen(flutter::Size size) {
27 double const virtual_screen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
28 double const virtual_screen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
29
30 return flutter::Size(std::clamp(size.width(), 0.0, virtual_screen_width),
31 std::clamp(size.height(), 0.0, virtual_screen_height));
32 }
33
34 void EnableTransparentWindowBackground(HWND hwnd,
35 flutter::WindowsProcTable const& win32) {
36 enum ACCENT_STATE { ACCENT_DISABLED = 0 };
37
38 struct ACCENT_POLICY {
39 ACCENT_STATE AccentState;
40 DWORD AccentFlags;
41 DWORD GradientColor;
42 DWORD AnimationId;
43 };
44
45 // Set the accent policy to disable window composition.
46 ACCENT_POLICY accent = {ACCENT_DISABLED, 2, static_cast<DWORD>(0), 0};
47 flutter::WindowsProcTable::WINDOWCOMPOSITIONATTRIBDATA data = {
48 .Attrib =
49 flutter::WindowsProcTable::WINDOWCOMPOSITIONATTRIB::WCA_ACCENT_POLICY,
50 .pvData = &accent,
51 .cbData = sizeof(accent)};
52 win32.SetWindowCompositionAttribute(hwnd, &data);
53
54 // Extend the frame into the client area and set the window's system
55 // backdrop type for visual effects.
56 MARGINS const margins = {-1};
57 win32.DwmExtendFrameIntoClientArea(hwnd, &margins);
58 INT effect_value = 1;
59 win32.DwmSetWindowAttribute(hwnd, DWMWA_SYSTEMBACKDROP_TYPE, &effect_value,
60 sizeof(BOOL));
61 }
62
63 // Retrieves the calling thread's last-error code message as a string,
64 // or a fallback message if the error message cannot be formatted.
65 std::string GetLastErrorAsString() {
66 LPWSTR message_buffer = nullptr;
67
68 if (DWORD const size = FormatMessage(
69 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
70 FORMAT_MESSAGE_IGNORE_INSERTS,
71 nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
72 reinterpret_cast<LPTSTR>(&message_buffer), 0, nullptr)) {
73 std::wstring const wide_message(message_buffer, size);
74 LocalFree(message_buffer);
75 message_buffer = nullptr;
76
77 if (int const buffer_size =
78 WideCharToMultiByte(CP_UTF8, 0, wide_message.c_str(), -1, nullptr,
79 0, nullptr, nullptr)) {
80 std::string message(buffer_size, 0);
81 WideCharToMultiByte(CP_UTF8, 0, wide_message.c_str(), -1, &message[0],
82 buffer_size, nullptr, nullptr);
83 return message;
84 }
85 }
86
87 if (message_buffer) {
88 LocalFree(message_buffer);
89 }
90 std::ostringstream oss;
91 oss << "Format message failed with 0x" << std::hex << std::setfill('0')
92 << std::setw(8) << GetLastError();
93 return oss.str();
94 }
95
96 // Checks whether the window class of name |class_name| is registered for the
97 // current application.
98 bool IsClassRegistered(LPCWSTR class_name) {
99 WNDCLASSEX window_class = {};
100 return GetClassInfoEx(GetModuleHandle(nullptr), class_name, &window_class) !=
101 0;
102 }
103
104 // Window attribute that enables dark mode window decorations.
105 //
106 // Redefined in case the developer's machine has a Windows SDK older than
107 // version 10.0.22000.0.
108 // See:
109 // https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
110 #ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
111 #define DWMWA_USE_IMMERSIVE_DARK_MODE 20
112 #endif
113
114 // Updates the window frame's theme to match the system theme.
115 void UpdateTheme(HWND window) {
116 // Registry key for app theme preference.
117 const wchar_t kGetPreferredBrightnessRegKey[] =
118 L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
119 const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme";
120
121 // A value of 0 indicates apps should use dark mode. A non-zero or missing
122 // value indicates apps should use light mode.
123 DWORD light_mode;
124 DWORD light_mode_size = sizeof(light_mode);
125 LSTATUS const result =
126 RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey,
127 kGetPreferredBrightnessRegValue, RRF_RT_REG_DWORD, nullptr,
128 &light_mode, &light_mode_size);
129
130 if (result == ERROR_SUCCESS) {
131 BOOL enable_dark_mode = light_mode == 0;
132 DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE,
133 &enable_dark_mode, sizeof(enable_dark_mode));
134 }
135 }
136
137 // Inserts |content| into the window tree.
138 void SetChildContent(HWND content, HWND window) {
139 SetParent(content, window);
140 RECT client_rect;
141 GetClientRect(window, &client_rect);
142 MoveWindow(content, client_rect.left, client_rect.top,
143 client_rect.right - client_rect.left,
144 client_rect.bottom - client_rect.top, true);
145 }
146
147 // Adjusts a 1D segment (defined by origin and size) to fit entirely within
148 // a destination segment. If the segment is larger than the destination, it is
149 // first shrunk to fit. Then, it's shifted to be within the bounds.
150 //
151 // Let the destination be "{...}" and the segment to adjust be "[...]".
152 //
153 // Case 1: The segment sticks out to the right.
154 //
155 // Before: {------[----}------]
156 // After: {------[----]}
157 //
158 // Case 2: The segment sticks out to the left.
159 //
160 // Before: [------{----]------}
161 // After: {[----]------}
162 void AdjustAlongAxis(LONG dst_origin, LONG dst_size, LONG* origin, LONG* size) {
163 *size = std::min(dst_size, *size);
164 if (*origin < dst_origin)
165 *origin = dst_origin;
166 else
167 *origin = std::min(dst_origin + dst_size, *origin + *size) - *size;
168 }
169
170 RECT AdjustToFit(const RECT& parent, const RECT& child) {
171 auto new_x = child.left;
172 auto new_y = child.top;
173 auto new_width = flutter::RectWidth(child);
174 auto new_height = flutter::RectHeight(child);
175 AdjustAlongAxis(parent.left, flutter::RectWidth(parent), &new_x, &new_width);
176 AdjustAlongAxis(parent.top, flutter::RectHeight(parent), &new_y, &new_height);
177 RECT result;
178 result.left = new_x;
179 result.right = new_x + new_width;
180 result.top = new_y;
181 result.bottom = new_y + new_height;
182 return result;
183 }
184
185 flutter::BoxConstraints FromWindowConstraints(
186 const flutter::WindowConstraints& preferred_constraints) {
187 std::optional<flutter::Size> smallest, biggest;
188 if (preferred_constraints.has_view_constraints) {
189 smallest = flutter::Size(preferred_constraints.view_min_width,
190 preferred_constraints.view_min_height);
191 if (preferred_constraints.view_max_width > 0 &&
192 preferred_constraints.view_max_height > 0) {
193 biggest = flutter::Size(preferred_constraints.view_max_width,
194 preferred_constraints.view_max_height);
195 }
196 }
197
198 return flutter::BoxConstraints(smallest, biggest);
199 }
200
201 } // namespace
202
203 namespace flutter {
204
205 std::unique_ptr<HostWindow> HostWindow::CreateRegularWindow(
206 WindowManager* window_manager,
207 FlutterWindowsEngine* engine,
208 const WindowSizeRequest& preferred_size,
209 const WindowConstraints& preferred_constraints,
210 LPCWSTR title) {
211 return std::unique_ptr<HostWindow>(new HostWindowRegular(
212 window_manager, engine, preferred_size,
213 FromWindowConstraints(preferred_constraints), title));
214 }
215
216 std::unique_ptr<HostWindow> HostWindow::CreateDialogWindow(
217 WindowManager* window_manager,
218 FlutterWindowsEngine* engine,
219 const WindowSizeRequest& preferred_size,
220 const WindowConstraints& preferred_constraints,
221 LPCWSTR title,
222 HWND parent) {
223 return std::unique_ptr<HostWindow>(
224 new HostWindowDialog(window_manager, engine, preferred_size,
225 FromWindowConstraints(preferred_constraints), title,
226 parent ? parent : std::optional<HWND>()));
227 }
228
229 std::unique_ptr<HostWindow> HostWindow::CreateTooltipWindow(
230 WindowManager* window_manager,
231 FlutterWindowsEngine* engine,
232 const WindowConstraints& preferred_constraints,
233 bool is_sized_to_content,
234 GetWindowPositionCallback get_position_callback,
235 HWND parent) {
236 return std::unique_ptr<HostWindowTooltip>(new HostWindowTooltip(
237 window_manager, engine, FromWindowConstraints(preferred_constraints),
238 is_sized_to_content, get_position_callback, parent));
239 }
240
241 HostWindow::HostWindow(WindowManager* window_manager,
242 FlutterWindowsEngine* engine)
243 : window_manager_(window_manager), engine_(engine) {}
244
245 void HostWindow::InitializeFlutterView(
246 HostWindowInitializationParams const& params) {
247 // Set up the view.
248 auto view_window = std::make_unique<FlutterWindow>(
249 params.initial_window_rect.width(), params.initial_window_rect.height(),
250 engine_->display_manager(), engine_->windows_proc_table());
251
252 std::unique_ptr<FlutterWindowsView> view =
253 engine_->CreateView(std::move(view_window), params.is_sized_to_content,
254 params.box_constraints, params.sizing_delegate);
255 FML_CHECK(view != nullptr);
256
257 view_controller_ =
258 std::make_unique<FlutterWindowsViewController>(nullptr, std::move(view));
259 FML_CHECK(engine_->running());
260 // The Windows embedder listens to accessibility updates using the
261 // view's HWND. The embedder's accessibility features may be stale if
262 // the app was in headless mode.
263 engine_->UpdateAccessibilityFeatures();
264
265 // Register the window class.
266 if (!IsClassRegistered(kWindowClassName)) {
267 auto const idi_app_icon = 101;
268 WNDCLASSEX window_class = {};
269 window_class.cbSize = sizeof(WNDCLASSEX);
270 window_class.style = CS_HREDRAW | CS_VREDRAW;
271 window_class.lpfnWndProc = HostWindow::WndProc;
272 window_class.hInstance = GetModuleHandle(nullptr);
273 window_class.hIcon =
274 LoadIcon(window_class.hInstance, MAKEINTRESOURCE(idi_app_icon));
275 if (!window_class.hIcon) {
276 window_class.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
277 }
278 window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
279 window_class.lpszClassName = kWindowClassName;
280
281 FML_CHECK(RegisterClassEx(&window_class));
282 }
283
284 // Create the native window.
285 window_handle_ = CreateWindowEx(
286 params.extended_window_style, kWindowClassName, params.title,
287 params.window_style, params.initial_window_rect.left(),
288 params.initial_window_rect.top(), params.initial_window_rect.width(),
289 params.initial_window_rect.height(),
290 params.owner_window ? *params.owner_window : nullptr, nullptr,
291 GetModuleHandle(nullptr), engine_->windows_proc_table().get());
292 FML_CHECK(window_handle_ != nullptr);
293
294 // Adjust the window position so its origin aligns with the top-left corner
295 // of the window frame, not the window rectangle (which includes the
296 // drop-shadow). This adjustment must be done post-creation since the frame
297 // rectangle is only available after the window has been created.
298 RECT frame_rect;
299 DwmGetWindowAttribute(window_handle_, DWMWA_EXTENDED_FRAME_BOUNDS,
300 &frame_rect, sizeof(frame_rect));
301 RECT window_rect;
302 GetWindowRect(window_handle_, &window_rect);
303 LONG const left_dropshadow_width = frame_rect.left - window_rect.left;
304 LONG const top_dropshadow_height = window_rect.top - frame_rect.top;
305 SetWindowPos(window_handle_, nullptr,
306 window_rect.left - left_dropshadow_width,
307 window_rect.top - top_dropshadow_height, 0, 0,
308 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
309
310 UpdateTheme(window_handle_);
311
312 SetChildContent(view_controller_->view()->GetWindowHandle(), window_handle_);
313
314 // TODO(loicsharma): Hide the window until the first frame is rendered.
315 // Single window apps use the engine's next frame callback to show the
316 // window. This doesn't work for multi window apps as the engine cannot have
317 // multiple next frame callbacks. If multiple windows are created, only the
318 // last one will be shown.
319 ShowWindow(window_handle_, params.nCmdShow);
320 SetWindowLongPtr(window_handle_, GWLP_USERDATA,
321 reinterpret_cast<LONG_PTR>(this));
322 }
323
324 HostWindow::~HostWindow() {
325 if (view_controller_) {
326 // Unregister the window class. Fail silently if other windows are still
327 // using the class, as only the last window can successfully unregister it.
328 if (!UnregisterClass(kWindowClassName, GetModuleHandle(nullptr))) {
329 // Clear the error state after the failed unregistration.
330 SetLastError(ERROR_SUCCESS);
331 }
332 }
333 }
334
335 HostWindow* HostWindow::GetThisFromHandle(HWND hwnd) {
336 wchar_t class_name[256];
337 if (!GetClassName(hwnd, class_name, sizeof(class_name) / sizeof(wchar_t))) {
338 FML_LOG(ERROR) << "Failed to get class name for window handle " << hwnd
339 << ": " << GetLastErrorAsString();
340 return nullptr;
341 }
342 // Ignore window handles that do not match the expected class name.
343 if (wcscmp(class_name, kWindowClassName) != 0) {
344 return nullptr;
345 }
346
347 return reinterpret_cast<HostWindow*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
348 }
349
350 HWND HostWindow::GetWindowHandle() const {
351 return window_handle_;
352 }
353
354 HWND HostWindow::GetFlutterViewWindowHandle() const {
355 return view_controller_->view()->GetWindowHandle();
356 }
357
358 void HostWindow::FocusRootViewOf(HostWindow* window) {
359 auto child_content = window->view_controller_->view()->GetWindowHandle();
360 if (window != nullptr && child_content != nullptr) {
361 SetFocus(child_content);
362 }
363 };
364
365 LRESULT HostWindow::WndProc(HWND hwnd,
366 UINT message,
367 WPARAM wparam,
368 LPARAM lparam) {
369 if (message == WM_NCCREATE) {
370 auto* const create_struct = reinterpret_cast<CREATESTRUCT*>(lparam);
371 auto* const windows_proc_table =
372 static_cast<WindowsProcTable*>(create_struct->lpCreateParams);
373 windows_proc_table->EnableNonClientDpiScaling(hwnd);
374 EnableTransparentWindowBackground(hwnd, *windows_proc_table);
375 } else if (HostWindow* const window = GetThisFromHandle(hwnd)) {
376 return window->HandleMessage(hwnd, message, wparam, lparam);
377 }
378
379 return DefWindowProc(hwnd, message, wparam, lparam);
380 }
381
382 LRESULT HostWindow::HandleMessage(HWND hwnd,
383 UINT message,
384 WPARAM wparam,
385 LPARAM lparam) {
386 auto result = engine_->window_proc_delegate_manager()->OnTopLevelWindowProc(
387 window_handle_, message, wparam, lparam);
388 if (result) {
389 return *result;
390 }
391
392 switch (message) {
393 case WM_DESTROY:
394 is_being_destroyed_ = true;
395 break;
396
397 case WM_NCLBUTTONDOWN: {
398 // Fix for 500ms hang after user clicks on the title bar, but before
399 // moving mouse. Reference:
400 // https://gamedev.net/forums/topic/672094-keeping-things-moving-during-win32-moveresize-events/5254386/
401 if (SendMessage(window_handle_, WM_NCHITTEST, wparam, lparam) ==
402 HTCAPTION) {
403 POINT cursorPos;
404 // Get the current cursor position and synthesize WM_MOUSEMOVE to
405 // unblock default window proc implementation for WM_NCLBUTTONDOWN at
406 // HTCAPTION.
407 GetCursorPos(&cursorPos);
408 ScreenToClient(window_handle_, &cursorPos);
409 PostMessage(window_handle_, WM_MOUSEMOVE, 0,
410 MAKELPARAM(cursorPos.x, cursorPos.y));
411 }
412 break;
413 }
414
415 case WM_DPICHANGED: {
416 auto* const new_scaled_window_rect = reinterpret_cast<RECT*>(lparam);
417 LONG const width =
418 new_scaled_window_rect->right - new_scaled_window_rect->left;
419 LONG const height =
420 new_scaled_window_rect->bottom - new_scaled_window_rect->top;
421 SetWindowPos(hwnd, nullptr, new_scaled_window_rect->left,
422 new_scaled_window_rect->top, width, height,
423 SWP_NOZORDER | SWP_NOACTIVATE);
424 return 0;
425 }
426
427 case WM_GETMINMAXINFO: {
428 RECT window_rect;
429 GetWindowRect(hwnd, &window_rect);
430 RECT client_rect;
431 GetClientRect(hwnd, &client_rect);
432 LONG const non_client_width = (window_rect.right - window_rect.left) -
433 (client_rect.right - client_rect.left);
434 LONG const non_client_height = (window_rect.bottom - window_rect.top) -
435 (client_rect.bottom - client_rect.top);
436
437 UINT const dpi = flutter::GetDpiForHWND(hwnd);
438 double const scale_factor =
439 static_cast<double>(dpi) / USER_DEFAULT_SCREEN_DPI;
440
441 MINMAXINFO* info = reinterpret_cast<MINMAXINFO*>(lparam);
442 Size const min_physical_size = ClampToVirtualScreen(Size(
443 box_constraints_.smallest().width() * scale_factor + non_client_width,
444 box_constraints_.smallest().height() * scale_factor +
445 non_client_height));
446
447 info->ptMinTrackSize.x = min_physical_size.width();
448 info->ptMinTrackSize.y = min_physical_size.height();
449 Size const max_physical_size = ClampToVirtualScreen(Size(
450 box_constraints_.biggest().width() * scale_factor + non_client_width,
451 box_constraints_.biggest().height() * scale_factor +
452 non_client_height));
453
454 info->ptMaxTrackSize.x = max_physical_size.width();
455 info->ptMaxTrackSize.y = max_physical_size.height();
456 return 0;
457 }
458
459 case WM_SIZE: {
460 auto child_content = view_controller_->view()->GetWindowHandle();
461 if (child_content != nullptr) {
462 // Resize and reposition the child content window.
463 RECT client_rect;
464 GetClientRect(hwnd, &client_rect);
465 MoveWindow(child_content, client_rect.left, client_rect.top,
466 client_rect.right - client_rect.left,
467 client_rect.bottom - client_rect.top, TRUE);
468 }
469 return 0;
470 }
471
472 case WM_ACTIVATE:
473 FocusRootViewOf(this);
474 return 0;
475
476 case WM_DWMCOLORIZATIONCOLORCHANGED:
477 UpdateTheme(hwnd);
478 return 0;
479
480 default:
481 break;
482 }
483
484 if (!view_controller_) {
485 return 0;
486 }
487
488 return DefWindowProc(hwnd, message, wparam, lparam);
489 }
490
491 void HostWindow::SetContentSize(const WindowSizeRequest& size) {
492 if (!size.has_preferred_view_size) {
493 return;
494 }
495
496 if (GetFullscreen()) {
497 std::optional<Size> const window_size = GetWindowSizeForClientSize(
498 *engine_->windows_proc_table(),
499 Size(size.preferred_view_width, size.preferred_view_height),
500 box_constraints_.smallest(), box_constraints_.biggest(),
501 saved_window_info_.style, saved_window_info_.ex_style, nullptr);
502 if (!window_size) {
503 return;
504 }
505
506 saved_window_info_.client_size =
507 ActualWindowSize{.width = size.preferred_view_width,
508 .height = size.preferred_view_height};
509 saved_window_info_.rect.right =
510 saved_window_info_.rect.left + static_cast<LONG>(window_size->width());
511 saved_window_info_.rect.bottom =
512 saved_window_info_.rect.top + static_cast<LONG>(window_size->height());
513 } else {
514 WINDOWINFO window_info = {.cbSize = sizeof(WINDOWINFO)};
515 GetWindowInfo(window_handle_, &window_info);
516
517 std::optional<Size> const window_size = GetWindowSizeForClientSize(
518 *engine_->windows_proc_table(),
519 Size(size.preferred_view_width, size.preferred_view_height),
520 box_constraints_.smallest(), box_constraints_.biggest(),
521 window_info.dwStyle, window_info.dwExStyle, nullptr);
522
523 if (!window_size) {
524 return;
525 }
526
527 SetWindowPos(window_handle_, NULL, 0, 0, window_size->width(),
528 window_size->height(),
529 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
530 }
531 }
532
533 void HostWindow::SetConstraints(const WindowConstraints& constraints) {
534 box_constraints_ = FromWindowConstraints(constraints);
535
536 if (GetFullscreen()) {
537 std::optional<Size> const window_size = GetWindowSizeForClientSize(
538 *engine_->windows_proc_table(),
539 Size(saved_window_info_.client_size.width,
540 saved_window_info_.client_size.height),
541 box_constraints_.smallest(), box_constraints_.biggest(),
542 saved_window_info_.style, saved_window_info_.ex_style, nullptr);
543 if (!window_size) {
544 return;
545 }
546
547 saved_window_info_.rect.right =
548 saved_window_info_.rect.left + static_cast<LONG>(window_size->width());
549 saved_window_info_.rect.bottom =
550 saved_window_info_.rect.top + static_cast<LONG>(window_size->height());
551 } else {
552 auto const client_size = GetWindowContentSize(window_handle_);
553 auto const current_size = Size(client_size.width, client_size.height);
554 WINDOWINFO window_info = {.cbSize = sizeof(WINDOWINFO)};
555 GetWindowInfo(window_handle_, &window_info);
556 std::optional<Size> const window_size = GetWindowSizeForClientSize(
557 *engine_->windows_proc_table(), current_size,
558 box_constraints_.smallest(), box_constraints_.biggest(),
559 window_info.dwStyle, window_info.dwExStyle, nullptr);
560
561 if (window_size && current_size != window_size) {
562 SetWindowPos(window_handle_, NULL, 0, 0, window_size->width(),
563 window_size->height(),
564 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
565 }
566 }
567 }
568
569 // The fullscreen method is largely adapted from the method found in chromium:
570 // See:
571 //
572 // * https://chromium.googlesource.com/chromium/src/+/refs/heads/main/ui/views/win/fullscreen_handler.h
573 // * https://chromium.googlesource.com/chromium/src/+/refs/heads/main/ui/views/win/fullscreen_handler.cc
574 void HostWindow::SetFullscreen(
575 bool fullscreen,
576 std::optional<FlutterEngineDisplayId> display_id) {
577 if (fullscreen == GetFullscreen()) {
578 return;
579 }
580
581 if (fullscreen) {
582 WINDOWINFO window_info = {.cbSize = sizeof(WINDOWINFO)};
583 GetWindowInfo(window_handle_, &window_info);
584 saved_window_info_.style = window_info.dwStyle;
585 saved_window_info_.ex_style = window_info.dwExStyle;
586 // Store the original window rect, DPI, and monitor info to detect changes
587 // and more accurately restore window placements when exiting fullscreen.
588 ::GetWindowRect(window_handle_, &saved_window_info_.rect);
589 saved_window_info_.client_size = GetWindowContentSize(window_handle_);
590 saved_window_info_.dpi = GetDpiForHWND(window_handle_);
591 saved_window_info_.monitor =
592 MonitorFromWindow(window_handle_, MONITOR_DEFAULTTONEAREST);
593 saved_window_info_.monitor_info.cbSize =
594 sizeof(saved_window_info_.monitor_info);
595 GetMonitorInfo(saved_window_info_.monitor,
596 &saved_window_info_.monitor_info);
597 }
598
599 if (fullscreen) {
600 // Next, get the raw HMONITOR that we want to be fullscreened on
601 HMONITOR monitor =
602 MonitorFromWindow(window_handle_, MONITOR_DEFAULTTONEAREST);
603 if (display_id) {
604 if (auto const display =
605 engine_->display_manager()->FindById(display_id.value())) {
606 monitor = reinterpret_cast<HMONITOR>(display->display_id);
607 }
608 }
609
610 MONITORINFO monitor_info;
611 monitor_info.cbSize = sizeof(monitor_info);
612 if (!GetMonitorInfo(monitor, &monitor_info)) {
613 FML_LOG(ERROR) << "Cannot set window fullscreen because the monitor info "
614 "was not found";
615 }
616
617 auto const width = RectWidth(monitor_info.rcMonitor);
618 auto const height = RectHeight(monitor_info.rcMonitor);
619 WINDOWINFO window_info = {.cbSize = sizeof(WINDOWINFO)};
620 GetWindowInfo(window_handle_, &window_info);
621
622 // Set new window style and size.
623 SetWindowLong(window_handle_, GWL_STYLE,
624 saved_window_info_.style & ~(WS_CAPTION | WS_THICKFRAME));
625 SetWindowLong(
626 window_handle_, GWL_EXSTYLE,
627 saved_window_info_.ex_style & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE |
628 WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
629
630 // We call SetWindowPos first to set the window flags immediately. This
631 // makes it so that the WM_GETMINMAXINFO gets called with the correct window
632 // and content sizes.
633 SetWindowPos(window_handle_, NULL, 0, 0, 0, 0,
634 SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
635
636 SetWindowPos(window_handle_, nullptr, monitor_info.rcMonitor.left,
637 monitor_info.rcMonitor.top, width, height,
638 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
639 } else {
640 // Restore the window style and bounds saved prior to entering fullscreen.
641 // Use WS_VISIBLE for windows shown after SetFullscreen: crbug.com/1062251.
642 // Making multiple window adjustments here is ugly, but if SetWindowPos()
643 // doesn't redraw, the taskbar won't be repainted.
644 SetWindowLong(window_handle_, GWL_STYLE,
645 saved_window_info_.style | WS_VISIBLE);
646 SetWindowLong(window_handle_, GWL_EXSTYLE, saved_window_info_.ex_style);
647
648 // We call SetWindowPos first to set the window flags immediately. This
649 // makes it so that the WM_GETMINMAXINFO gets called with the correct window
650 // and content sizes.
651 SetWindowPos(window_handle_, NULL, 0, 0, 0, 0,
652 SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
653
654 HMONITOR monitor =
655 MonitorFromRect(&saved_window_info_.rect, MONITOR_DEFAULTTONEAREST);
656 MONITORINFO monitor_info;
657 monitor_info.cbSize = sizeof(monitor_info);
658 GetMonitorInfo(monitor, &monitor_info);
659
660 auto window_rect = saved_window_info_.rect;
661
662 // Adjust the window bounds to restore, if displays were disconnected,
663 // virtually rearranged, or otherwise changed metrics during fullscreen.
664 if (monitor != saved_window_info_.monitor ||
665 !AreRectsEqual(saved_window_info_.monitor_info.rcWork,
666 monitor_info.rcWork)) {
667 window_rect = AdjustToFit(monitor_info.rcWork, window_rect);
668 }
669
670 auto const fullscreen_dpi = GetDpiForHWND(window_handle_);
671 SetWindowPos(window_handle_, nullptr, window_rect.left, window_rect.top,
672 RectWidth(window_rect), RectHeight(window_rect),
673 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
674 auto const final_dpi = GetDpiForHWND(window_handle_);
675 if (final_dpi != saved_window_info_.dpi || final_dpi != fullscreen_dpi) {
676 // Reissue SetWindowPos if the DPI changed from saved or fullscreen DPIs.
677 // The first call may misinterpret bounds spanning displays, if the
678 // fullscreen display's DPI does not match the target display's DPI.
679 //
680 // Scale and clamp the bounds if the final DPI changed from the saved DPI.
681 // This more accurately matches the original placement, while avoiding
682 // unexpected offscreen placement in a recongifured multi-screen space.
683 if (final_dpi != saved_window_info_.dpi) {
684 auto const scale =
685 final_dpi / static_cast<float>(saved_window_info_.dpi);
686 auto const width = static_cast<LONG>(scale * RectWidth(window_rect));
687 auto const height = static_cast<LONG>(scale * RectHeight(window_rect));
688 window_rect.right = window_rect.left + width;
689 window_rect.bottom = window_rect.top + height;
690 window_rect = AdjustToFit(monitor_info.rcWork, window_rect);
691 }
692
693 SetWindowPos(window_handle_, nullptr, window_rect.left, window_rect.top,
694 RectWidth(window_rect), RectHeight(window_rect),
695 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
696 }
697 }
698
699 if (!task_bar_list_) {
700 HRESULT hr =
701 ::CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER,
702 IID_PPV_ARGS(&task_bar_list_));
703 if (SUCCEEDED(hr) && FAILED(task_bar_list_->HrInit())) {
704 task_bar_list_ = nullptr;
705 }
706 }
707
708 // As per MSDN marking the window as fullscreen should ensure that the
709 // taskbar is moved to the bottom of the Z-order when the fullscreen window
710 // is activated. If the window is not fullscreen, the Shell falls back to
711 // heuristics to determine how the window should be treated, which means
712 // that it could still consider the window as fullscreen. :(
713 if (task_bar_list_) {
714 task_bar_list_->MarkFullscreenWindow(window_handle_, !!fullscreen);
715 }
716
717 is_fullscreen_ = fullscreen;
718 }
719
720 bool HostWindow::GetFullscreen() const {
721 return is_fullscreen_;
722 }
723
724 ActualWindowSize HostWindow::GetWindowContentSize(HWND hwnd) {
725 RECT rect;
726 GetClientRect(hwnd, &rect);
727 double const dpr = FlutterDesktopGetDpiForHWND(hwnd) /
728 static_cast<double>(USER_DEFAULT_SCREEN_DPI);
729 double const width = rect.right / dpr;
730 double const height = rect.bottom / dpr;
731 return {
732 .width = rect.right / dpr,
733 .height = rect.bottom / dpr,
734 };
735 }
736
737 std::optional<Size> HostWindow::GetWindowSizeForClientSize(
738 WindowsProcTable const& win32,
739 Size const& client_size,
740 std::optional<Size> smallest,
741 std::optional<Size> biggest,
742 DWORD window_style,
743 DWORD extended_window_style,
744 std::optional<HWND> const& owner_hwnd) {
745 UINT const dpi = GetDpiForHWND(owner_hwnd ? *owner_hwnd : nullptr);
746 double const scale_factor =
747 static_cast<double>(dpi) / USER_DEFAULT_SCREEN_DPI;
748 RECT rect = {
749 .right = static_cast<LONG>(client_size.width() * scale_factor),
750 .bottom = static_cast<LONG>(client_size.height() * scale_factor)};
751
752 if (!win32.AdjustWindowRectExForDpi(&rect, window_style, FALSE,
753 extended_window_style, dpi)) {
754 FML_LOG(ERROR) << "Failed to run AdjustWindowRectExForDpi: "
755 << GetLastErrorAsString();
756 return std::nullopt;
757 }
758
759 double width = static_cast<double>(rect.right - rect.left);
760 double height = static_cast<double>(rect.bottom - rect.top);
761
762 // Apply size constraints.
763 double const non_client_width = width - (client_size.width() * scale_factor);
764 double const non_client_height =
765 height - (client_size.height() * scale_factor);
766 if (smallest) {
767 flutter::Size min_physical_size = ClampToVirtualScreen(
768 flutter::Size(smallest->width() * scale_factor + non_client_width,
769 smallest->height() * scale_factor + non_client_height));
770 width = std::max(width, min_physical_size.width());
771 height = std::max(height, min_physical_size.height());
772 }
773 if (biggest) {
774 flutter::Size max_physical_size = ClampToVirtualScreen(
775 flutter::Size(biggest->width() * scale_factor + non_client_width,
776 biggest->height() * scale_factor + non_client_height));
777 width = std::min(width, max_physical_size.width());
778 height = std::min(height, max_physical_size.height());
779 }
780
781 return flutter::Size{width, height};
782 }
783
784 void HostWindow::EnableRecursively(bool enable) {
785 EnableWindow(window_handle_, enable);
786
787 for (HostWindow* const owned : GetOwnedWindows()) {
788 owned->EnableRecursively(enable);
789 }
790 }
791
792 HostWindow* HostWindow::FindFirstEnabledDescendant() const {
793 if (IsWindowEnabled(window_handle_)) {
794 return const_cast<HostWindow*>(this);
795 }
796
797 for (HostWindow* const owned : GetOwnedWindows()) {
798 if (HostWindow* const result = owned->FindFirstEnabledDescendant()) {
799 return result;
800 }
801 }
802
803 return nullptr;
804 }
805
806 std::vector<HostWindow*> HostWindow::GetOwnedWindows() const {
807 std::vector<HostWindow*> owned_windows;
808 struct EnumData {
809 HWND owner_window_handle;
810 std::vector<HostWindow*>* owned_windows;
811 } data{window_handle_, &owned_windows};
812
813 EnumWindows(
814 [](HWND hwnd, LPARAM lparam) -> BOOL {
815 auto* const data = reinterpret_cast<EnumData*>(lparam);
816 if (GetWindow(hwnd, GW_OWNER) == data->owner_window_handle) {
817 HostWindow* const window = GetThisFromHandle(hwnd);
818 if (window && !window->is_being_destroyed_) {
819 data->owned_windows->push_back(window);
820 }
821 }
822 return TRUE;
823 },
824 reinterpret_cast<LPARAM>(&data));
825
826 return owned_windows;
827 }
828
829 HostWindow* HostWindow::GetOwnerWindow() const {
830 if (HWND const owner_window_handle = GetWindow(GetWindowHandle(), GW_OWNER)) {
831 return GetThisFromHandle(owner_window_handle);
832 }
833 return nullptr;
834 };
835
836 void HostWindow::DisableRecursively() {
837 // Disable the window itself.
838 EnableWindow(window_handle_, false);
839
840 for (HostWindow* const owned : GetOwnedWindows()) {
841 owned->DisableRecursively();
842 }
843 }
844
845 void HostWindow::UpdateModalStateLayer() {
846 auto children = GetOwnedWindows();
847 if (children.empty()) {
848 // Leaf window in the active path, enable it.
849 EnableWindow(window_handle_, true);
850 } else {
851 // Non-leaf window in the active path, disable it and process children.
852 EnableWindow(window_handle_, false);
853
854 // On same level of window hierarchy the most recently created window
855 // will remain enabled.
856 auto latest_child = *std::max_element(
857 children.begin(), children.end(), [](HostWindow* a, HostWindow* b) {
858 return a->view_controller_->view()->view_id() <
859 b->view_controller_->view()->view_id();
860 });
861
862 for (HostWindow* const child : children) {
863 if (child == latest_child) {
864 child->UpdateModalStateLayer();
865 } else {
866 child->DisableRecursively();
867 }
868 }
869 }
870 }
871
872 } // namespace flutter
flutter::FlutterWindowsEngine
Definition: flutter_windows_engine.h:92
flutter::FlutterWindowsEngine::windows_proc_table
std::shared_ptr< WindowsProcTable > windows_proc_table()
Definition: flutter_windows_engine.h:319
flutter::FlutterWindowsEngine::UpdateAccessibilityFeatures
void UpdateAccessibilityFeatures()
Definition: flutter_windows_engine.cc:1021
flutter::FlutterWindowsEngine::window_proc_delegate_manager
WindowProcDelegateManager * window_proc_delegate_manager()
Definition: flutter_windows_engine.h:185
flutter::FlutterWindowsEngine::display_manager
std::shared_ptr< DisplayManagerWin32 > display_manager()
Definition: flutter_windows_engine.h:166
flutter::FlutterWindowsEngine::CreateView
std::unique_ptr< FlutterWindowsView > CreateView(std::unique_ptr< WindowBindingHandler > window, bool is_sized_to_content, const BoxConstraints &box_constraints, FlutterWindowsViewSizingDelegate *sizing_delegate=nullptr)
Definition: flutter_windows_engine.cc:526
flutter::FlutterWindowsEngine::running
virtual bool running() const
Definition: flutter_windows_engine.h:125
flutter::HostWindowDialog
Definition: host_window_dialog.h:11
flutter::HostWindow
Definition: host_window.h:29
flutter::HostWindow::task_bar_list_
Microsoft::WRL::ComPtr< ITaskbarList2 > task_bar_list_
Definition: host_window.h:238
flutter::HostWindow::GetWindowHandle
HWND GetWindowHandle() const
Definition: host_window.cc:350
flutter::HostWindow::box_constraints_
BoxConstraints box_constraints_
Definition: host_window.h:226
flutter::HostWindow::window_handle_
HWND window_handle_
Definition: host_window.h:223
flutter::HostWindow::InitializeFlutterView
void InitializeFlutterView(HostWindowInitializationParams const &params)
Definition: host_window.cc:245
flutter::HostWindow::saved_window_info_
SavedWindowInfo saved_window_info_
Definition: host_window.h:235
flutter::HostWindow::is_fullscreen_
bool is_fullscreen_
Definition: host_window.h:232
flutter::HostWindow::view_controller_
std::unique_ptr< FlutterWindowsViewController > view_controller_
Definition: host_window.h:217
flutter::HostWindow::DisableRecursively
void DisableRecursively()
Definition: host_window.cc:836
flutter::HostWindow::WndProc
static LRESULT WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
Definition: host_window.cc:365
flutter::HostWindow::GetOwnerWindow
HostWindow * GetOwnerWindow() const
Definition: host_window.cc:829
flutter::HostWindow::GetWindowContentSize
static ActualWindowSize GetWindowContentSize(HWND hwnd)
Definition: host_window.cc:724
flutter::HostWindow::EnableRecursively
void EnableRecursively(bool enable)
Definition: host_window.cc:784
flutter::HostWindow::SetContentSize
void SetContentSize(const WindowSizeRequest &size)
Definition: host_window.cc:491
flutter::HostWindow::is_being_destroyed_
bool is_being_destroyed_
Definition: host_window.h:229
flutter::HostWindow::UpdateModalStateLayer
void UpdateModalStateLayer()
Definition: host_window.cc:845
flutter::HostWindow::FocusRootViewOf
static void FocusRootViewOf(HostWindow *window)
Definition: host_window.cc:358
flutter::HostWindow::GetFlutterViewWindowHandle
HWND GetFlutterViewWindowHandle() const
Definition: host_window.cc:354
flutter::HostWindow::engine_
FlutterWindowsEngine * engine_
Definition: host_window.h:212
flutter::HostWindow::~HostWindow
virtual ~HostWindow()
Definition: host_window.cc:324
flutter::HostWindow::GetThisFromHandle
static HostWindow * GetThisFromHandle(HWND hwnd)
Definition: host_window.cc:335
flutter::HostWindow::HostWindow
HostWindow(WindowManager *window_manager, FlutterWindowsEngine *engine)
Definition: host_window.cc:241
flutter::HostWindow::GetOwnedWindows
std::vector< HostWindow * > GetOwnedWindows() const
Definition: host_window.cc:806
flutter::HostWindow::GetFullscreen
virtual bool GetFullscreen() const
Definition: host_window.cc:720
flutter::HostWindow::SetConstraints
void SetConstraints(const WindowConstraints &constraints)
Definition: host_window.cc:533
flutter::HostWindow::CreateTooltipWindow
static std::unique_ptr< HostWindow > CreateTooltipWindow(WindowManager *window_manager, FlutterWindowsEngine *engine, const WindowConstraints &preferred_constraints, bool is_sized_to_content, GetWindowPositionCallback get_position_callback, HWND parent)
Definition: host_window.cc:229
flutter::HostWindow::SetFullscreen
virtual void SetFullscreen(bool fullscreen, std::optional< FlutterEngineDisplayId > display_id)
Definition: host_window.cc:574
flutter::HostWindow::HandleMessage
virtual LRESULT HandleMessage(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
Definition: host_window.cc:382
flutter::HostWindow::CreateDialogWindow
static std::unique_ptr< HostWindow > CreateDialogWindow(WindowManager *window_manager, FlutterWindowsEngine *engine, const WindowSizeRequest &preferred_size, const WindowConstraints &preferred_constraints, LPCWSTR title, HWND parent)
Definition: host_window.cc:216
flutter::HostWindow::GetWindowSizeForClientSize
static std::optional< Size > GetWindowSizeForClientSize(WindowsProcTable const &win32, Size const &client_size, std::optional< Size > smallest, std::optional< Size > biggest, DWORD window_style, DWORD extended_window_style, std::optional< HWND > const &owner_hwnd)
Definition: host_window.cc:737
flutter::HostWindow::CreateRegularWindow
static std::unique_ptr< HostWindow > CreateRegularWindow(WindowManager *window_manager, FlutterWindowsEngine *engine, const WindowSizeRequest &preferred_size, const WindowConstraints &preferred_constraints, LPCWSTR title)
Definition: host_window.cc:205
flutter::HostWindow::FindFirstEnabledDescendant
HostWindow * FindFirstEnabledDescendant() const
Definition: host_window.cc:792
flutter::HostWindowRegular
Definition: host_window_regular.h:11
flutter::HostWindowTooltip
Definition: host_window_tooltip.h:15
flutter::WindowManager
Definition: window_manager.h:109
flutter::WindowProcDelegateManager::OnTopLevelWindowProc
std::optional< LRESULT > OnTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) const
Definition: window_proc_delegate_manager.cc:37
flutter::WindowsProcTable
Definition: windows_proc_table.h:18
flutter::WindowsProcTable::AdjustWindowRectExForDpi
virtual BOOL AdjustWindowRectExForDpi(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi) const
Definition: windows_proc_table.cc:110
flutter::WindowsProcTable::EnableNonClientDpiScaling
virtual BOOL EnableNonClientDpiScaling(HWND hwnd) const
Definition: windows_proc_table.cc:79
flutter::WindowsProcTable::DwmExtendFrameIntoClientArea
virtual HRESULT DwmExtendFrameIntoClientArea(HWND hwnd, const MARGINS *pMarInset) const
Definition: windows_proc_table.cc:97
flutter::WindowsProcTable::DwmSetWindowAttribute
virtual HRESULT DwmSetWindowAttribute(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute) const
Definition: windows_proc_table.cc:103
flutter::WindowsProcTable::SetWindowCompositionAttribute
virtual BOOL SetWindowCompositionAttribute(HWND hwnd, WINDOWCOMPOSITIONATTRIBDATA *data) const
Definition: windows_proc_table.cc:87
display_manager.h
dpi_utils.h
flutter_window.h
FlutterDesktopGetDpiForHWND
UINT FlutterDesktopGetDpiForHWND(HWND hwnd)
Definition: flutter_windows.cc:323
flutter_windows_view_controller.h
DWMWA_USE_IMMERSIVE_DARK_MODE
#define DWMWA_USE_IMMERSIVE_DARK_MODE
Definition: host_window.cc:111
host_window.h
host_window_dialog.h
host_window_regular.h
host_window_tooltip.h
content
union flutter::testing::@100::KeyboardChange::@0 content
message
Win32Message message
Definition: keyboard_unittests.cc:137
flutter
Definition: accessibility_bridge_windows.cc:11
flutter::GetWindowPositionCallback
WindowRect *(* GetWindowPositionCallback)(const WindowSize &child_size, const WindowRect &parent_rect, const WindowRect &output_rect)
Definition: window_manager.h:69
flutter::GetDpiForHWND
UINT GetDpiForHWND(HWND hwnd)
Definition: dpi_utils.cc:128
flutter::RectWidth
LONG RectWidth(const RECT &r)
Definition: rect_helper.h:11
flutter::AreRectsEqual
bool AreRectsEqual(const RECT &a, const RECT &b)
Definition: rect_helper.h:19
flutter::RectHeight
LONG RectHeight(const RECT &r)
Definition: rect_helper.h:15
rect_helper.h
flutter::ActualWindowSize
Definition: window_manager.h:96
flutter::ActualWindowSize::width
double width
Definition: window_manager.h:97
flutter::ActualWindowSize::height
double height
Definition: window_manager.h:98
flutter::HostWindow::HostWindowInitializationParams
Definition: host_window.h:119
flutter::HostWindow::HostWindowInitializationParams::title
LPCWSTR title
Definition: host_window.h:125
flutter::HostWindow::HostWindowInitializationParams::window_style
DWORD window_style
Definition: host_window.h:121
flutter::HostWindow::HostWindowInitializationParams::extended_window_style
DWORD extended_window_style
Definition: host_window.h:122
flutter::HostWindow::HostWindowInitializationParams::nCmdShow
int nCmdShow
Definition: host_window.h:127
flutter::HostWindow::HostWindowInitializationParams::owner_window
std::optional< HWND > const & owner_window
Definition: host_window.h:126
flutter::HostWindow::HostWindowInitializationParams::initial_window_rect
Rect const initial_window_rect
Definition: host_window.h:124
flutter::HostWindow::HostWindowInitializationParams::sizing_delegate
FlutterWindowsViewSizingDelegate * sizing_delegate
Definition: host_window.h:128
flutter::HostWindow::HostWindowInitializationParams::is_sized_to_content
bool is_sized_to_content
Definition: host_window.h:129
flutter::HostWindow::HostWindowInitializationParams::box_constraints
const BoxConstraints & box_constraints
Definition: host_window.h:123
flutter::HostWindow::SavedWindowInfo::client_size
ActualWindowSize client_size
Definition: host_window.h:147
flutter::HostWindow::SavedWindowInfo::dpi
int dpi
Definition: host_window.h:148
flutter::HostWindow::SavedWindowInfo::ex_style
LONG ex_style
Definition: host_window.h:145
flutter::HostWindow::SavedWindowInfo::style
LONG style
Definition: host_window.h:144
flutter::HostWindow::SavedWindowInfo::monitor_info
MONITORINFO monitor_info
Definition: host_window.h:150
flutter::HostWindow::SavedWindowInfo::monitor
HMONITOR monitor
Definition: host_window.h:149
flutter::HostWindow::SavedWindowInfo::rect
RECT rect
Definition: host_window.h:146
flutter::WindowConstraints
Definition: window_manager.h:33
flutter::WindowConstraints::view_max_width
double view_max_width
Definition: window_manager.h:37
flutter::WindowConstraints::view_min_width
double view_min_width
Definition: window_manager.h:35
flutter::WindowConstraints::has_view_constraints
bool has_view_constraints
Definition: window_manager.h:34
flutter::WindowConstraints::view_max_height
double view_max_height
Definition: window_manager.h:38
flutter::WindowConstraints::view_min_height
double view_min_height
Definition: window_manager.h:36
flutter::WindowSizeRequest
Definition: window_manager.h:26
flutter::WindowSizeRequest::preferred_view_height
double preferred_view_height
Definition: window_manager.h:29
flutter::WindowSizeRequest::preferred_view_width
double preferred_view_width
Definition: window_manager.h:28
flutter::WindowSizeRequest::has_preferred_view_size
bool has_preferred_view_size
Definition: window_manager.h:27
flutter::WindowsProcTable::WINDOWCOMPOSITIONATTRIBDATA
Definition: windows_proc_table.h:22
flutter::WindowsProcTable::WINDOWCOMPOSITIONATTRIBDATA::Attrib
WINDOWCOMPOSITIONATTRIB Attrib
Definition: windows_proc_table.h:23
wchar_util.h
window_manager.h