From e331fb1feda8891baba2a2dc1caeed67834d9d93 Mon Sep 17 00:00:00 2001
From: Zhao Yuhang <2546789017@qq.com>
Date: 周五, 22 12月 2023 23:47:22 +0800
Subject: [PATCH] improve dark mode on win

---
 src/core/shared/qwkwindowsextra_p.h      |   39 +++++++++++++++++++
 src/core/qwindowkit_windows.h            |    7 +++
 src/core/contexts/win32windowcontext.cpp |   16 +++++--
 3 files changed, 57 insertions(+), 5 deletions(-)

diff --git a/src/core/contexts/win32windowcontext.cpp b/src/core/contexts/win32windowcontext.cpp
index ede9504..19f1864 100644
--- a/src/core/contexts/win32windowcontext.cpp
+++ b/src/core/contexts/win32windowcontext.cpp
@@ -937,18 +937,24 @@
             if (!isWin101809OrGreater()) {
                 return false;
             }
+
             BOOL enable = attribute.toBool();
+
+            if (isWin101903OrGreater()) {
+                apis.pSetPreferredAppMode(enable ? PAM_AUTO : PAM_DEFAULT);
+            } else {
+                apis.pAllowDarkModeForApp(enable);
+            }
+
             for (const auto attr : {
                     _DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1,
                     _DWMWA_USE_IMMERSIVE_DARK_MODE,
             }) {
                 apis.pDwmSetWindowAttribute(hwnd, attr, &enable, sizeof(enable));
             }
-            WINDOWCOMPOSITIONATTRIBDATA wcad{};
-            wcad.Attrib = WCA_USEDARKMODECOLORS;
-            wcad.pvData = &enable;
-            wcad.cbData = sizeof(enable);
-            apis.pSetWindowCompositionAttribute(hwnd, &wcad);
+
+            apis.pFlushMenuThemes();
+
             return true;
         }
         return false;
diff --git a/src/core/qwindowkit_windows.h b/src/core/qwindowkit_windows.h
index 5dfe712..8a98124 100644
--- a/src/core/qwindowkit_windows.h
+++ b/src/core/qwindowkit_windows.h
@@ -65,6 +65,13 @@
                 rovi.dwBuildNumber >= 22000);
     }
 
+    inline bool IsWindows101903OrGreater_Real() {
+        RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
+        return (rovi.dwMajorVersion > 10) ||
+               (rovi.dwMajorVersion == 10 && rovi.dwMinorVersion >= 0 &&
+                rovi.dwBuildNumber >= 18362);
+    }
+
     inline bool IsWindows101809OrGreater_Real() {
         RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
         return (rovi.dwMajorVersion > 10) ||
diff --git a/src/core/shared/qwkwindowsextra_p.h b/src/core/shared/qwkwindowsextra_p.h
index baddc07..df97727 100644
--- a/src/core/shared/qwkwindowsextra_p.h
+++ b/src/core/shared/qwkwindowsextra_p.h
@@ -132,7 +132,24 @@
     };
     using PWINDOWCOMPOSITIONATTRIBDATA = WINDOWCOMPOSITIONATTRIBDATA *;
 
+    enum PREFERRED_APP_MODE
+    {
+        PAM_DEFAULT = 0, // Default behavior on systems before Win10 1809. It indicates the application doesn't support dark mode at all.
+        PAM_AUTO = 1, // Available since Win10 1809, let system decide whether to enable dark mode or not.
+        PAM_DARK = 2, // Available since Win10 1903, force dark mode regardless of the system theme.
+        PAM_LIGHT = 3, // Available since Win10 1903, force light mode regardless of the system theme.
+        PAM_MAX = 4
+    };
+
     using SetWindowCompositionAttributePtr = BOOL(WINAPI *)(HWND, PWINDOWCOMPOSITIONATTRIBDATA);
+
+    // Win10 1809 (10.0.17763)
+    using RefreshImmersiveColorPolicyStatePtr = VOID(WINAPI *)(VOID); // Ordinal 104
+    using AllowDarkModeForWindowPtr = BOOL(WINAPI *)(HWND, BOOL); // Ordinal 133
+    using AllowDarkModeForAppPtr = BOOL(WINAPI *)(BOOL); // Ordinal 135
+    using FlushMenuThemesPtr = VOID(WINAPI *)(VOID); // Ordinal 136
+    // Win10 1903 (10.0.18362)
+    using SetPreferredAppModePtr = PREFERRED_APP_MODE(WINAPI *)(PREFERRED_APP_MODE); // Ordinal 135
 
     namespace {
 
@@ -161,6 +178,11 @@
 #undef DYNAMIC_API_DECLARE
 
             SetWindowCompositionAttributePtr pSetWindowCompositionAttribute = nullptr;
+            RefreshImmersiveColorPolicyStatePtr pRefreshImmersiveColorPolicyState = nullptr;
+            AllowDarkModeForWindowPtr pAllowDarkModeForWindow = nullptr;
+            AllowDarkModeForAppPtr pAllowDarkModeForApp = nullptr;
+            FlushMenuThemesPtr pFlushMenuThemes = nullptr;
+            SetPreferredAppModePtr pSetPreferredAppMode = nullptr;
 
         private:
             DynamicApis() {
@@ -190,6 +212,18 @@
                 DYNAMIC_API_RESOLVE(winmm, timeEndPeriod);
 
 #undef DYNAMIC_API_RESOLVE
+
+#define UNDOC_API_RESOLVE(DLL, NAME, ORDINAL)                                                             \
+    p##NAME = reinterpret_cast<decltype(p##NAME)>(DLL.resolve(MAKEINTRESOURCEA(ORDINAL)))
+
+                QSystemLibrary uxtheme(QStringLiteral("uxtheme"));
+                UNDOC_API_RESOLVE(uxtheme, RefreshImmersiveColorPolicyState, 104);
+                UNDOC_API_RESOLVE(uxtheme, AllowDarkModeForWindow, 133);
+                UNDOC_API_RESOLVE(uxtheme, AllowDarkModeForApp, 135);
+                UNDOC_API_RESOLVE(uxtheme, FlushMenuThemes, 136);
+                UNDOC_API_RESOLVE(uxtheme, SetPreferredAppMode, 135);
+
+#undef UNDOC_API_RESOLVE
             }
 
             ~DynamicApis() = default;
@@ -299,6 +333,11 @@
         return result;
     }
 
+    static inline bool isWin101903OrGreater() {
+        static const bool result = IsWindows101903OrGreater_Real();
+        return result;
+    }
+
     static inline bool isWin11OrGreater() {
         static const bool result = IsWindows11OrGreater_Real();
         return result;

--
Gitblit v1.9.1