21constexpr wchar_t kWindowClassName[] = L
"FLUTTER_HOST_WINDOW";
26 double const virtual_screen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
27 double const virtual_screen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
30 std::clamp(
size.height(), 0.0, virtual_screen_height));
33void EnableTransparentWindowBackground(HWND hwnd,
35 enum ACCENT_STATE { ACCENT_DISABLED = 0 };
37 struct ACCENT_POLICY {
38 ACCENT_STATE AccentState;
45 ACCENT_POLICY accent = {ACCENT_DISABLED, 2,
static_cast<DWORD>(0), 0};
50 .cbData =
sizeof(accent)};
55 MARGINS
const margins = {-1};
64std::string GetLastErrorAsString() {
65 LPWSTR message_buffer =
nullptr;
67 if (
DWORD const size = FormatMessage(
68 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
69 FORMAT_MESSAGE_IGNORE_INSERTS,
70 nullptr,
GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
71 reinterpret_cast<LPTSTR
>(&message_buffer), 0,
nullptr)) {
72 std::wstring
const wide_message(message_buffer, size);
73 LocalFree(message_buffer);
74 message_buffer =
nullptr;
76 if (
int const buffer_size =
77 WideCharToMultiByte(CP_UTF8, 0, wide_message.c_str(), -1,
nullptr,
78 0,
nullptr,
nullptr)) {
79 std::string
message(buffer_size, 0);
80 WideCharToMultiByte(CP_UTF8, 0, wide_message.c_str(), -1, &
message[0],
81 buffer_size,
nullptr,
nullptr);
87 LocalFree(message_buffer);
89 std::ostringstream oss;
90 oss <<
"Format message failed with 0x" << std::hex << std::setfill(
'0')
97bool IsClassRegistered(LPCWSTR class_name) {
98 WNDCLASSEX window_class = {};
99 return GetClassInfoEx(GetModuleHandle(
nullptr), class_name, &window_class) !=
109#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
110#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
114void UpdateTheme(HWND
window) {
116 const wchar_t kGetPreferredBrightnessRegKey[] =
117 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
118 const wchar_t kGetPreferredBrightnessRegValue[] = L
"AppsUseLightTheme";
123 DWORD light_mode_size =
sizeof(light_mode);
124 LSTATUS
const result =
126 kGetPreferredBrightnessRegValue, RRF_RT_REG_DWORD,
nullptr,
127 &light_mode, &light_mode_size);
130 BOOL enable_dark_mode = light_mode == 0;
132 &enable_dark_mode,
sizeof(enable_dark_mode));
140 GetClientRect(
window, &client_rect);
141 MoveWindow(
content, client_rect.left, client_rect.top,
142 client_rect.right - client_rect.left,
143 client_rect.bottom - client_rect.top,
true);
162 *
size = std::min(dst_size, *size);
163 if (*origin < dst_origin)
164 *origin = dst_origin;
166 *origin = std::min(dst_origin + dst_size, *origin + *size) - *
size;
169RECT AdjustToFit(
const RECT& parent,
const RECT& child) {
170 auto new_x = child.left;
171 auto new_y = child.top;
178 result.right = new_x + new_width;
180 result.bottom = new_y + new_height;
186 std::optional<flutter::Size> smallest, biggest;
211 window_manager,
engine, preferred_size,
212 FromWindowConstraints(preferred_constraints), title));
222 return std::unique_ptr<HostWindow>(
224 FromWindowConstraints(preferred_constraints), title,
225 parent ? parent : std::optional<HWND>()));
232 DWORD extended_window_style,
234 Rect const initial_window_rect,
236 std::optional<HWND>
const& owner_window)
237 : window_manager_(window_manager),
239 archetype_(archetype),
240 box_constraints_(box_constraints) {
242 auto view_window = std::make_unique<FlutterWindow>(
243 initial_window_rect.
width(), initial_window_rect.
height(),
244 engine->display_manager(),
engine->windows_proc_table());
246 std::unique_ptr<FlutterWindowsView>
view =
247 engine->CreateView(std::move(view_window));
251 std::make_unique<FlutterWindowsViewController>(
nullptr, std::move(
view));
256 engine->UpdateAccessibilityFeatures();
259 if (!IsClassRegistered(kWindowClassName)) {
260 auto const idi_app_icon = 101;
261 WNDCLASSEX window_class = {};
262 window_class.cbSize =
sizeof(WNDCLASSEX);
263 window_class.style = CS_HREDRAW | CS_VREDRAW;
265 window_class.hInstance = GetModuleHandle(
nullptr);
267 LoadIcon(window_class.hInstance, MAKEINTRESOURCE(idi_app_icon));
268 if (!window_class.hIcon) {
269 window_class.hIcon =
LoadIcon(
nullptr, IDI_APPLICATION);
271 window_class.hCursor = LoadCursor(
nullptr, IDC_ARROW);
272 window_class.lpszClassName = kWindowClassName;
274 FML_CHECK(RegisterClassEx(&window_class));
279 extended_window_style, kWindowClassName, title, window_style,
280 initial_window_rect.
left(), initial_window_rect.
top(),
281 initial_window_rect.
width(), initial_window_rect.
height(),
282 owner_window ? *owner_window :
nullptr,
nullptr, GetModuleHandle(
nullptr),
283 engine->windows_proc_table().get());
291 DwmGetWindowAttribute(
window_handle_, DWMWA_EXTENDED_FRAME_BOUNDS,
292 &frame_rect,
sizeof(frame_rect));
295 LONG const left_dropshadow_width = frame_rect.left - window_rect.left;
296 LONG const top_dropshadow_height = window_rect.top - frame_rect.top;
298 window_rect.left - left_dropshadow_width,
299 window_rect.top - top_dropshadow_height, 0, 0,
300 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
320 if (!UnregisterClass(kWindowClassName, GetModuleHandle(
nullptr))) {
328 wchar_t class_name[256];
329 if (!GetClassName(hwnd, class_name,
sizeof(class_name) /
sizeof(
wchar_t))) {
330 FML_LOG(ERROR) <<
"Failed to get class name for window handle " << hwnd
331 <<
": " << GetLastErrorAsString();
335 if (wcscmp(class_name, kWindowClassName) != 0) {
339 return reinterpret_cast<HostWindow*
>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
348 if (
window !=
nullptr && child_content !=
nullptr) {
349 SetFocus(child_content);
358 auto*
const create_struct =
reinterpret_cast<CREATESTRUCT*
>(lparam);
359 auto*
const windows_proc_table =
362 EnableTransparentWindowBackground(hwnd, *windows_proc_table);
367 return DefWindowProc(hwnd,
message, wparam, lparam);
385 case WM_NCLBUTTONDOWN: {
395 GetCursorPos(&cursorPos);
398 MAKELPARAM(cursorPos.x, cursorPos.y));
403 case WM_DPICHANGED: {
404 auto*
const new_scaled_window_rect =
reinterpret_cast<RECT*
>(lparam);
406 new_scaled_window_rect->right - new_scaled_window_rect->left;
408 new_scaled_window_rect->bottom - new_scaled_window_rect->top;
409 SetWindowPos(hwnd,
nullptr, new_scaled_window_rect->left,
411 SWP_NOZORDER | SWP_NOACTIVATE);
415 case WM_GETMINMAXINFO: {
417 GetWindowRect(hwnd, &window_rect);
419 GetClientRect(hwnd, &client_rect);
420 LONG const non_client_width = (window_rect.right - window_rect.left) -
421 (client_rect.right - client_rect.left);
422 LONG const non_client_height = (window_rect.bottom - window_rect.top) -
423 (client_rect.bottom - client_rect.top);
426 double const scale_factor =
427 static_cast<double>(dpi) / USER_DEFAULT_SCREEN_DPI;
429 MINMAXINFO* info =
reinterpret_cast<MINMAXINFO*
>(lparam);
430 Size const min_physical_size = ClampToVirtualScreen(
Size(
435 info->ptMinTrackSize.x = min_physical_size.
width();
436 info->ptMinTrackSize.y = min_physical_size.
height();
437 Size const max_physical_size = ClampToVirtualScreen(
Size(
442 info->ptMaxTrackSize.x = max_physical_size.
width();
443 info->ptMaxTrackSize.y = max_physical_size.
height();
449 if (child_content !=
nullptr) {
452 GetClientRect(hwnd, &client_rect);
453 MoveWindow(child_content, client_rect.left, client_rect.top,
454 client_rect.right - client_rect.left,
455 client_rect.bottom - client_rect.top,
TRUE);
464 case WM_DWMCOLORIZATIONCOLORCHANGED:
476 return DefWindowProc(hwnd,
message, wparam, lparam);
480 if (!
size.has_preferred_view_size) {
487 Size(
size.preferred_view_width,
size.preferred_view_height),
496 .height =
size.preferred_view_height};
502 WINDOWINFO window_info = {.cbSize =
sizeof(WINDOWINFO)};
507 Size(
size.preferred_view_width,
size.preferred_view_height),
509 window_info.dwStyle, window_info.dwExStyle,
nullptr);
516 window_size->height(),
517 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
541 auto const current_size =
Size(client_size.width, client_size.height);
542 WINDOWINFO window_info = {.cbSize =
sizeof(WINDOWINFO)};
547 window_info.dwStyle, window_info.dwExStyle,
nullptr);
549 if (window_size && current_size != window_size) {
551 window_size->height(),
552 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
564 std::optional<FlutterEngineDisplayId> display_id) {
570 WINDOWINFO window_info = {.cbSize =
sizeof(WINDOWINFO)};
592 if (
auto const display =
594 monitor =
reinterpret_cast<HMONITOR
>(display->display_id);
598 MONITORINFO monitor_info;
599 monitor_info.cbSize =
sizeof(monitor_info);
600 if (!GetMonitorInfo(monitor, &monitor_info)) {
601 FML_LOG(ERROR) <<
"Cannot set window fullscreen because the monitor info "
607 WINDOWINFO window_info = {.cbSize =
sizeof(WINDOWINFO)};
616 WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
622 SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
624 SetWindowPos(
window_handle_,
nullptr, monitor_info.rcMonitor.left,
626 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
640 SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
644 MONITORINFO monitor_info;
645 monitor_info.cbSize =
sizeof(monitor_info);
646 GetMonitorInfo(monitor, &monitor_info);
654 monitor_info.rcWork)) {
655 window_rect = AdjustToFit(monitor_info.rcWork, window_rect);
659 SetWindowPos(
window_handle_,
nullptr, window_rect.left, window_rect.top,
661 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
676 window_rect.right = window_rect.left +
width;
677 window_rect.bottom = window_rect.top +
height;
678 window_rect = AdjustToFit(monitor_info.rcWork, window_rect);
681 SetWindowPos(
window_handle_,
nullptr, window_rect.left, window_rect.top,
683 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
689 ::CoCreateInstance(CLSID_TaskbarList,
nullptr, CLSCTX_INPROC_SERVER,
714 GetClientRect(hwnd, &rect);
716 static_cast<double>(USER_DEFAULT_SCREEN_DPI);
717 double const width = rect.right / dpr;
718 double const height = rect.bottom / dpr;
720 .width = rect.right / dpr,
721 .height = rect.bottom / dpr,
727 Size const& client_size,
728 std::optional<Size> smallest,
729 std::optional<Size> biggest,
731 DWORD extended_window_style,
732 std::optional<HWND>
const& owner_hwnd) {
734 double const scale_factor =
735 static_cast<double>(dpi) / USER_DEFAULT_SCREEN_DPI;
737 .right =
static_cast<LONG>(client_size.
width() * scale_factor),
738 .bottom =
static_cast<LONG>(client_size.
height() * scale_factor)};
741 extended_window_style, dpi)) {
742 FML_LOG(ERROR) <<
"Failed to run AdjustWindowRectExForDpi: "
743 << GetLastErrorAsString();
747 double width =
static_cast<double>(rect.right - rect.left);
748 double height =
static_cast<double>(rect.bottom - rect.top);
751 double const non_client_width =
width - (client_size.
width() * scale_factor);
752 double const non_client_height =
756 flutter::Size(smallest->width() * scale_factor + non_client_width,
757 smallest->height() * scale_factor + non_client_height));
763 flutter::Size(biggest->width() * scale_factor + non_client_width,
764 biggest->height() * scale_factor + non_client_height));
776 owned->EnableRecursively(enable);
795 std::vector<HostWindow*> owned_windows;
797 HWND owner_window_handle;
798 std::vector<HostWindow*>* owned_windows;
803 auto*
const data =
reinterpret_cast<EnumData*
>(lparam);
804 if (GetWindow(hwnd, GW_OWNER) ==
data->owner_window_handle) {
814 return owned_windows;
818 if (HWND
const owner_window_handle = GetWindow(
GetWindowHandle(), GW_OWNER)) {
829 owned->DisableRecursively();
835 if (children.empty()) {
844 auto latest_child = *std::max_element(
846 return a->view_controller_->view()->view_id() <
847 b->view_controller_->view()->view_id();
851 if (child == latest_child) {
852 child->UpdateModalStateLayer();
854 child->DisableRecursively();
std::shared_ptr< WindowsProcTable > windows_proc_table()
std::shared_ptr< DisplayManagerWin32 > display_manager()
WindowProcDelegateManager * window_proc_delegate_manager()
Microsoft::WRL::ComPtr< ITaskbarList2 > task_bar_list_
HWND GetWindowHandle() const
BoxConstraints box_constraints_
SavedWindowInfo saved_window_info_
std::unique_ptr< FlutterWindowsViewController > view_controller_
void DisableRecursively()
static LRESULT WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
HostWindow * GetOwnerWindow() const
static ActualWindowSize GetWindowContentSize(HWND hwnd)
void EnableRecursively(bool enable)
void SetContentSize(const WindowSizeRequest &size)
void UpdateModalStateLayer()
static void FocusRootViewOf(HostWindow *window)
HostWindow(WindowManager *window_manager, FlutterWindowsEngine *engine, WindowArchetype archetype, DWORD window_style, DWORD extended_window_style, const BoxConstraints &box_constraints, Rect const initial_window_rect, LPCWSTR title, std::optional< HWND > const &owner_window)
FlutterWindowsEngine * engine_
static HostWindow * GetThisFromHandle(HWND hwnd)
std::vector< HostWindow * > GetOwnedWindows() const
virtual bool GetFullscreen() const
void SetConstraints(const WindowConstraints &constraints)
virtual void SetFullscreen(bool fullscreen, std::optional< FlutterEngineDisplayId > display_id)
virtual LRESULT HandleMessage(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
static std::unique_ptr< HostWindow > CreateDialogWindow(WindowManager *window_manager, FlutterWindowsEngine *engine, const WindowSizeRequest &preferred_size, const WindowConstraints &preferred_constraints, LPCWSTR title, HWND parent)
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)
static std::unique_ptr< HostWindow > CreateRegularWindow(WindowManager *window_manager, FlutterWindowsEngine *engine, const WindowSizeRequest &preferred_size, const WindowConstraints &preferred_constraints, LPCWSTR title)
HostWindow * FindFirstEnabledDescendant() const
std::optional< LRESULT > OnTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) const
virtual BOOL AdjustWindowRectExForDpi(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi) const
virtual BOOL EnableNonClientDpiScaling(HWND hwnd) const
virtual HRESULT DwmExtendFrameIntoClientArea(HWND hwnd, const MARGINS *pMarInset) const
virtual HRESULT DwmSetWindowAttribute(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute) const
virtual BOOL SetWindowCompositionAttribute(HWND hwnd, WINDOWCOMPOSITIONATTRIBDATA *data) const
G_BEGIN_DECLS GBytes * message
UINT FlutterDesktopGetDpiForHWND(HWND hwnd)
#define FML_LOG(severity)
#define FML_CHECK(condition)
#define DWMWA_USE_IMMERSIVE_DARK_MODE
union flutter::testing::@2824::KeyboardChange::@78 content
UINT GetDpiForHWND(HWND hwnd)
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
LONG RectWidth(const RECT &r)
bool AreRectsEqual(const RECT &a, const RECT &b)
LONG RectHeight(const RECT &r)
void AdjustAlongAxis(int dst_origin, int dst_size, int *origin, int *size)
ActualWindowSize client_size
bool has_view_constraints
WINDOWCOMPOSITIONATTRIB Attrib
std::shared_ptr< const fml::Mapping > data
#define HKEY_CURRENT_USER
WINBASEAPI VOID WINAPI SetLastError(_In_ DWORD dwErrCode)
WINBASEAPI _Check_return_ _Post_equals_last_error_ DWORD WINAPI GetLastError(VOID)