#include "flutter_window.h" #include #include #include "flutter/generated_plugin_registrant.h" // Kept out of captures altogether (Windows 10 2004 and later); older SDKs // don't name it. #ifndef WDA_EXCLUDEFROMCAPTURE #define WDA_EXCLUDEFROMCAPTURE 0x00000011 #endif namespace { // Whether this Windows keeps a window out of captures with // WDA_EXCLUDEFROMCAPTURE: Windows 10 2004 (build 19041) and later. Before, // it takes the value without failing and acts as WDA_MONITOR, so the // version decides, not a failure. RtlGetVersion tells the real version; // GetVersionEx tells what the app's manifest claims. bool ExcludesFromCapture() { using RtlGetVersionFunction = LONG(WINAPI*)(PRTL_OSVERSIONINFOW); const HMODULE ntdll = GetModuleHandleW(L"ntdll.dll"); if (!ntdll) { return false; } const auto rtl_get_version = reinterpret_cast( GetProcAddress(ntdll, "RtlGetVersion")); if (!rtl_get_version) { return false; } RTL_OSVERSIONINFOW version = {}; version.dwOSVersionInfoSize = sizeof(version); if (rtl_get_version(&version) != 0) { return false; } return version.dwMajorVersion > 10 || (version.dwMajorVersion == 10 && version.dwBuildNumber >= 19041); } } // namespace 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()); GuardScreen(); SetChildContent(flutter_controller_->view()->GetNativeWindow()); 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::GuardScreen() { screen_guard_ = std::make_unique>( flutter_controller_->engine()->messenger(), "app.halkyon/screen_guard", &flutter::StandardMethodCodec::GetInstance()); screen_guard_->SetMethodCallHandler( [this](const flutter::MethodCall& call, std::unique_ptr> result) { if (call.method_name() == "hold") { secrets_shown_++; // Before Windows 10 2004 the window shows black in captures // instead. static const bool excludes = ExcludesFromCapture(); SetWindowDisplayAffinity( GetHandle(), excludes ? WDA_EXCLUDEFROMCAPTURE : WDA_MONITOR); result->Success(); } else if (call.method_name() == "release") { secrets_shown_ = secrets_shown_ > 0 ? secrets_shown_ - 1 : 0; if (secrets_shown_ == 0) { SetWindowDisplayAffinity(GetHandle(), WDA_NONE); } result->Success(); } else { result->NotImplemented(); } }); } void FlutterWindow::OnDestroy() { screen_guard_ = nullptr; if (flutter_controller_) { flutter_controller_ = nullptr; } Win32Window::OnDestroy(); } 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); }