From c8a5a82994e513acb00ba0e1f0b882ccbb18a6db Mon Sep 17 00:00:00 2001
From: Sine Striker <trueful@163.com>
Date: 周二, 26 12月 2023 05:15:47 +0800
Subject: [PATCH] clean code

---
 src/core/contexts/win32windowcontext_p.h |    2 
 src/widgets/widgetwindowagent_win.cpp    |   98 +++++++++++-----
 src/core/style/styleagent_win.cpp        |    4 
 src/core/shared/qwkwindowsextra_p.h      |   61 ++--------
 src/quick/quickwindowagent_win.cpp       |    8 
 src/core/qwindowkit_windows.h            |  125 +++++++++++++++-----
 src/core/qwindowkit_windows.cpp          |   29 +++-
 src/core/contexts/win32windowcontext.cpp |    5 
 8 files changed, 199 insertions(+), 133 deletions(-)

diff --git a/src/core/contexts/win32windowcontext.cpp b/src/core/contexts/win32windowcontext.cpp
index 98f47d6..8f5a9b6 100644
--- a/src/core/contexts/win32windowcontext.cpp
+++ b/src/core/contexts/win32windowcontext.cpp
@@ -9,7 +9,6 @@
 #include <QtGui/QGuiApplication>
 #include <QtGui/QPainter>
 #include <QtGui/QPalette>
-#include <QtGui/QStyleHints>
 
 #include <QtGui/private/qhighdpiscaling_p.h>
 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
