#include "flutter_window.h" #include #include #include "flutter/generated_plugin_registrant.h" FlutterWindow::FlutterWindow(const flutter::DartProject& project) : project_(project) {} FlutterWindow::~FlutterWindow() {} bool FlutterWindow::OnCreate() { if (!Win32Window::OnCreate()) { return false; } RECT frame = GetClientArea(); // The size here must match the window dimensions to avoid unnecessary surface // creation / destruction in the startup path. flutter_controller_ = std::make_unique( frame.right - frame.left, frame.bottom - frame.top, project_); // Ensure that basic setup of the controller was successful. if (!flutter_controller_->engine() || !flutter_controller_->view()) { return false; } RegisterPlugins(flutter_controller_->engine()); SetChildContent(flutter_controller_->view()->GetNativeWindow()); // 注册窗口控制通道:Dart 端可请求按视频比例调整窗口尺寸。 window_channel_ = std::make_unique>( flutter_controller_->engine()->messenger(), "app/window", &flutter::StandardMethodCodec::GetInstance()); window_channel_->SetMethodCallHandler( [this](const flutter::MethodCall& call, std::unique_ptr> result) { if (call.method_name() == "resizeToVideoAspect") { double aspect = 0.0; if (const auto* value = std::get_if(call.arguments())) { aspect = *value; } else if (const auto* ivalue = std::get_if(call.arguments())) { aspect = static_cast(*ivalue); } ResizeToVideoAspect(aspect); result->Success(); } else { result->NotImplemented(); } }); flutter_controller_->engine()->SetNextFrameCallback([&]() { this->Show(); }); // Flutter can complete the first frame before the "show window" callback is // registered. The following call ensures a frame is pending to ensure the // window is shown. It is a no-op if the first frame hasn't completed yet. flutter_controller_->ForceRedraw(); return true; } void FlutterWindow::OnDestroy() { if (flutter_controller_) { flutter_controller_ = nullptr; } Win32Window::OnDestroy(); } void FlutterWindow::ResizeToVideoAspect(double aspect) { if (aspect <= 0.0) { return; } HWND hwnd = GetHandle(); if (!hwnd) { return; } RECT window_rect; RECT client_rect; GetWindowRect(hwnd, &window_rect); GetClientRect(hwnd, &client_rect); const int window_w = window_rect.right - window_rect.left; const int window_h = window_rect.bottom - window_rect.top; const int client_w = client_rect.right - client_rect.left; const int client_h = client_rect.bottom - client_rect.top; // 边框(含标题栏)占用的额外像素。 const int border_w = window_w - client_w; const int border_h = window_h - client_h; // 保持窗口宽度不变,按比例计算客户区高度。 int target_client_w = client_w; int target_client_h = static_cast(target_client_w / aspect + 0.5); int target_window_w = window_w; int target_window_h = target_client_h + border_h; // 获取窗口所在显示器的可用工作区。 HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); MONITORINFO monitor_info; monitor_info.cbSize = sizeof(MONITORINFO); GetMonitorInfo(monitor, &monitor_info); const int work_h = monitor_info.rcWork.bottom - monitor_info.rcWork.top; // 高度超出屏幕:改为以屏幕高度为准的合适窗口大小。 if (target_window_h > work_h) { target_window_h = work_h; target_client_h = target_window_h - border_h; target_client_w = static_cast(target_client_h * aspect + 0.5); target_window_w = target_client_w + border_w; } // 计算位置:尽量保持当前左上角,同时确保窗口落在工作区内。 int new_left = window_rect.left; int new_top = window_rect.top; if (new_left + target_window_w > monitor_info.rcWork.right) { new_left = monitor_info.rcWork.right - target_window_w; } if (new_top + target_window_h > monitor_info.rcWork.bottom) { new_top = monitor_info.rcWork.bottom - target_window_h; } if (new_left < monitor_info.rcWork.left) { new_left = monitor_info.rcWork.left; } if (new_top < monitor_info.rcWork.top) { new_top = monitor_info.rcWork.top; } SetWindowPos(hwnd, nullptr, new_left, new_top, target_window_w, target_window_h, SWP_NOZORDER | SWP_NOACTIVATE); } LRESULT FlutterWindow::MessageHandler(HWND hwnd, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { // Give Flutter, including plugins, an opportunity to handle window messages. if (flutter_controller_) { std::optional result = flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, lparam); if (result) { return *result; } } switch (message) { case WM_FONTCHANGE: flutter_controller_->engine()->ReloadSystemFonts(); break; } return Win32Window::MessageHandler(hwnd, message, wparam, lparam); }