| // Copyright 2013 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/shell/platform/windows/settings_plugin.h" | |
| #include "flutter/shell/platform/common/json_message_codec.h" | |
| #include "flutter/shell/platform/windows/system_utils.h" | |
| namespace flutter { | |
| namespace { | |
| constexpr char kChannelName[] = "flutter/settings"; | |
| constexpr char kAlwaysUse24HourFormat[] = "alwaysUse24HourFormat"; | |
| constexpr char kTextScaleFactor[] = "textScaleFactor"; | |
| constexpr char kPlatformBrightness[] = "platformBrightness"; | |
| constexpr char kPlatformBrightnessDark[] = "dark"; | |
| constexpr char kPlatformBrightnessLight[] = "light"; | |
| constexpr wchar_t kGetPreferredBrightnessRegKey[] = | |
| L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; | |
| constexpr wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; | |
| constexpr wchar_t kGetTextScaleFactorRegKey[] = | |
| L"Software\\Microsoft\\Accessibility"; | |
| constexpr wchar_t kGetTextScaleFactorRegValue[] = L"TextScaleFactor"; | |
| // Return an approximation of the apparent luminance of a given color. | |
| int GetLuminance(DWORD color) { | |
| int r = GetRValue(color); | |
| int g = GetGValue(color); | |
| int b = GetBValue(color); | |
| return (r + r + r + b + (g << 2)) >> 3; | |
| } | |
| // Return kLight if light mode for apps is selected, otherwise return kDark. | |
| SettingsPlugin::PlatformBrightness GetThemeBrightness() { | |
| DWORD use_light_theme; | |
| DWORD use_light_theme_size = sizeof(use_light_theme); | |
| LONG result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, | |
| kGetPreferredBrightnessRegValue, RRF_RT_REG_DWORD, | |
| nullptr, &use_light_theme, &use_light_theme_size); | |
| if (result == 0) { | |
| return use_light_theme ? SettingsPlugin::PlatformBrightness::kLight | |
| : SettingsPlugin::PlatformBrightness::kDark; | |
| } else { | |
| // The current OS does not support dark mode. (Older Windows 10 or before | |
| // Windows 10) | |
| return SettingsPlugin::PlatformBrightness::kLight; | |
| } | |
| } | |
| } // namespace | |
| SettingsPlugin::SettingsPlugin(BinaryMessenger* messenger, | |
| TaskRunner* task_runner) | |
| : channel_(std::make_unique<BasicMessageChannel<rapidjson::Document>>( | |
| messenger, | |
| kChannelName, | |
| &JsonMessageCodec::GetInstance())), | |
| task_runner_(task_runner) {} | |
| SettingsPlugin::~SettingsPlugin() { | |
| StopWatching(); | |
| } | |
| void SettingsPlugin::SendSettings() { | |
| rapidjson::Document settings(rapidjson::kObjectType); | |
| auto& allocator = settings.GetAllocator(); | |
| settings.AddMember(kAlwaysUse24HourFormat, GetAlwaysUse24HourFormat(), | |
| allocator); | |
| settings.AddMember(kTextScaleFactor, GetTextScaleFactor(), allocator); | |
| if (GetPreferredBrightness() == PlatformBrightness::kDark) { | |
| settings.AddMember(kPlatformBrightness, kPlatformBrightnessDark, allocator); | |
| } else { | |
| settings.AddMember(kPlatformBrightness, kPlatformBrightnessLight, | |
| allocator); | |
| } | |
| channel_->Send(settings); | |
| } | |
| void SettingsPlugin::StartWatching() { | |
| RegOpenKeyEx(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, | |
| RRF_RT_REG_DWORD, KEY_NOTIFY, &preferred_brightness_reg_hkey_); | |
| RegOpenKeyEx(HKEY_CURRENT_USER, kGetTextScaleFactorRegKey, RRF_RT_REG_DWORD, | |
| KEY_NOTIFY, &text_scale_factor_reg_hkey_); | |
| // Start watching when the keys exist. | |
| if (preferred_brightness_reg_hkey_ != nullptr) { | |
| WatchPreferredBrightnessChanged(); | |
| } | |
| if (text_scale_factor_reg_hkey_ != nullptr) { | |
| WatchTextScaleFactorChanged(); | |
| } | |
| } | |
| void SettingsPlugin::StopWatching() { | |
| preferred_brightness_changed_watcher_ = nullptr; | |
| text_scale_factor_changed_watcher_ = nullptr; | |
| if (preferred_brightness_reg_hkey_ != nullptr) { | |
| RegCloseKey(preferred_brightness_reg_hkey_); | |
| } | |
| if (text_scale_factor_reg_hkey_ != nullptr) { | |
| RegCloseKey(text_scale_factor_reg_hkey_); | |
| } | |
| } | |
| bool SettingsPlugin::GetAlwaysUse24HourFormat() { | |
| return Prefer24HourTime(GetUserTimeFormat()); | |
| } | |
| float SettingsPlugin::GetTextScaleFactor() { | |
| DWORD text_scale_factor; | |
| DWORD text_scale_factor_size = sizeof(text_scale_factor); | |
| LONG result = RegGetValue( | |
| HKEY_CURRENT_USER, kGetTextScaleFactorRegKey, kGetTextScaleFactorRegValue, | |
| RRF_RT_REG_DWORD, nullptr, &text_scale_factor, &text_scale_factor_size); | |
| if (result == 0) { | |
| return text_scale_factor / 100.0; | |
| } else { | |
| // The current OS does not have text scale factor. | |
| return 1.0; | |
| } | |
| } | |
| SettingsPlugin::PlatformBrightness SettingsPlugin::GetPreferredBrightness() { | |
| if (is_high_contrast_) { | |
| DWORD window_color = GetSysColor(COLOR_WINDOW); | |
| int luminance = GetLuminance(window_color); | |
| return luminance >= 127 ? SettingsPlugin::PlatformBrightness::kLight | |
| : SettingsPlugin::PlatformBrightness::kDark; | |
| } else { | |
| return GetThemeBrightness(); | |
| } | |
| } | |
| void SettingsPlugin::WatchPreferredBrightnessChanged() { | |
| preferred_brightness_changed_watcher_ = | |
| std::make_unique<EventWatcher>([this]() { | |
| task_runner_->PostTask([this]() { | |
| SendSettings(); | |
| WatchPreferredBrightnessChanged(); | |
| }); | |
| }); | |
| RegNotifyChangeKeyValue( | |
| preferred_brightness_reg_hkey_, FALSE, REG_NOTIFY_CHANGE_LAST_SET, | |
| preferred_brightness_changed_watcher_->GetHandle(), TRUE); | |
| } | |
| void SettingsPlugin::WatchTextScaleFactorChanged() { | |
| text_scale_factor_changed_watcher_ = std::make_unique<EventWatcher>([this]() { | |
| task_runner_->PostTask([this]() { | |
| SendSettings(); | |
| WatchTextScaleFactorChanged(); | |
| }); | |
| }); | |
| RegNotifyChangeKeyValue( | |
| text_scale_factor_reg_hkey_, FALSE, REG_NOTIFY_CHANGE_LAST_SET, | |
| text_scale_factor_changed_watcher_->GetHandle(), TRUE); | |
| } | |
| void SettingsPlugin::UpdateHighContrastMode(bool is_high_contrast) { | |
| is_high_contrast_ = is_high_contrast; | |
| SendSettings(); | |
| } | |
| } // namespace flutter |