| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "flutter_window.h" |
| |
| #include <optional> |
| #include <mutex> |
| |
| #include <dwmapi.h> |
| #include <flutter/method_channel.h> |
| #include <flutter/standard_method_codec.h> |
| |
| #include "flutter/generated_plugin_registrant.h" |
| |
| /// Window attribute that enables dark mode window decorations. |
| /// |
| /// Redefined in case the developer's machine has a Windows SDK older than |
| /// version 10.0.22000.0. |
| /// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute |
| #ifndef DWMWA_USE_IMMERSIVE_DARK_MODE |
| #define DWMWA_USE_IMMERSIVE_DARK_MODE 20 |
| #endif |
| |
| /// Registry key for app theme preference. |
| /// |
| /// A value of 0 indicates apps should use dark mode. A non-zero or missing |
| /// value indicates apps should use light mode. |
| constexpr const wchar_t kGetPreferredBrightnessRegKey[] = |
| L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; |
| constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; |
| |
| 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<flutter::FlutterViewController>( |
| 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()); |
| |
| static std::mutex visible_mutex; |
| static bool visible = false; |
| |
| flutter_controller_->engine()->SetNextFrameCallback([&]() { |
| std::scoped_lock lock(visible_mutex); |
| this->Show(); |
| visible = true; |
| }); |
| |
| // Create a method channel to check the window's visibility. |
| flutter::MethodChannel<> channel( |
| flutter_controller_->engine()->messenger(), "tests.flutter.dev/windows_startup_test", |
| &flutter::StandardMethodCodec::GetInstance()); |
| |
| channel.SetMethodCallHandler( |
| [&](const flutter::MethodCall<>& call, |
| std::unique_ptr<flutter::MethodResult<>> result) { |
| std::string method = call.method_name(); |
| |
| if (method == "isWindowVisible") { |
| std::scoped_lock lock(visible_mutex); |
| result->Success(visible); |
| } else if (method == "isAppDarkModeEnabled") { |
| BOOL enabled; |
| HRESULT hr = DwmGetWindowAttribute(GetHandle(), |
| DWMWA_USE_IMMERSIVE_DARK_MODE, |
| &enabled, sizeof(enabled)); |
| if (SUCCEEDED(hr)) { |
| result->Success((bool)enabled); |
| } else if (hr == E_INVALIDARG) { |
| // Fallback if the operating system doesn't support dark mode. |
| result->Success(false); |
| } else { |
| result->Error("error", "Received result handle " + hr); |
| } |
| } else if (method == "isSystemDarkModeEnabled") { |
| DWORD data; |
| DWORD data_size = sizeof(data); |
| LONG status = RegGetValue(HKEY_CURRENT_USER, |
| kGetPreferredBrightnessRegKey, |
| kGetPreferredBrightnessRegValue, |
| RRF_RT_REG_DWORD, nullptr, &data, &data_size); |
| |
| if (status == ERROR_SUCCESS) { |
| // Preferred brightness is 0 if dark mode is enabled, |
| // otherwise non-zero. |
| result->Success(data == 0); |
| } else if (status == ERROR_FILE_NOT_FOUND) { |
| // Fallback if the operating system doesn't support dark mode. |
| result->Success(false); |
| } else { |
| result->Error("error", "Received status " + status); |
| } |
| } else { |
| result->NotImplemented(); |
| } |
| }); |
| |
| return true; |
| } |
| |
| void FlutterWindow::OnDestroy() { |
| 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<LRESULT> 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); |
| } |