@@ -1319,12 +1318,12 @@
                                                  LPARAM lParam, LRESULT *result) {
         switch (message) {
             case WM_SHOWWINDOW: {
-                if (!centered) {
+                if (!initialCentered) {
                     // If wParam is TRUE, the window is being shown.
                     // If lParam is zero, the message was sent because of a call to the ShowWindow
                     // function.
                     if (wParam && !lParam) {
-                        centered = true;
+                        initialCentered = true;
                         moveWindowToDesktopCenter(hWnd);
                     }
                 }
diff --git a/src/core/contexts/win32windowcontext_p.h b/src/core/contexts/win32windowcontext_p.h
index 6a01e16..ca64faf 100644
--- a/src/core/contexts/win32windowcontext_p.h
+++ b/src/core/contexts/win32windowcontext_p.h
@@ -69,7 +69,7 @@
         // WM_MOUSELEAVE.
         bool mouseLeaveBlocked = false;
 
-        bool centered = false;
+        bool initialCentered = false;
     };
 
 }
diff --git a/src/core/qwindowkit_windows.cpp b/src/core/qwindowkit_windows.cpp
index b74167f..8292de5 100644
--- a/src/core/qwindowkit_windows.cpp
+++ b/src/core/qwindowkit_windows.cpp
@@ -2,17 +2,24 @@
 
 namespace QWK {
 
-    RTL_OSVERSIONINFOW GetRealOSVersion() {
-        static const auto result = []() -> RTL_OSVERSIONINFOW {
-            HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll");
-            using RtlGetVersionPtr = NTSTATUS(WINAPI *)(PRTL_OSVERSIONINFOW);
-            auto pRtlGetVersion = reinterpret_cast<RtlGetVersionPtr>(::GetProcAddress(hMod, "RtlGetVersion"));
-            RTL_OSVERSIONINFOW rovi{};
-            rovi.dwOSVersionInfoSize = sizeof(rovi);
-            pRtlGetVersion(&rovi);
-            return rovi;
-        }();
-        return result;
+    static RTL_OSVERSIONINFOW GetRealOSVersionImpl() {
+        HMODULE hMod = ::GetModuleHandleW(L"ntdll.dll");
+        using RtlGetVersionPtr = NTSTATUS(WINAPI *)(PRTL_OSVERSIONINFOW);
+        auto pRtlGetVersion =
+            reinterpret_cast<RtlGetVersionPtr>(::GetProcAddress(hMod, "RtlGetVersion"));
+        RTL_OSVERSIONINFOW rovi{};
+        rovi.dwOSVersionInfoSize = sizeof(rovi);
+        pRtlGetVersion(&rovi);
+        return rovi;
+    }
+
+    namespace Private {
+
+        RTL_OSVERSIONINFOW GetRealOSVersion() {
+            static const auto result = GetRealOSVersionImpl();
+            return result;
+        }
+
     }
 
 }
\ No newline at end of file
diff --git a/src/core/qwindowkit_windows.h b/src/core/qwindowkit_windows.h
index 998939f..8b3448b 100644
--- a/src/core/qwindowkit_windows.h
+++ b/src/core/qwindowkit_windows.h
@@ -49,54 +49,113 @@
 
 namespace QWK {
 
-    QWK_CORE_EXPORT RTL_OSVERSIONINFOW GetRealOSVersion();
+    namespace Private {
 
-    inline bool IsWindows1122H2OrGreater_Real() {
-        RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
-        return (rovi.dwMajorVersion > 10) ||
-               (rovi.dwMajorVersion == 10 && rovi.dwMinorVersion >= 0 &&
-                rovi.dwBuildNumber >= 22621);
+        QWK_CORE_EXPORT RTL_OSVERSIONINFOW GetRealOSVersion();
+
+        inline bool IsWindows1122H2OrGreater_Real() {
+            RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
+            return (rovi.dwMajorVersion > 10) ||
+                   (rovi.dwMajorVersion == 10 && rovi.dwMinorVersion >= 0 &&
+                    rovi.dwBuildNumber >= 22621);
+        }
+
+        inline bool IsWindows11OrGreater_Real() {
+            RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
+            return (rovi.dwMajorVersion > 10) ||
+                   (rovi.dwMajorVersion == 10 && rovi.dwMinorVersion >= 0 &&
+                    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) ||
+                   (rovi.dwMajorVersion == 10 && rovi.dwMinorVersion >= 0 &&
+                    rovi.dwBuildNumber >= 17763);
+        }
+
+        inline bool IsWindows10OrGreater_Real() {
+            RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
+            return (rovi.dwMajorVersion > 10) ||
+                   (rovi.dwMajorVersion == 10 && rovi.dwMinorVersion >= 0);
+        }
+
+        inline bool IsWindows8Point1OrGreater_Real() {
+            RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
+            return (rovi.dwMajorVersion > 6) ||
+                   (rovi.dwMajorVersion == 6 && rovi.dwMinorVersion >= 3);
+        }
+
+        inline bool IsWindows8OrGreater_Real() {
+            RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
+            return (rovi.dwMajorVersion > 6) ||
+                   (rovi.dwMajorVersion == 6 && rovi.dwMinorVersion >= 2);
+        }
+
+        inline bool IsWindows10_Real() {
+            return IsWindows10OrGreater_Real() && !IsWindows11OrGreater_Real();
+        }
+
     }
 
-    inline bool IsWindows11OrGreater_Real() {
-        RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
-        return (rovi.dwMajorVersion > 10) ||
-               (rovi.dwMajorVersion == 10 && rovi.dwMinorVersion >= 0 &&
-                rovi.dwBuildNumber >= 22000);
+    //
+    // Version Helpers
+    //
+
+    static inline bool isWin8OrGreater() {
+        static const bool result = Private::IsWindows8OrGreater_Real();
+        return result;
     }
 
-    inline bool IsWindows101903OrGreater_Real() {
-        RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
-        return (rovi.dwMajorVersion > 10) ||
-               (rovi.dwMajorVersion == 10 && rovi.dwMinorVersion >= 0 &&
-                rovi.dwBuildNumber >= 18362);
+    static inline bool isWin8Point1OrGreater() {
+        static const bool result = Private::IsWindows8Point1OrGreater_Real();
+        return result;
     }
 
-    inline bool IsWindows101809OrGreater_Real() {
-        RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
-        return (rovi.dwMajorVersion > 10) ||
-               (rovi.dwMajorVersion == 10 && rovi.dwMinorVersion >= 0 &&
-                rovi.dwBuildNumber >= 17763);
+    static inline bool isWin10OrGreater() {
+        static const bool result = Private::IsWindows10OrGreater_Real();
+        return result;
     }
 
-    inline bool IsWindows10OrGreater_Real() {
-        RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
-        return (rovi.dwMajorVersion > 10) ||
-               (rovi.dwMajorVersion == 10 && rovi.dwMinorVersion >= 0);
+    static inline bool isWin101809OrGreater() {
+        static const bool result = Private::IsWindows101809OrGreater_Real();
+        return result;
     }
 
-    inline bool IsWindows8Point1OrGreater_Real() {
-        RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
-        return (rovi.dwMajorVersion > 6) || (rovi.dwMajorVersion == 6 && rovi.dwMinorVersion >= 3);
+    static inline bool isWin101903OrGreater() {
+        static const bool result = Private::IsWindows101903OrGreater_Real();
+        return result;
     }
 
-    inline bool IsWindows8OrGreater_Real() {
-        RTL_OSVERSIONINFOW rovi = GetRealOSVersion();
-        return (rovi.dwMajorVersion > 6) || (rovi.dwMajorVersion == 6 && rovi.dwMinorVersion >= 2);
+    static inline bool isWin11OrGreater() {
+        static const bool result = Private::IsWindows11OrGreater_Real();
+        return result;
     }
 
-    inline bool IsWindows10_Real() {
-        return IsWindows10OrGreater_Real() && !IsWindows11OrGreater_Real();
+    static inline bool isWin1122H2OrGreater() {
+        static const bool result = Private::IsWindows1122H2OrGreater_Real();
+        return result;
+    }
+
+    static inline bool isWin10() {
+        static const bool result = Private::IsWindows10_Real();
+        return result;
+    };
+
+    //
+    // Native Event Helpers
+    //
+
+    inline bool isImmersiveColorSetChange(WPARAM wParam, LPARAM lParam) {
+        return !wParam && lParam &&
+               std::wcscmp(reinterpret_cast<LPCWSTR>(lParam), L"ImmersiveColorSet") == 0;
     }
 
 }
diff --git a/src/core/shared/qwkwindowsextra_p.h b/src/core/shared/qwkwindowsextra_p.h
index 8ada487..0b24382 100644
--- a/src/core/shared/qwkwindowsextra_p.h
+++ b/src/core/shared/qwkwindowsextra_p.h
@@ -135,9 +135,9 @@
     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_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
     };
 
@@ -308,7 +308,7 @@
     }
 
     static inline constexpr MARGINS qmargins2margins(const QMargins &qmargins) {
-        return MARGINS{qmargins.left(), qmargins.right(), qmargins.top(), qmargins.bottom()};
+        return {qmargins.left(), qmargins.right(), qmargins.top(), qmargins.bottom()};
     }
 
     static inline /*constexpr*/ QString hwnd2str(const WId windowId) {
@@ -320,41 +320,6 @@
     static inline /*constexpr*/ QString hwnd2str(HWND hwnd) {
         // NULL handle is allowed here.
         return hwnd2str(reinterpret_cast<WId>(hwnd));
-    }
-
-    static inline bool isWin8OrGreater() {
-        static const bool result = IsWindows8OrGreater_Real();
-        return result;
-    }
-
-    static inline bool isWin8Point1OrGreater() {
-        static const bool result = IsWindows8Point1OrGreater_Real();
-        return result;
-    }
-
-    static inline bool isWin10OrGreater() {
-        static const bool result = IsWindows10OrGreater_Real();
-        return result;
-    }
-
-    static inline bool isWin101809OrGreater() {
-        static const bool result = IsWindows101809OrGreater_Real();
-        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;
-    }
-
-    static inline bool isWin1122H2OrGreater() {
-        static const bool result = IsWindows1122H2OrGreater_Real();
-        return result;
     }
 
     static inline bool isDwmCompositionEnabled() {
@@ -370,11 +335,11 @@
     }
 
     static inline bool isWindowFrameBorderColorized() {
-        const QWinRegistryKey registry(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\DWM)");
+        QWinRegistryKey registry(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\DWM)");
         if (!registry.isValid()) {
             return false;
         }
-        const auto value = registry.dwordValue(L"ColorPrevalence");
+        auto value = registry.dwordValue(L"ColorPrevalence");
         if (!value.second) {
             return false;
         }
@@ -392,12 +357,12 @@
 #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
         return QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Dark;
 #else
-        const QWinRegistryKey registry(
+        QWinRegistryKey registry(
             HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)");
         if (!registry.isValid()) {
             return false;
         }
-        const auto value = registry.dwordValue(L"AppsUseLightTheme");
+        auto value = registry.dwordValue(L"AppsUseLightTheme");
         if (!value.second) {
             return false;
         }
@@ -423,21 +388,21 @@
 #if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
         return QGuiApplication::palette().color(QPalette::Accent);
 #else
-        const QWinRegistryKey registry(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\DWM)");
+        QWinRegistryKey registry(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\DWM)");
         if (!registry.isValid()) {
             return {};
         }
-        const auto value = registry.dwordValue(L"AccentColor");
+        auto value = registry.dwordValue(L"AccentColor");
         if (!value.second) {
             return {};
         }
         // The retrieved value is in the #AABBGGRR format, we need to
         // convert it to the #AARRGGBB format which Qt expects.
-        const QColor abgr = QColor::fromRgba(value.first);
-        if (!abgr.isValid()) {
+        QColor color = QColor::fromRgba(value.first);
+        if (!color.isValid()) {
             return {};
         }
-        return QColor::fromRgb(abgr.blue(), abgr.green(), abgr.red(), abgr.alpha());
+        return QColor::fromRgb(color.blue(), color.green(), color.red(), color.alpha());
 #endif
     }
 
diff --git a/src/core/style/styleagent_win.cpp b/src/core/style/styleagent_win.cpp
index c4e4e96..6b77012 100644
--- a/src/core/style/styleagent_win.cpp
+++ b/src/core/style/styleagent_win.cpp
@@ -30,9 +30,7 @@
                         return true;
 
                     case WM_SETTINGCHANGE: {
-                        if (!msg->wParam && msg->lParam &&
-                            std::wcscmp(reinterpret_cast<LPCWSTR>(msg->lParam), L"ImmersiveColorSet") ==
-                            0) {
+                        if (isImmersiveColorSetChange(msg->wParam, msg->lParam)) {
                             return true;
                         }
                         break;
diff --git a/src/quick/quickwindowagent_win.cpp b/src/quick/quickwindowagent_win.cpp
index a1966fd..46e72e3 100644
--- a/src/quick/quickwindowagent_win.cpp
+++ b/src/quick/quickwindowagent_win.cpp
@@ -8,6 +8,10 @@
 namespace QWK {
 
 #if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
+    // TODO: Find a way to draw native border
+    // We haven't found a way to place hooks in the Quick program and call the GDI API to draw
+    // the native border area so that we'll use the emulated drawn border for now.
+
     class BorderItem : public QQuickPaintedItem,
                        public NativeEventFilter,
                        public SharedEventFilter {
@@ -107,9 +111,7 @@
             }
 
             case WM_SETTINGCHANGE: {
-                if (!msg->wParam && msg->lParam &&
-                    std::wcscmp(reinterpret_cast<LPCWSTR>(msg->lParam), L"ImmersiveColorSet") ==
-                        0) {
+                if (isImmersiveColorSetChange(msg->wParam, msg->lParam)) {
                     update();
                 }
                 break;
diff --git a/src/widgets/widgetwindowagent_win.cpp b/src/widgets/widgetwindowagent_win.cpp
index 2733f94..0f88e1c 100644
--- a/src/widgets/widgetwindowagent_win.cpp
+++ b/src/widgets/widgetwindowagent_win.cpp
@@ -9,6 +9,28 @@
 namespace QWK {
 
 #if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
+    // https://github.com/qt/qtbase/blob/e26a87f1ecc40bc8c6aa5b889fce67410a57a702/src/plugins/platforms/windows/qwindowsbackingstore.cpp#L42
+    // In QtWidgets applications, when repainting happens, QPA at the last calls
+    // QWindowsBackingStore::flush() to draw the contents of the buffer to the screen, we need to
+    // call GDI drawing the top border after that.
+
+    // After debugging, we know that there are two situations that will lead to redrawing.
+    //
+    // 1. Windows sends a WM_PAINT message, after which Qt immediately generates a QExposeEvent or
+    // QResizeEvent and send it to the corresponding QWidgetWindow instance, calling "flush" at the
+    // end of its handler.
+    //
+    // 2. When a timer or user input triggers Qt to redraw spontaneously, the corresponding
+    // QWidget receives a QEvent::UpdateRequest event and also calls "flush" at the end of its
+    // handler.
+    //
+    // The above two cases are mutually exclusive, so we just need to intercept the two events
+    // separately and draw the border area after the "flush" is called.
+
+    // https://github.com/qt/qtbase/blob/e26a87f1ecc40bc8c6aa5b889fce67410a57a702/src/plugins/platforms/windows/qwindowswindow.cpp#L2440
+    // Note that we can not draw the border right after WM_PAINT comes or right before the WndProc
+    // returns, because Qt calls BeginPaint() and EndPaint() itself. We should make sure that we
+    // draw the top border between these two calls, otherwise some display exceptions may arise.
 
     class WidgetBorderHandler : public QObject, public NativeEventFilter, public SharedEventFilter {
     public:
@@ -21,6 +43,8 @@
             // Must extend top frame to client area
             static QVariant defaultMargins = QVariant::fromValue(QMargins(0, 1, 0, 0));
             ctx->setWindowAttribute(QStringLiteral("extra-margins"), defaultMargins);
+
+            // Enable dark mode by default, otherwise the frame borders are white
             ctx->setWindowAttribute(QStringLiteral("dark-mode"), true);
 
             ctx->installNativeEventFilter(this);
@@ -41,6 +65,37 @@
             } else {
                 widget->setContentsMargins({});
             }
+        }
+
+        inline void resumeWidgetEvent(QWidget *w, QEvent *event) {
+            // Friend class helping to call `event`
+            class HackedWidget : public QWidget {
+            public:
+                friend class QWK::WidgetBorderHandler;
+            };
+
+            // Let the widget paint first
+            static_cast<HackedWidget *>(w)->event(event);
+
+            // Due to the timer or user action, Qt will redraw some regions spontaneously,
+            // even if there is no WM_PAINT message, we must wait for it to finish redrawing
+            // and then update the top border area.
+            ctx->virtual_hook(AbstractWindowContext::DrawWindows10BorderHook2, nullptr);
+        }
+
+        inline void resumeWindowEvent(QWindow *window, QEvent *event) {
+            // Friend class helping to call `event`
+            class HackedWindow : public QWindow {
+            public:
+                friend class QWK::WidgetBorderHandler;
+            };
+
+            // Let Qt paint first
+            static_cast<HackedWindow *>(window)->event(event);
+
+            // Upon receiving the WM_PAINT message, Qt will redraw the entire view, and we
+            // must wait for it to finish redrawing before drawing this top border area.
+            ctx->virtual_hook(AbstractWindowContext::DrawWindows10BorderHook2, nullptr);
         }
 
     protected:
@@ -83,28 +138,22 @@
             Q_UNUSED(obj)
 
             auto window = widget->windowHandle();
+
+            // Qt will absolutely send a QExposeEvent or QResizeEvent to the QWindow when it
+            // receives a WM_PAINT message. When the control flow enters the expose handler, Qt
+            // must have already called BeginPaint() and it's the best time for us to draw the
+            // top border.
+
+            // Since a QExposeEvent will be sent immediately after the QResizeEvent, we can simply
+            // ignore it.
             if (event->type() == QEvent::Expose) {
-                // Qt will absolutely send a QExposeEvent to the QWindow when it receives a
-                // WM_PAINT message. When the control flow enters the expose handler, Qt must
-                // have already called BeginPaint() and it's the best time for us to draw the
-                // top border.
                 auto ee = static_cast<QExposeEvent *>(event);
-                if (isNormalWindow() && window->isExposed() && !ee->region().isNull()) {
-                    // Friend class helping to call `event`
-                    class HackedWindow : public QWindow {
-                    public:
-                        friend class QWK::WidgetBorderHandler;
-                    };
-
-                    // Let Qt paint first
-                    static_cast<HackedWindow *>(window)->event(event);
-
-                    // Upon receiving the WM_PAINT message, Qt will redraw the entire view, and we
-                    // must wait for it to finish redrawing before drawing this top border area.
-                    ctx->virtual_hook(AbstractWindowContext::DrawWindows10BorderHook2, nullptr);
+                if (window->isExposed() && !ee->region().isNull()) {
+                    resumeWindowEvent(window, event);
                     return true;
                 }
             }
+
             return false;
         }
 
@@ -114,20 +163,7 @@
                 case QEvent::UpdateRequest: {
                     if (!isNormalWindow())
                         break;
-
-                    // Friend class helping to call `event`
-                    class HackedWidget : public QWidget {
-                    public:
-                        friend class QWK::WidgetBorderHandler;
-                    };
-
-                    // Let the widget paint first
-                    static_cast<HackedWidget *>(widget)->event(event);
-
-                    // Due to the timer or user action, Qt will redraw some regions spontaneously,
-                    // even if there is no WM_PAINT message, we must wait for it to finish redrawing
-                    // and then update the top border area.
-                    ctx->virtual_hook(AbstractWindowContext::DrawWindows10BorderHook2, nullptr);
+                    resumeWidgetEvent(widget, event);
                     return true;
                 }
 

--
Gitblit v1.9.1