Skip to content

Commit bd250bd

Browse files
authored
Windows: Add dark theme support. (flutter#28131)
This PR adds the dark theme support for both windows and winuwp engine, based on flutter#54612. On Win32: using a registry value that is not documented. (I tested on Windows 10.0.19043.1165) On UWP: using default background color. (I couldn't find WinRT API that returns dark/light directly, without xaml package.) Flutter PR for win32: flutter#88520. This PR will close flutter#54612. This PR will complete one item in flutter#70214.
1 parent 0aee3c6 commit bd250bd

19 files changed

+139
-3
lines changed

shell/platform/windows/client_wrapper/flutter_engine.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ void FlutterEngine::ReloadSystemFonts() {
7474
FlutterDesktopEngineReloadSystemFonts(engine_);
7575
}
7676

77+
void FlutterEngine::ReloadPlatformBrightness() {
78+
FlutterDesktopEngineReloadPlatformBrightness(engine_);
79+
}
80+
7781
FlutterDesktopPluginRegistrarRef FlutterEngine::GetRegistrarForPlugin(
7882
const std::string& plugin_name) {
7983
if (!engine_) {

shell/platform/windows/client_wrapper/flutter_engine_unittests.cc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ class TestFlutterWindowsApi : public testing::StubFlutterWindowsApi {
4949
// |flutter::testing::StubFlutterWindowsApi|
5050
void EngineReloadSystemFonts() override { reload_fonts_called_ = true; }
5151

52+
// |flutter::testing::StubFlutterWindowsApi|
53+
void EngineReloadPlatformBrightness() override {
54+
reload_brightness_called_ = true;
55+
}
56+
5257
bool create_called() { return create_called_; }
5358

5459
bool run_called() { return run_called_; }
@@ -57,6 +62,8 @@ class TestFlutterWindowsApi : public testing::StubFlutterWindowsApi {
5762

5863
bool reload_fonts_called() { return reload_fonts_called_; }
5964

65+
bool reload_brightness_called() { return reload_brightness_called_; }
66+
6067
const std::vector<std::string>& dart_entrypoint_arguments() {
6168
return dart_entrypoint_arguments_;
6269
}
@@ -66,6 +73,7 @@ class TestFlutterWindowsApi : public testing::StubFlutterWindowsApi {
6673
bool run_called_ = false;
6774
bool destroy_called_ = false;
6875
bool reload_fonts_called_ = false;
76+
bool reload_brightness_called_ = false;
6977
std::vector<std::string> dart_entrypoint_arguments_;
7078
};
7179

@@ -124,6 +132,18 @@ TEST(FlutterEngineTest, ReloadFonts) {
124132
EXPECT_TRUE(test_api->reload_fonts_called());
125133
}
126134

135+
TEST(FlutterEngineTest, ReloadBrightness) {
136+
testing::ScopedStubFlutterWindowsApi scoped_api_stub(
137+
std::make_unique<TestFlutterWindowsApi>());
138+
auto test_api = static_cast<TestFlutterWindowsApi*>(scoped_api_stub.stub());
139+
140+
FlutterEngine engine(DartProject(L"fake/project/path"));
141+
engine.Run();
142+
143+
engine.ReloadPlatformBrightness();
144+
EXPECT_TRUE(test_api->reload_brightness_called());
145+
}
146+
127147
TEST(FlutterEngineTest, GetMessenger) {
128148
DartProject project(L"data");
129149
testing::ScopedStubFlutterWindowsApi scoped_api_stub(

shell/platform/windows/client_wrapper/include/flutter/flutter_engine.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ class FlutterEngine : public PluginRegistry {
5858
// Win32 application).
5959
void ReloadSystemFonts();
6060

61+
// Tells the engine that the platform brightness value has changed. Should be
62+
// called by clients when OS-level theme changes happen (e.g.,
63+
// WM_DWMCOLORIZATIONCOLORCHANGED in a Win32 application).
64+
void ReloadPlatformBrightness();
65+
6166
// flutter::PluginRegistry:
6267
FlutterDesktopPluginRegistrarRef GetRegistrarForPlugin(
6368
const std::string& plugin_name) override;

shell/platform/windows/client_wrapper/testing/stub_flutter_windows_api.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,13 @@ void FlutterDesktopEngineReloadSystemFonts(FlutterDesktopEngineRef engine) {
117117
}
118118
}
119119

120+
void FlutterDesktopEngineReloadPlatformBrightness(
121+
FlutterDesktopEngineRef engine) {
122+
if (s_stub_implementation) {
123+
s_stub_implementation->EngineReloadPlatformBrightness();
124+
}
125+
}
126+
120127
FlutterDesktopPluginRegistrarRef FlutterDesktopEngineGetPluginRegistrar(
121128
FlutterDesktopEngineRef engine,
122129
const char* plugin_name) {

shell/platform/windows/client_wrapper/testing/stub_flutter_windows_api.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ class StubFlutterWindowsApi {
6565
// Called for FlutterDesktopEngineReloadSystemFonts.
6666
virtual void EngineReloadSystemFonts() {}
6767

68+
// Called for FlutterDesktopEngineReloadPlatformBrightness.
69+
virtual void EngineReloadPlatformBrightness() {}
70+
6871
// Called for FlutterDesktopViewGetHWND.
6972
virtual HWND ViewGetHWND() { return reinterpret_cast<HWND>(1); }
7073

shell/platform/windows/flutter_window_win32_unittests.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ class MockWindowBindingHandlerDelegate : public WindowBindingHandlerDelegate {
222222
int,
223223
FlutterPointerDeviceKind,
224224
int32_t));
225+
MOCK_METHOD0(OnPlatformBrightnessChanged, void());
225226
};
226227

227228
// A FlutterWindowsView that overrides the RegisterKeyboardHandlers function

shell/platform/windows/flutter_window_winuwp.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ void FlutterWindowWinUWP::SetEventHandlers() {
156156
window_.PointerWheelChanged(
157157
{this, &FlutterWindowWinUWP::OnPointerWheelChanged});
158158

159+
ui_settings_.ColorValuesChanged(
160+
{this, &FlutterWindowWinUWP::OnColorValuesChanged});
161+
159162
// TODO(clarkezone) support mouse leave handling
160163
// https://github.com/flutter/flutter/issues/70199
161164

@@ -355,6 +358,12 @@ void FlutterWindowWinUWP::OnCharacterReceived(
355358
}
356359
}
357360

361+
void FlutterWindowWinUWP::OnColorValuesChanged(
362+
winrt::Windows::Foundation::IInspectable const&,
363+
winrt::Windows::Foundation::IInspectable const&) {
364+
binding_handler_delegate_->OnPlatformBrightnessChanged();
365+
}
366+
358367
bool FlutterWindowWinUWP::OnBitmapSurfaceUpdated(const void* allocation,
359368
size_t row_bytes,
360369
size_t height) {

shell/platform/windows/flutter_window_winuwp.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ class FlutterWindowWinUWP : public WindowBindingHandler {
114114
winrt::Windows::Foundation::IInspectable const&,
115115
winrt::Windows::UI::Core::CharacterReceivedEventArgs const& args);
116116

117+
// Notifies current |WindowBindingHandlerDelegate| of color values changed
118+
// events.
119+
void OnColorValuesChanged(winrt::Windows::Foundation::IInspectable const&,
120+
winrt::Windows::Foundation::IInspectable const&);
121+
117122
// Converts from logical point to physical X value.
118123
double GetPosX(winrt::Windows::UI::Core::PointerEventArgs const& args);
119124

@@ -153,6 +158,9 @@ class FlutterWindowWinUWP : public WindowBindingHandler {
153158
// SwapChain to the CoreWindow.
154159
winrt::Windows::UI::Composition::SpriteVisual render_target_{nullptr};
155160

161+
// UISettings for observing the color change.
162+
winrt::Windows::UI::ViewManagement::UISettings ui_settings_;
163+
156164
// GamepadCursorWinUWP object used to manage an emulated cursor visual driven
157165
// by gamepad.
158166
std::unique_ptr<GamepadCursorWinUWP> game_pad_cursor_{nullptr};

shell/platform/windows/flutter_windows.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,11 @@ void FlutterDesktopEngineReloadSystemFonts(FlutterDesktopEngineRef engine) {
107107
EngineFromHandle(engine)->ReloadSystemFonts();
108108
}
109109

110+
void FlutterDesktopEngineReloadPlatformBrightness(
111+
FlutterDesktopEngineRef engine) {
112+
EngineFromHandle(engine)->ReloadPlatformBrightness();
113+
}
114+
110115
FlutterDesktopPluginRegistrarRef FlutterDesktopEngineGetPluginRegistrar(
111116
FlutterDesktopEngineRef engine,
112117
const char* plugin_name) {

shell/platform/windows/flutter_windows_engine.cc

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,12 @@ void FlutterWindowsEngine::ReloadSystemFonts() {
391391
embedder_api_.ReloadSystemFonts(engine_);
392392
}
393393

394+
void FlutterWindowsEngine::ReloadPlatformBrightness() {
395+
if (engine_) {
396+
SendSystemSettings();
397+
}
398+
}
399+
394400
void FlutterWindowsEngine::SendSystemSettings() {
395401
std::vector<LanguageInfo> languages = GetPreferredLanguageInfo();
396402
std::vector<FlutterLocale> flutter_locales;
@@ -413,9 +419,8 @@ void FlutterWindowsEngine::SendSystemSettings() {
413419
settings.AddMember("alwaysUse24HourFormat",
414420
Prefer24HourTime(GetUserTimeFormat()), allocator);
415421
settings.AddMember("textScaleFactor", 1.0, allocator);
416-
// TODO: Implement dark mode support.
417-
// https://github.com/flutter/flutter/issues/54612
418-
settings.AddMember("platformBrightness", "light", allocator);
422+
settings.AddMember("platformBrightness",
423+
Utf8FromUtf16(GetPreferredBrightness()), allocator);
419424
settings_channel_->Send(settings);
420425
}
421426

shell/platform/windows/flutter_windows_engine.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ class FlutterWindowsEngine {
131131
// Informs the engine that the system font list has changed.
132132
void ReloadSystemFonts();
133133

134+
// Informs the engine that the platform brightness has changed.
135+
void ReloadPlatformBrightness();
136+
134137
// Attempts to register the texture with the given |texture_id|.
135138
bool RegisterExternalTexture(int64_t texture_id);
136139

shell/platform/windows/flutter_windows_view.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,10 @@ void FlutterWindowsView::OnScroll(double x,
249249
device_id);
250250
}
251251

252+
void FlutterWindowsView::OnPlatformBrightnessChanged() {
253+
SendPlatformBrightnessChanged();
254+
}
255+
252256
void FlutterWindowsView::OnCursorRectUpdated(const Rect& rect) {
253257
binding_handler_->OnCursorRectUpdated(rect);
254258
}
@@ -465,6 +469,11 @@ void FlutterWindowsView::SendPointerEventWithData(
465469
}
466470
}
467471

472+
void FlutterWindowsView::SendPlatformBrightnessChanged() {
473+
engine_->task_runner()->RunNowOrPostTask(
474+
[this]() { engine_->ReloadPlatformBrightness(); });
475+
};
476+
468477
bool FlutterWindowsView::MakeCurrent() {
469478
return engine_->surface_manager()->MakeCurrent();
470479
}

shell/platform/windows/flutter_windows_view.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate,
149149
FlutterPointerDeviceKind device_kind,
150150
int32_t device_id) override;
151151

152+
// |WindowBindingHandlerDelegate|
153+
void OnPlatformBrightnessChanged() override;
154+
152155
// |TextInputPluginDelegate|
153156
void OnCursorRectUpdated(const Rect& rect) override;
154157

@@ -284,6 +287,9 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate,
284287
void SendPointerEventWithData(const FlutterPointerEvent& event_data,
285288
PointerState* state);
286289

290+
// Reports platform brightness change to Flutter engine.
291+
void SendPlatformBrightnessChanged();
292+
287293
// Currently configured WindowsRenderTarget for this view used by
288294
// surface_manager for creation of render surfaces and bound to the physical
289295
// os window.

shell/platform/windows/public/flutter_windows.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,9 @@ FlutterDesktopEngineProcessMessages(FlutterDesktopEngineRef engine);
174174
FLUTTER_EXPORT void FlutterDesktopEngineReloadSystemFonts(
175175
FlutterDesktopEngineRef engine);
176176

177+
FLUTTER_EXPORT void FlutterDesktopEngineReloadPlatformBrightness(
178+
FlutterDesktopEngineRef engine);
179+
177180
// Returns the plugin registrar handle for the plugin with the given name.
178181
//
179182
// The name must be unique across the application.

shell/platform/windows/system_utils.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212

1313
namespace flutter {
1414

15+
namespace {
16+
static constexpr wchar_t kPlatformBrightnessLight[] = L"light";
17+
static constexpr wchar_t kPlatformBrightnessDark[] = L"dark";
18+
} // namespace
19+
1520
// Components of a system language/locale.
1621
struct LanguageInfo {
1722
std::string language;
@@ -37,6 +42,9 @@ std::wstring GetUserTimeFormat();
3742
// Returns true if the time_format is set to use 24 hour time.
3843
bool Prefer24HourTime(std::wstring time_format);
3944

45+
// Returns the user-preferred brightness.
46+
std::wstring GetPreferredBrightness();
47+
4048
} // namespace flutter
4149

4250
#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_SYSTEM_UTILS_H_

shell/platform/windows/system_utils_unittests.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,5 +88,10 @@ TEST(SystemUtils, Prefer24HourTimeHandles24Hour) {
8888
EXPECT_TRUE(Prefer24HourTime(L"HH:mm:ss"));
8989
}
9090

91+
TEST(SystemUtils, GetPreferredBrightness) {
92+
std::wstring brightness = GetPreferredBrightness();
93+
EXPECT_TRUE(brightness == L"light" || brightness == L"dark");
94+
}
95+
9196
} // namespace testing
9297
} // namespace flutter

shell/platform/windows/system_utils_win32.cc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,22 @@ bool Prefer24HourTime(std::wstring time_format) {
106106
return time_format.find(L"H") != std::wstring::npos;
107107
}
108108

109+
std::wstring GetPreferredBrightness() {
110+
DWORD use_light_theme;
111+
DWORD use_light_theme_size = sizeof(use_light_theme);
112+
LONG result = RegGetValue(
113+
HKEY_CURRENT_USER,
114+
L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
115+
L"AppsUseLightTheme", RRF_RT_REG_DWORD, nullptr, &use_light_theme,
116+
&use_light_theme_size);
117+
118+
if (result == 0) {
119+
return use_light_theme ? kPlatformBrightnessLight : kPlatformBrightnessDark;
120+
} else {
121+
// The current OS does not support dark mode. (Older Windows 10 or before
122+
// Windows 10)
123+
return kPlatformBrightnessLight;
124+
}
125+
}
126+
109127
} // namespace flutter

shell/platform/windows/system_utils_winuwp.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
#include "third_party/cppwinrt/generated/winrt/Windows.Foundation.Collections.h"
1212
#include "third_party/cppwinrt/generated/winrt/Windows.System.UserProfile.h"
13+
#include "third_party/cppwinrt/generated/winrt/Windows.UI.ViewManagement.h"
14+
#include "third_party/cppwinrt/generated/winrt/Windows.UI.h"
1315

1416
#include "flutter/shell/platform/windows/string_conversion.h"
1517

@@ -80,4 +82,16 @@ bool Prefer24HourTime(std::wstring time_format) {
8082
return time_format.find(L"H") != std::wstring::npos;
8183
}
8284

85+
std::wstring GetPreferredBrightness() {
86+
winrt::Windows::UI::ViewManagement::UISettings ui_settings;
87+
auto background_color = ui_settings.GetColorValue(
88+
winrt::Windows::UI::ViewManagement::UIColorType::Background);
89+
// Assuming that Windows return `Colors::Black` when being dark theme.
90+
if (background_color == winrt::Windows::UI::Colors::Black()) {
91+
return kPlatformBrightnessDark;
92+
} else {
93+
return kPlatformBrightnessLight;
94+
}
95+
}
96+
8397
} // namespace flutter

shell/platform/windows/window_binding_handler_delegate.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ class WindowBindingHandlerDelegate {
9595
int scroll_offset_multiplier,
9696
FlutterPointerDeviceKind device_kind,
9797
int32_t device_id) = 0;
98+
99+
// Notifies delegate that backing window has received brightness change event.
100+
virtual void OnPlatformBrightnessChanged() = 0;
98101
};
99102

100103
} // namespace flutter

0 commit comments

Comments
 (0)