22constexpr wchar_t kWindowClassName[] = L
"FLUTTER_HOST_WINDOW";
27 double const virtual_screen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
28 double const virtual_screen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
31 std::clamp(
size.height(), 0.0, virtual_screen_height));
34void EnableTransparentWindowBackground(HWND hwnd,
36 enum ACCENT_STATE { ACCENT_DISABLED = 0 };
38 struct ACCENT_POLICY {
39 ACCENT_STATE AccentState;
46 ACCENT_POLICY accent = {ACCENT_DISABLED, 2,
static_cast<DWORD>(0), 0};
51 .cbData =
sizeof(accent)};
56 MARGINS
const margins = {-1};
65std::string GetLastErrorAsString() {
66 LPWSTR message_buffer =
nullptr;
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;
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);
88 LocalFree(message_buffer);
90 std::ostringstream oss;
91 oss <<
"Format message failed with 0x" << std::hex << std::setfill(
'0')
98bool IsClassRegistered(LPCWSTR class_name) {
99 WNDCLASSEX window_class = {};
100 return GetClassInfoEx(GetModuleHandle(
nullptr), class_name, &window_class) !=
110#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
111#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
115void UpdateTheme(HWND
window) {
117 const wchar_t kGetPreferredBrightnessRegKey[] =
118 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
119 const wchar_t kGetPreferredBrightnessRegValue[] = L
"AppsUseLightTheme";
124 DWORD light_mode_size =
sizeof(light_mode);
125 LSTATUS
const result =
127 kGetPreferredBrightnessRegValue, RRF_RT_REG_DWORD,
nullptr,
128 &light_mode, &light_mode_size);
131 BOOL enable_dark_mode = light_mode == 0;
133 &enable_dark_mode,
sizeof(enable_dark_mode));
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);
163 *
size = std::min(dst_size, *size);
164 if (*origin < dst_origin)
165 *origin = dst_origin;
167 *origin = std::min(dst_origin + dst_size, *origin + *size) - *
size;
170RECT AdjustToFit(
const RECT& parent,
const RECT& child) {
171 auto new_x = child.left;
172 auto new_y = child.top;
179 result.right = new_x + new_width;
181 result.bottom = new_y + new_height;
187 std::optional<flutter::Size> smallest, biggest;
212 window_manager,
engine, preferred_size,
213 FromWindowConstraints(preferred_constraints), title));
223 return std::unique_ptr<HostWindow>(
225 FromWindowConstraints(preferred_constraints), title,
226 parent ? parent : std::optional<HWND>()));
233 bool is_sized_to_content,
237 window_manager,
engine, FromWindowConstraints(preferred_constraints),
238 is_sized_to_content, get_position_callback, parent));
243 : window_manager_(window_manager), engine_(
engine) {}
248 auto view_window = std::make_unique<FlutterWindow>(
249 params.initial_window_rect.width(),
params.initial_window_rect.height(),
252 std::unique_ptr<FlutterWindowsView>
view =
258 std::make_unique<FlutterWindowsViewController>(
nullptr, std::move(
view));
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;
272 window_class.hInstance = GetModuleHandle(
nullptr);
274 LoadIcon(window_class.hInstance, MAKEINTRESOURCE(idi_app_icon));
275 if (!window_class.hIcon) {
276 window_class.hIcon =
LoadIcon(
nullptr, IDI_APPLICATION);
278 window_class.hCursor = LoadCursor(
nullptr, IDC_ARROW);
279 window_class.lpszClassName = kWindowClassName;
281 FML_CHECK(RegisterClassEx(&window_class));
286 params.extended_window_style, kWindowClassName,
params.title,
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,
299 DwmGetWindowAttribute(
window_handle_, DWMWA_EXTENDED_FRAME_BOUNDS,
300 &frame_rect,
sizeof(frame_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;
306 window_rect.left - left_dropshadow_width,
307 window_rect.top - top_dropshadow_height, 0, 0,
308 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
328 if (!UnregisterClass(kWindowClassName, GetModuleHandle(
nullptr))) {
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();
343 if (wcscmp(class_name, kWindowClassName) != 0) {
347 return reinterpret_cast<HostWindow*
>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
359 auto child_content =
window->view_controller_->view()->GetWindowHandle();
360 if (
window !=
nullptr && child_content !=
nullptr) {
361 SetFocus(child_content);
370 auto*
const create_struct =
reinterpret_cast<CREATESTRUCT*
>(lparam);
371 auto*
const windows_proc_table =
374 EnableTransparentWindowBackground(hwnd, *windows_proc_table);
379 return DefWindowProc(hwnd,
message, wparam, lparam);
397 case WM_NCLBUTTONDOWN: {
407 GetCursorPos(&cursorPos);
410 MAKELPARAM(cursorPos.x, cursorPos.y));
415 case WM_DPICHANGED: {
416 auto*
const new_scaled_window_rect =
reinterpret_cast<RECT*
>(lparam);
418 new_scaled_window_rect->right - new_scaled_window_rect->left;
420 new_scaled_window_rect->bottom - new_scaled_window_rect->top;
421 SetWindowPos(hwnd,
nullptr, new_scaled_window_rect->left,
423 SWP_NOZORDER | SWP_NOACTIVATE);
427 case WM_GETMINMAXINFO: {
429 GetWindowRect(hwnd, &window_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);
438 double const scale_factor =
439 static_cast<double>(dpi) / USER_DEFAULT_SCREEN_DPI;
441 MINMAXINFO* info =
reinterpret_cast<MINMAXINFO*
>(lparam);
442 Size const min_physical_size = ClampToVirtualScreen(
Size(
447 info->ptMinTrackSize.x = min_physical_size.
width();
448 info->ptMinTrackSize.y = min_physical_size.
height();
449 Size const max_physical_size = ClampToVirtualScreen(
Size(
454 info->ptMaxTrackSize.x = max_physical_size.
width();
455 info->ptMaxTrackSize.y = max_physical_size.
height();
461 if (child_content !=
nullptr) {
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);
476 case WM_DWMCOLORIZATIONCOLORCHANGED:
488 return DefWindowProc(hwnd,
message, wparam, lparam);
492 if (!
size.has_preferred_view_size) {
499 Size(
size.preferred_view_width,
size.preferred_view_height),
508 .height =
size.preferred_view_height};
514 WINDOWINFO window_info = {.cbSize =
sizeof(WINDOWINFO)};
519 Size(
size.preferred_view_width,
size.preferred_view_height),
521 window_info.dwStyle, window_info.dwExStyle,
nullptr);
528 window_size->height(),
529 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
553 auto const current_size =
Size(client_size.width, client_size.height);
554 WINDOWINFO window_info = {.cbSize =
sizeof(WINDOWINFO)};
559 window_info.dwStyle, window_info.dwExStyle,
nullptr);
561 if (window_size && current_size != window_size) {
563 window_size->height(),
564 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
576 std::optional<FlutterEngineDisplayId> display_id) {
582 WINDOWINFO window_info = {.cbSize =
sizeof(WINDOWINFO)};
604 if (
auto const display =
606 monitor =
reinterpret_cast<HMONITOR
>(display->display_id);
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 "
619 WINDOWINFO window_info = {.cbSize =
sizeof(WINDOWINFO)};
628 WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
634 SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
636 SetWindowPos(
window_handle_,
nullptr, monitor_info.rcMonitor.left,
638 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
652 SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
656 MONITORINFO monitor_info;
657 monitor_info.cbSize =
sizeof(monitor_info);
658 GetMonitorInfo(monitor, &monitor_info);
666 monitor_info.rcWork)) {
667 window_rect = AdjustToFit(monitor_info.rcWork, window_rect);
671 SetWindowPos(
window_handle_,
nullptr, window_rect.left, window_rect.top,
673 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
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);
693 SetWindowPos(
window_handle_,
nullptr, window_rect.left, window_rect.top,
695 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
701 ::CoCreateInstance(CLSID_TaskbarList,
nullptr, CLSCTX_INPROC_SERVER,
726 GetClientRect(hwnd, &rect);
728 static_cast<double>(USER_DEFAULT_SCREEN_DPI);
729 double const width = rect.right / dpr;
730 double const height = rect.bottom / dpr;
732 .width = rect.right / dpr,
733 .height = rect.bottom / dpr,
739 Size const& client_size,
740 std::optional<Size> smallest,
741 std::optional<Size> biggest,
743 DWORD extended_window_style,
744 std::optional<HWND>
const& owner_hwnd) {
746 double const scale_factor =
747 static_cast<double>(dpi) / USER_DEFAULT_SCREEN_DPI;
749 .right =
static_cast<LONG>(client_size.
width() * scale_factor),
750 .bottom =
static_cast<LONG>(client_size.
height() * scale_factor)};
753 extended_window_style, dpi)) {
754 FML_LOG(ERROR) <<
"Failed to run AdjustWindowRectExForDpi: "
755 << GetLastErrorAsString();
759 double width =
static_cast<double>(rect.right - rect.left);
760 double height =
static_cast<double>(rect.bottom - rect.top);
763 double const non_client_width =
width - (client_size.
width() * scale_factor);
764 double const non_client_height =
768 flutter::Size(smallest->width() * scale_factor + non_client_width,
769 smallest->height() * scale_factor + non_client_height));
775 flutter::Size(biggest->width() * scale_factor + non_client_width,
776 biggest->height() * scale_factor + non_client_height));
788 owned->EnableRecursively(enable);
807 std::vector<HostWindow*> owned_windows;
809 HWND owner_window_handle;
810 std::vector<HostWindow*>* owned_windows;
815 auto*
const data =
reinterpret_cast<EnumData*
>(lparam);
816 if (GetWindow(hwnd, GW_OWNER) ==
data->owner_window_handle) {
826 return owned_windows;
830 if (HWND
const owner_window_handle = GetWindow(
GetWindowHandle(), GW_OWNER)) {
841 owned->DisableRecursively();
847 if (children.empty()) {
856 auto latest_child = *std::max_element(
858 return a->view_controller_->view()->view_id() <
859 b->view_controller_->view()->view_id();
863 if (child == latest_child) {
864 child->UpdateModalStateLayer();
866 child->DisableRecursively();
void UpdateAccessibilityFeatures()
std::shared_ptr< WindowsProcTable > windows_proc_table()
std::unique_ptr< FlutterWindowsView > CreateView(std::unique_ptr< WindowBindingHandler > window, bool is_sized_to_content, const BoxConstraints &box_constraints, FlutterWindowsViewSizingDelegate *sizing_delegate=nullptr)
std::shared_ptr< DisplayManagerWin32 > display_manager()
virtual bool running() const
WindowProcDelegateManager * window_proc_delegate_manager()
Microsoft::WRL::ComPtr< ITaskbarList2 > task_bar_list_
HWND GetWindowHandle() const
BoxConstraints box_constraints_
void InitializeFlutterView(HostWindowInitializationParams const ¶ms)
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)
HWND GetFlutterViewWindowHandle() const
FlutterWindowsEngine * engine_
static HostWindow * GetThisFromHandle(HWND hwnd)
HostWindow(WindowManager *window_manager, FlutterWindowsEngine *engine)
std::vector< HostWindow * > GetOwnedWindows() const
virtual bool GetFullscreen() const
void SetConstraints(const WindowConstraints &constraints)
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)
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
const EmbeddedViewParams * params
UINT FlutterDesktopGetDpiForHWND(HWND hwnd)
#define FML_LOG(severity)
#define FML_CHECK(condition)
#define DWMWA_USE_IMMERSIVE_DARK_MODE
union flutter::testing::@2836::KeyboardChange::@77 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
WindowRect *(* GetWindowPositionCallback)(const WindowSize &child_size, const WindowRect &parent_rect, const WindowRect &output_rect)
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)