Wire Up Windows Dark Mode to NativeThemeWin

The Dark/Light mode toggle in System Settings appears to be intended
for UWP apps, so this change needs to be slightly more creative about
checking this state.

This change checks and monitors AppsUseLightTheme in HKCU's theme area,
which is not an API guarantee. Future versions of Windows could change
the way this is persisted and subsequently break this change.

BUG=838670

Change-Id: Ic84341ae69e2bb9cd988f9bea027052033c66360
Reviewed-on: https://chromium-review.googlesource.com/c/1429963
Reviewed-by: Elly Fong-Jones <ellyjones@chromium.org>
Commit-Queue: Robert Liao <robliao@chromium.org>
Cr-Commit-Position: refs/heads/master@{#625331}
diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc
index aceb7232..bc7b496 100644
--- a/ui/native_theme/native_theme_win.cc
+++ b/ui/native_theme/native_theme_win.cc
@@ -10,7 +10,9 @@
 #include <vsstyle.h>
 #include <vssym32.h>
 
+#include "base/bind.h"
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/logging.h"
 #include "base/stl_util.h"
 #include "base/win/scoped_gdi_object.h"
@@ -28,6 +30,7 @@
 #include "third_party/skia/include/core/SkRefCnt.h"
 #include "third_party/skia/include/core/SkShader.h"
 #include "third_party/skia/include/core/SkSurface.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/display/win/screen_win.h"
 #include "ui/gfx/color_palette.h"
@@ -253,6 +256,19 @@
     close_theme_ = reinterpret_cast<CloseThemeDataPtr>(
         GetProcAddress(theme_dll_, "CloseThemeData"));
   }
+  if (base::FeatureList::IsEnabled(features::kDarkMode)) {
+    // Dark Mode currently targets UWP apps, which means Win32 apps need to use
+    // alternate, less reliable means of detecting the state. The following
+    // can break in future Windows versions.
+    bool key_open_succeeded =
+        hkcu_themes_regkey_.Open(
+            HKEY_CURRENT_USER,
+            L"Software\\Microsoft\\Windows\\CurrentVersion\\"
+            L"Themes\\Personalize",
+            KEY_READ | KEY_NOTIFY) == ERROR_SUCCESS;
+    if (key_open_succeeded)
+      RegisterThemeRegkeyObserver();
+  }
   memset(theme_handles_, 0, sizeof(theme_handles_));
 
   // Initialize the cached system colors.
@@ -562,6 +578,17 @@
   return force_enabled || IsUsingHighContrastThemeInternal();
 }
 
+bool NativeThemeWin::SystemDarkModeEnabled() const {
+  bool fDarkModeEnabled = false;
+  if (hkcu_themes_regkey_.Valid()) {
+    DWORD apps_use_light_theme = 1;
+    hkcu_themes_regkey_.ReadValueDW(L"AppsUseLightTheme",
+                                    &apps_use_light_theme);
+    fDarkModeEnabled = (apps_use_light_theme == 0);
+  }
+  return fDarkModeEnabled || NativeTheme::SystemDarkModeEnabled();
+}
+
 void NativeThemeWin::PaintIndirect(cc::PaintCanvas* destination_canvas,
                                    Part part,
                                    State state,
@@ -1890,4 +1917,16 @@
   return handle;
 }
 
+void NativeThemeWin::RegisterThemeRegkeyObserver() {
+  DCHECK(hkcu_themes_regkey_.Valid());
+  hkcu_themes_regkey_.StartWatching(base::BindRepeating(
+      [](NativeThemeWin* native_theme) {
+        native_theme->NotifyObservers();
+        // RegKey::StartWatching only provides one notification. Reregistration
+        // is required to get future notifications.
+        native_theme->RegisterThemeRegkeyObserver();
+      },
+      base::Unretained(this)));
+}
+
 }  // namespace ui
diff --git a/ui/native_theme/native_theme_win.h b/ui/native_theme/native_theme_win.h
index 9ee7350..cdc2157 100644
--- a/ui/native_theme/native_theme_win.h
+++ b/ui/native_theme/native_theme_win.h
@@ -19,6 +19,7 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/no_destructor.h"
+#include "base/win/registry.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/sys_color_change_listener.h"
@@ -80,6 +81,7 @@
   gfx::Size GetNinePatchCanvasSize(Part part) const override;
   gfx::Rect GetNinePatchAperture(Part part) const override;
   bool UsesHighContrastColors() const override;
+  bool SystemDarkModeEnabled() const override;
 
  protected:
   friend class NativeTheme;
@@ -260,6 +262,8 @@
   // Returns a handle to the theme data.
   HANDLE GetThemeHandle(ThemeName theme_name) const;
 
+  void RegisterThemeRegkeyObserver();
+
   typedef HRESULT (WINAPI* DrawThemeBackgroundPtr)(HANDLE theme,
                                                    HDC hdc,
                                                    int part_id,
@@ -314,6 +318,9 @@
   // Handle to uxtheme.dll.
   HMODULE theme_dll_;
 
+  // Dark Mode registry key.
+  base::win::RegKey hkcu_themes_regkey_;
+
   // A cache of open theme handles.
   mutable HANDLE theme_handles_[LAST];