blob: 094184703a0309238fa1ff865443dfc40a97029e [file] [log] [blame]
// 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