From 6b2d31247dc2c2804e571b31a71c8a423c1db9d4 Mon Sep 17 00:00:00 2001
From: Sine Striker <trueful@163.com>
Date: 周二, 26 12月 2023 01:44:03 +0800
Subject: [PATCH] Totally fix top border issue on Win10 for QtWidgets

---
 src/core/contexts/abstractwindowcontext.cpp |   56 ++++---
 src/widgets/widgetwindowagent_win.cpp       |   59 +++----
 src/core/contexts/abstractwindowcontext_p.h |   10 -
 src/core/shared/qwkwindowsextra_p.h         |   49 +++++++
 src/quick/quickwindowagent_win.cpp          |   41 ++++-
 src/quick/quickwindowagent_p.h              |    3 
 src/widgets/widgetwindowagent_p.h           |    1 
 README.md                                   |    5 
 src/core/contexts/win32windowcontext.cpp    |  158 ++++++----------------
 src/core/contexts/win32windowcontext_p.h    |   11 -
 src/core/qwindowkit_windows.h               |    8 +
 examples/mainwindow/mainwindow.cpp          |   14 --
 src/quick/quickwindowagent.cpp              |    2 
 13 files changed, 198 insertions(+), 219 deletions(-)

diff --git a/README.md b/README.md
index a466f62..3e56977 100644
--- a/README.md
+++ b/README.md
@@ -235,16 +235,13 @@
 ## Documentations
 
 + Examples (TODO)
++ Notes (TODO)
 + [FramelessHelper Related](docs/framelesshelper-related.md)
 
 ## TODO
 
 + Fix 5.15 window abnormal behavior
-+ Fix window 10 top border color in dark background
-+ Fix `isFixedSize` code
 + Support customized system button area on Mac
-+ Implement Mac window context hook
-+ Support window attribute switching on Windows
 
 ## License
 
diff --git a/examples/mainwindow/mainwindow.cpp b/examples/mainwindow/mainwindow.cpp
index 6a7435e..983a7a3 100644
--- a/examples/mainwindow/mainwindow.cpp
+++ b/examples/mainwindow/mainwindow.cpp
@@ -20,10 +20,6 @@
 #include <widgetframe/windowbar.h>
 #include <widgetframe/windowbutton.h>
 
-#ifdef Q_OS_WINDOWS
-#  include <QWKCore/qwindowkit_windows.h>
-#endif
-
 class ClockWidget : public QLabel {
 public:
     explicit ClockWidget(QWidget *parent = nullptr) : QLabel(parent) {
@@ -118,16 +114,6 @@
     // 1. Setup window agent
     windowAgent = new QWK::WidgetWindowAgent(this);
     windowAgent->setup(this);
-
-#ifdef Q_OS_WIN
-    if (QWK::IsWindows10OrGreater_Real() && !QWK::IsWindows11OrGreater_Real()) {
-        // windowAgent->setWindowAttribute(QStringLiteral("dark-mode"), true);
-
-        // https://github.com/microsoft/terminal/blob/71a6f26e6ece656084e87de1a528c4a8072eeabd/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp#L940
-        // Must call DWM API to extend top frame to client area
-        windowAgent->setWindowAttribute(QStringLiteral("extra-margins"), true);
-    }
-#endif
 
     // 2. Construct your title bar
     auto menuBar = [this]() {
diff --git a/src/core/contexts/abstractwindowcontext.cpp b/src/core/contexts/abstractwindowcontext.cpp
index 8672faf..dc0dc38 100644
--- a/src/core/contexts/abstractwindowcontext.cpp
+++ b/src/core/contexts/abstractwindowcontext.cpp
@@ -71,32 +71,7 @@
         }
     }
 
-    bool AbstractWindowContext::setWindowAttribute(const QString &key, const QVariant &attribute) {
-        auto it = m_windowAttributes.find(key);
-        if (it == m_windowAttributes.end()) {
-            if (!attribute.isValid()) {
-                return true;
-            }
-            if (!m_windowHandle || !windowAttributeChanged(key, attribute, {})) {
-                return false;
-            }
-            m_windowAttributes.insert(key, attribute);
-            return true;
-        }
 
-        if (it.value() == attribute)
-            return true;
-        if (!m_windowHandle || !windowAttributeChanged(key, attribute, it.value())) {
-            return false;
-        }
-
-        if (attribute.isValid()) {
-            it.value() = attribute;
-        } else {
-            m_windowAttributes.erase(it);
-        }
-        return true;
-    }
 
     bool AbstractWindowContext::setHitTestVisible(const QObject *obj, bool visible) {
         Q_ASSERT(obj);
@@ -285,6 +260,37 @@
         }
     }
 
+    QVariant AbstractWindowContext::windowAttribute(const QString &key) const {
+        return m_windowAttributes.value(key);
+    }
+
+    bool AbstractWindowContext::setWindowAttribute(const QString &key, const QVariant &attribute) {
+        auto it = m_windowAttributes.find(key);
+        if (it == m_windowAttributes.end()) {
+            if (!attribute.isValid()) {
+                return true;
+            }
+            if (!m_windowHandle || !windowAttributeChanged(key, attribute, {})) {
+                return false;
+            }
+            m_windowAttributes.insert(key, attribute);
+            return true;
+        }
+
+        if (it.value() == attribute)
+            return true;
+        if (!m_windowHandle || !windowAttributeChanged(key, attribute, it.value())) {
+            return false;
+        }
+
+        if (attribute.isValid()) {
+            it.value() = attribute;
+        } else {
+            m_windowAttributes.erase(it);
+        }
+        return true;
+    }
+
     bool AbstractWindowContext::windowAttributeChanged(const QString &key,
                                                        const QVariant &attribute,
                                                        const QVariant &oldAttribute) {
diff --git a/src/core/contexts/abstractwindowcontext_p.h b/src/core/contexts/abstractwindowcontext_p.h
index ec4937a..04651ad 100644
--- a/src/core/contexts/abstractwindowcontext_p.h
+++ b/src/core/contexts/abstractwindowcontext_p.h
@@ -40,9 +40,6 @@
         inline QWindow *window() const;
         inline WindowItemDelegate *delegate() const;
 
-        inline QVariant windowAttribute(const QString &key) const;
-        bool setWindowAttribute(const QString &key, const QVariant &attribute);
-
         inline bool isHitTestVisible(const QObject *obj) const;
         bool setHitTestVisible(const QObject *obj, bool visible);
 
@@ -75,6 +72,9 @@
 
         void showSystemMenu(const QPoint &pos);
         void notifyWinIdChange();
+
+        virtual QVariant windowAttribute(const QString &key) const;
+        virtual bool setWindowAttribute(const QString &key, const QVariant &attribute);
 
     protected:
         virtual void winIdChanged() = 0;
@@ -110,10 +110,6 @@
 
     inline WindowItemDelegate *AbstractWindowContext::delegate() const {
         return m_delegate.get();
-    }
-
-    inline QVariant AbstractWindowContext::windowAttribute(const QString &key) const {
-        return m_windowAttributes.value(key);
     }
 
     inline bool AbstractWindowContext::isHitTestVisible(const QObject *obj) const {
diff --git a/src/core/contexts/win32windowcontext.cpp b/src/core/contexts/win32windowcontext.cpp
index 6dec43f..bf25bdb 100644
--- a/src/core/contexts/win32windowcontext.cpp
+++ b/src/core/contexts/win32windowcontext.cpp
@@ -27,10 +27,6 @@
 #include "qwkglobal_p.h"
 #include "qwkwindowsextra_p.h"
 
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-Q_DECLARE_METATYPE(QMargins)
-#endif
-
 namespace QWK {
 
     // The thickness of an auto-hide taskbar in pixels.
@@ -69,55 +65,6 @@
         ::SetWindowPos(hwnd, nullptr, 0, 0, 0, 0,
                        SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER |
                            SWP_FRAMECHANGED);
-    }
-
-    static inline quint32 getDpiForWindow(HWND hwnd) {
-        const DynamicApis &apis = DynamicApis::instance();
-        if (apis.pGetDpiForWindow) {         // Win10
-            return apis.pGetDpiForWindow(hwnd);
-        } else if (apis.pGetDpiForMonitor) { // Win8.1
-            HMONITOR monitor = ::MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
-            UINT dpiX{0};
-            UINT dpiY{0};
-            apis.pGetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
-            return dpiX;
-        } else { // Win2K
-            HDC hdc = ::GetDC(nullptr);
-            const int dpiX = ::GetDeviceCaps(hdc, LOGPIXELSX);
-            // const int dpiY = ::GetDeviceCaps(hdc, LOGPIXELSY);
-            ::ReleaseDC(nullptr, hdc);
-            return quint32(dpiX);
-        }
-    }
-
-    static inline quint32 getSystemMetricsForDpi(int index, quint32 dpi) {
-        const DynamicApis &apis = DynamicApis::instance();
-        if (apis.pGetSystemMetricsForDpi) {
-            return ::GetSystemMetricsForDpi(index, dpi);
-        }
-        return ::GetSystemMetrics(index);
-    }
-
-    static inline quint32 getWindowFrameBorderThickness(HWND hwnd) {
-        const DynamicApis &apis = DynamicApis::instance();
-        if (UINT result = 0; SUCCEEDED(apis.pDwmGetWindowAttribute(
-                hwnd, _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, &result, sizeof(result)))) {
-            return result;
-        }
-        return getSystemMetricsForDpi(SM_CXBORDER, getDpiForWindow(hwnd));
-    }
-
-    static inline quint32 getResizeBorderThickness(HWND hwnd) {
-        const quint32 dpi = getDpiForWindow(hwnd);
-        return getSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) +
-               getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
-    }
-
-    static inline quint32 getTitleBarHeight(HWND hwnd) {
-        const quint32 dpi = getDpiForWindow(hwnd);
-        return getSystemMetricsForDpi(SM_CYCAPTION, dpi) +
-               getSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) +
-               getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
     }
 
     static void setInternalWindowFrameMargins(QWindow *window, const QMargins &margins) {
@@ -699,8 +646,8 @@
                     QPoint{m_windowHandle->width(), 0}
                 });
                 painter.restore();
-                return;
 #endif
+                return;
             }
 
             case DrawWindows10BorderHook2: {
@@ -729,49 +676,35 @@
                 return;
             }
 
-                //            case AbstractWindowContext::DrawWindows10BackgroundHook: {
-                // #if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
-                //                if (!m_windowHandle)
-                //                    return;
-                //
-                //                auto hWnd = reinterpret_cast<HWND>(windowId);
-                //                HDC hdc = ::GetDC(hWnd);
-                //                RECT windowRect{};
-                //                ::GetClientRect(hWnd, &windowRect);
-                //                RECT rcRest = {
-                //                    0,
-                //                    int(getWindowFrameBorderThickness(hWnd)),
-                //                    RECT_WIDTH(windowRect),
-                //                    RECT_HEIGHT(windowRect),
-                //                };
-                //                HBRUSH blueBrush = ::CreateSolidBrush(RGB(0, 0, 255));
-                //
-                //                // To hide the original title bar, we have to paint on top of it
-                //                with
-                //                // the alpha component set to 255. This is a hack to do it with
-                //                GDI.
-                //                // See NonClientIslandWindow::_UpdateFrameMargins for more
-                //                information. HDC opaqueDc; BP_PAINTPARAMS params =
-                //                {sizeof(params), BPPF_NOCLIP | BPPF_ERASE}; auto buf =
-                //                BeginBufferedPaint(hdc, &rcRest, BPBF_TOPDOWNDIB, &params,
-                //                &opaqueDc); if (!buf || !opaqueDc) {
-                //                    return;
-                //                }
-                //
-                //                ::FillRect(opaqueDc, &rcRest, blueBrush);
-                //                ::BufferedPaintSetAlpha(buf, nullptr, 255);
-                //                ::EndBufferedPaint(buf, TRUE);
-                //
-                //                ::DeleteObject(blueBrush);
-                //                ::ReleaseDC(hWnd, hdc);
-                // #endif
-                //                return;
-                //            }
-
             default:
                 break;
         }
         AbstractWindowContext::virtual_hook(id, data);
+    }
+
+    QVariant Win32WindowContext::windowAttribute(const QString &key) const {
+        if (key == QStringLiteral("title-bar-rect")) {
+            if (!m_windowHandle)
+                return {};
+
+            auto hwnd = reinterpret_cast<HWND>(windowId);
+            RECT frame{};
+            ::AdjustWindowRectExForDpi(&frame, ::GetWindowLongPtrW(hwnd, GWL_STYLE), FALSE, 0,
+                                       getDpiForWindow(hwnd));
+            return QVariant::fromValue(rect2qrect(frame));
+        }
+
+        if (key == QStringLiteral("win10-border-needed")) {
+            return isSystemBorderEnabled() && !isWin11OrGreater();
+        }
+
+        if (key == QStringLiteral("border-thickness")) {
+            return m_windowHandle
+                       ? int(getWindowFrameBorderThickness(reinterpret_cast<HWND>(windowId)))
+                       : 0;
+        }
+
+        return AbstractWindowContext::windowAttribute(key);
     }
 
     void Win32WindowContext::winIdChanged() {
@@ -790,7 +723,8 @@
         auto hWnd = reinterpret_cast<HWND>(winId);
 
         if (!isSystemBorderEnabled()) {
-            setWindowAttribute("extra-margins", true);
+            setWindowAttribute(QStringLiteral("extra-margins"),
+                               QVariant::fromValue(QMargins(1, 1, 1, 1)));
         }
 
         {
@@ -865,17 +799,20 @@
 
     bool Win32WindowContext::windowAttributeChanged(const QString &key, const QVariant &attribute,
                                                     const QVariant &oldAttribute) {
+        Q_UNUSED(oldAttribute)
+
         const auto hwnd = reinterpret_cast<HWND>(m_windowHandle->winId());
         const DynamicApis &apis = DynamicApis::instance();
-        static constexpr const MARGINS defaultEmptyMargins = {0, 0, 0, 0};
-        static constexpr const MARGINS defaultExtraMargins = {1, 1, 1, 1};
         static constexpr const MARGINS extendedMargins = {-1, -1, -1, -1};
+        const auto &restoreMargins = [this, &apis, hwnd]() {
+            auto margins = qmargins2margins(
+                m_windowAttributes.value(QStringLiteral("extra-margins")).value<QMargins>());
+            apis.pDwmExtendFrameIntoClientArea(hwnd, &margins);
+        };
+
         if (key == QStringLiteral("extra-margins")) {
-            if (isWin11OrGreater())
-                return false;
-            hasExtraMargins = attribute.toBool();
-            DynamicApis::instance().pDwmExtendFrameIntoClientArea(
-                hwnd, hasExtraMargins ? &defaultExtraMargins : &defaultEmptyMargins);
+            auto margins = qmargins2margins(attribute.value<QMargins>());
+            DynamicApis::instance().pDwmExtendFrameIntoClientArea(hwnd, &margins);
             return true;
         }
 
@@ -902,8 +839,6 @@
         }
 
         // For Win11 or later
-        static const auto &defaultMargins =
-            isSystemBorderEnabled() ? defaultExtraMargins : defaultEmptyMargins;
         if (key == QStringLiteral("mica")) {
             if (!isWin11OrGreater()) {
                 return false;
@@ -933,7 +868,7 @@
                     const BOOL enable = FALSE;
                     apis.pDwmSetWindowAttribute(hwnd, _DWMWA_MICA_EFFECT, &enable, sizeof(enable));
                 }
-                apis.pDwmExtendFrameIntoClientArea(hwnd, &defaultMargins);
+                restoreMargins();
             }
             return true;
         }
@@ -955,7 +890,7 @@
                 const _DWM_SYSTEMBACKDROP_TYPE backdropType = _DWMSBT_AUTO;
                 apis.pDwmSetWindowAttribute(hwnd, _DWMWA_SYSTEMBACKDROP_TYPE, &backdropType,
                                             sizeof(backdropType));
-                apis.pDwmExtendFrameIntoClientArea(hwnd, &defaultMargins);
+                restoreMargins();
             }
             return true;
         }
@@ -1002,7 +937,7 @@
                 //     wcad.cbData = sizeof(policy);
                 //     apis.pSetWindowCompositionAttribute(hwnd, &wcad);
 
-                apis.pDwmExtendFrameIntoClientArea(hwnd, &defaultMargins);
+                restoreMargins();
             }
             return true;
         }
@@ -1045,7 +980,7 @@
                     bb.dwFlags = DWM_BB_ENABLE;
                     apis.pDwmEnableBlurBehindWindow(hwnd, &bb);
                 }
-                apis.pDwmExtendFrameIntoClientArea(hwnd, &defaultMargins);
+                restoreMargins();
             }
             return true;
         }
@@ -2080,15 +2015,6 @@
             return true;
         }
         return false;
-    }
-
-    bool Win32WindowContext::needBorderPainter() const {
-        Q_UNUSED(this)
-        return isSystemBorderEnabled() && !isWin11OrGreater();
-    }
-
-    int Win32WindowContext::borderThickness() const {
-        return int(getWindowFrameBorderThickness(reinterpret_cast<HWND>(windowId)));
     }
 
 }
diff --git a/src/core/contexts/win32windowcontext_p.h b/src/core/contexts/win32windowcontext_p.h
index baa0254..6a01e16 100644
--- a/src/core/contexts/win32windowcontext_p.h
+++ b/src/core/contexts/win32windowcontext_p.h
@@ -17,8 +17,6 @@
 
     class Win32WindowContext : public AbstractWindowContext {
         Q_OBJECT
-        Q_PROPERTY(bool needBorderPainter READ needBorderPainter FINAL)
-        Q_PROPERTY(int borderThickness READ borderThickness FINAL)
     public:
         Win32WindowContext();
         ~Win32WindowContext() override;
@@ -34,6 +32,8 @@
 
         QString key() const override;
         void virtual_hook(int id, void *data) override;
+
+        QVariant windowAttribute(const QString &key) const override;
 
     protected:
         void winIdChanged() override;
@@ -59,11 +59,6 @@
         bool nonClientCalcSizeHandler(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,
                                       LRESULT *result);
 
-    public:
-        bool needBorderPainter() const;
-
-        int borderThickness() const;
-
     protected:
         WId windowId = 0;
 
@@ -75,8 +70,6 @@
         bool mouseLeaveBlocked = false;
 
         bool centered = false;
-
-        bool hasExtraMargins = false;
     };
 
 }
diff --git a/src/core/qwindowkit_windows.h b/src/core/qwindowkit_windows.h
index 8a98124..998939f 100644
--- a/src/core/qwindowkit_windows.h
+++ b/src/core/qwindowkit_windows.h
@@ -95,6 +95,14 @@
         return (rovi.dwMajorVersion > 6) || (rovi.dwMajorVersion == 6 && rovi.dwMinorVersion >= 2);
     }
 
+    inline bool IsWindows10_Real() {
+        return IsWindows10OrGreater_Real() && !IsWindows11OrGreater_Real();
+    }
+
 }
 
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+Q_DECLARE_METATYPE(QMargins)
+#endif
+
 #endif // QWINDOWKIT_WINDOWS_H
diff --git a/src/core/shared/qwkwindowsextra_p.h b/src/core/shared/qwkwindowsextra_p.h
index 15fe4e7..8ada487 100644
--- a/src/core/shared/qwkwindowsextra_p.h
+++ b/src/core/shared/qwkwindowsextra_p.h
@@ -441,6 +441,55 @@
 #endif
     }
 
+    static inline quint32 getDpiForWindow(HWND hwnd) {
+        const DynamicApis &apis = DynamicApis::instance();
+        if (apis.pGetDpiForWindow) {         // Win10
+            return apis.pGetDpiForWindow(hwnd);
+        } else if (apis.pGetDpiForMonitor) { // Win8.1
+            HMONITOR monitor = ::MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
+            UINT dpiX{0};
+            UINT dpiY{0};
+            apis.pGetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
+            return dpiX;
+        } else { // Win2K
+            HDC hdc = ::GetDC(nullptr);
+            const int dpiX = ::GetDeviceCaps(hdc, LOGPIXELSX);
+            // const int dpiY = ::GetDeviceCaps(hdc, LOGPIXELSY);
+            ::ReleaseDC(nullptr, hdc);
+            return quint32(dpiX);
+        }
+    }
+
+    static inline quint32 getSystemMetricsForDpi(int index, quint32 dpi) {
+        const DynamicApis &apis = DynamicApis::instance();
+        if (apis.pGetSystemMetricsForDpi) {
+            return ::GetSystemMetricsForDpi(index, dpi);
+        }
+        return ::GetSystemMetrics(index);
+    }
+
+    static inline quint32 getWindowFrameBorderThickness(HWND hwnd) {
+        const DynamicApis &apis = DynamicApis::instance();
+        if (UINT result = 0; SUCCEEDED(apis.pDwmGetWindowAttribute(
+                hwnd, _DWMWA_VISIBLE_FRAME_BORDER_THICKNESS, &result, sizeof(result)))) {
+            return result;
+        }
+        return getSystemMetricsForDpi(SM_CXBORDER, getDpiForWindow(hwnd));
+    }
+
+    static inline quint32 getResizeBorderThickness(HWND hwnd) {
+        const quint32 dpi = getDpiForWindow(hwnd);
+        return getSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) +
+               getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
+    }
+
+    static inline quint32 getTitleBarHeight(HWND hwnd) {
+        const quint32 dpi = getDpiForWindow(hwnd);
+        return getSystemMetricsForDpi(SM_CYCAPTION, dpi) +
+               getSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) +
+               getSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
+    }
+
 }
 
 #endif // QWKWINDOWSEXTRA_P_H
diff --git a/src/quick/quickwindowagent.cpp b/src/quick/quickwindowagent.cpp
index 4e07a3d..100514d 100644
--- a/src/quick/quickwindowagent.cpp
+++ b/src/quick/quickwindowagent.cpp
@@ -35,7 +35,7 @@
         d->setup(window, new QuickItemDelegate());
         d->hostWindow = window;
 
-#ifdef Q_OS_WINDOWS
+#if defined(Q_OS_WINDOWS) && QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
         d->setupWindows10BorderWorkaround();
 #endif
         return true;
diff --git a/src/quick/quickwindowagent_p.h b/src/quick/quickwindowagent_p.h
index 15d8b58..8919bdb 100644
--- a/src/quick/quickwindowagent_p.h
+++ b/src/quick/quickwindowagent_p.h
@@ -10,6 +10,7 @@
 // version without notice, or may even be removed.
 //
 
+#include <QWKCore/qwkconfig.h>
 #include <QWKCore/private/windowagentbase_p.h>
 #include <QWKQuick/quickwindowagent.h>
 
@@ -26,7 +27,7 @@
         // Host
         QQuickWindow *hostWindow{};
 
-#ifdef Q_OS_WINDOWS
+#if defined(Q_OS_WINDOWS) && QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
         void setupWindows10BorderWorkaround();
 #endif
     };
diff --git a/src/quick/quickwindowagent_win.cpp b/src/quick/quickwindowagent_win.cpp
index 8b2ea86..a1966fd 100644
--- a/src/quick/quickwindowagent_win.cpp
+++ b/src/quick/quickwindowagent_win.cpp
@@ -4,18 +4,20 @@
 #include <QtQuick/private/qquickitem_p.h>
 
 #include <QWKCore/qwindowkit_windows.h>
-#include <QWKCore/qwkconfig.h>
-#include <QWKCore/private/nativeeventfilter_p.h>
 
 namespace QWK {
 
 #if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
-    class BorderItem : public QQuickPaintedItem, public NativeEventFilter {
+    class BorderItem : public QQuickPaintedItem,
+                       public NativeEventFilter,
+                       public SharedEventFilter {
     public:
         explicit BorderItem(QQuickItem *parent, AbstractWindowContext *context);
         ~BorderItem() override;
 
-        void updateGeometry();
+        inline bool isNormalWindow() const;
+
+        inline void updateGeometry();
 
     public:
         void paint(QPainter *painter) override;
@@ -24,6 +26,8 @@
     protected:
         bool nativeEventFilter(const QByteArray &eventType, void *message,
                                QT_NATIVE_EVENT_RESULT_TYPE *result) override;
+
+        bool sharedEventFilter(QObject *obj, QEvent *event) override;
 
         AbstractWindowContext *context;
 
@@ -47,6 +51,8 @@
         setZ(9999); // Make sure our fake border always above everything in the window.
 
         context->installNativeEventFilter(this);
+        context->installSharedEventFilter(this);
+
         connect(window(), &QQuickWindow::activeChanged, this,
                 &BorderItem::_q_windowActivityChanged);
         updateGeometry();
@@ -54,8 +60,14 @@
 
     BorderItem::~BorderItem() = default;
 
+    bool BorderItem::isNormalWindow() const {
+        return !(context->window()->windowState() &
+                 (Qt::WindowMinimized | Qt::WindowMaximized | Qt::WindowFullScreen));
+    }
+
     void BorderItem::updateGeometry() {
-        setHeight(context->property("borderThickness").toInt());
+        setHeight(context->windowAttribute(QStringLiteral("border-thickness")).toInt());
+        setVisible(isNormalWindow());
     }
 
     void BorderItem::paint(QPainter *painter) {
@@ -109,19 +121,30 @@
         return false;
     }
 
+    bool BorderItem::sharedEventFilter(QObject *obj, QEvent *event) {
+        Q_UNUSED(obj)
+        switch (event->type()) {
+            case QEvent::WindowStateChange: {
+                updateGeometry();
+                break;
+            }
+            default:
+                break;
+        }
+        return false;
+    }
+
     void BorderItem::_q_windowActivityChanged() {
         update();
     }
-#endif
 
     void QuickWindowAgentPrivate::setupWindows10BorderWorkaround() {
-#if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
         // Install painting hook
         auto ctx = context.get();
-        if (ctx->property("needBorderPainter").toBool()) {
+        if (ctx->windowAttribute(QStringLiteral("win10-border-needed")).toBool()) {
             std::ignore = new BorderItem(hostWindow->contentItem(), ctx);
         }
-#endif
     }
+#endif
 
 }
diff --git a/src/widgets/widgetwindowagent_p.h b/src/widgets/widgetwindowagent_p.h
index c5b01be..64702b1 100644
--- a/src/widgets/widgetwindowagent_p.h
+++ b/src/widgets/widgetwindowagent_p.h
@@ -34,6 +34,7 @@
 
 #if defined(Q_OS_WINDOWS) && QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
         void setupWindows10BorderWorkaround();
+        std::unique_ptr<QObject> borderHandler;
 #endif
     };
 
diff --git a/src/widgets/widgetwindowagent_win.cpp b/src/widgets/widgetwindowagent_win.cpp
index 9e49d38..3eb6beb 100644
--- a/src/widgets/widgetwindowagent_win.cpp
+++ b/src/widgets/widgetwindowagent_win.cpp
@@ -5,19 +5,23 @@
 #include <QtGui/QPainter>
 
 #include <QWKCore/qwindowkit_windows.h>
-#include <QWKCore/private/nativeeventfilter_p.h>
 
 namespace QWK {
 
 #if QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDER)
 
-    class WidgetBorderHandler;
-
     class WidgetBorderHandler : public QObject, public NativeEventFilter, public SharedEventFilter {
     public:
-        explicit WidgetBorderHandler(QWidget *widget, AbstractWindowContext *ctx)
-            : QObject(ctx), widget(widget), ctx(ctx) {
+        explicit WidgetBorderHandler(QWidget *widget, AbstractWindowContext *ctx,
+                                     QObject *parent = nullptr)
+            : QObject(parent), widget(widget), ctx(ctx) {
             widget->installEventFilter(this);
+
+            // https://github.com/microsoft/terminal/blob/71a6f26e6ece656084e87de1a528c4a8072eeabd/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp#L940
+            // Must extend top frame to client area
+            static QVariant defaultMargins = QVariant::fromValue(QMargins(0, 1, 0, 0));
+            ctx->setWindowAttribute(QStringLiteral("extra-margins"), defaultMargins);
+            ctx->setWindowAttribute(QStringLiteral("dark-mode"), true);
 
             ctx->installNativeEventFilter(this);
             ctx->installSharedEventFilter(this);
@@ -30,14 +34,10 @@
                      (Qt::WindowMinimized | Qt::WindowMaximized | Qt::WindowFullScreen));
         }
 
-        void updateGeometry() {
+        inline void updateGeometry() {
             if (isNormalWindow()) {
-                widget->setContentsMargins({
-                    0,
-                    ctx->property("borderThickness").toInt(),
-                    0,
-                    0,
-                });
+                widget->setContentsMargins(
+                    {0, ctx->windowAttribute(QStringLiteral("border-thickness")).toInt(), 0, 0});
             } else {
                 widget->setContentsMargins({});
             }
@@ -54,31 +54,24 @@
                     break;
                 }
 
-                case WM_THEMECHANGED:
-                case WM_SYSCOLORCHANGE:
-                case WM_DWMCOLORIZATIONCOLORCHANGED: {
-                    widget->update();
-                    break;
-                }
-
-                case WM_SETTINGCHANGE: {
-                    if (!msg->wParam && msg->lParam &&
-                        std::wcscmp(reinterpret_cast<LPCWSTR>(msg->lParam), L"ImmersiveColorSet") ==
-                            0) {
-                        widget->update();
-                    }
-                    break;
-                }
-#  if 0
                 case WM_ACTIVATE: {
                     if (LOWORD(msg->wParam) == WA_INACTIVE) {
-                        // 绐楀彛澶卞幓婵�娲荤姸鎬�
+                        // https://github.com/microsoft/terminal/blob/71a6f26e6ece656084e87de1a528c4a8072eeabd/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp#L904
+                        // When the window is inactive, there is a transparency bug in the top
+                        // border and we needs to extend the non-client area to the whole title
+                        // bar.
+                        QRect frame =
+                            ctx->windowAttribute(QStringLiteral("title-bar-rect")).toRect();
+                        QMargins margins{0, -frame.top(), 0, 0};
+                        ctx->setWindowAttribute(QStringLiteral("extra-margins"),
+                                                QVariant::fromValue(margins));
                     } else {
-                        // 绐楀彛琚縺娲�
+                        // Restore margins when the window is active
+                        static QVariant defaultMargins = QVariant::fromValue(QMargins(0, 1, 0, 0));
+                        ctx->setWindowAttribute(QStringLiteral("extra-margins"), defaultMargins);
                     }
                     break;
                 }
-#  endif
 
                 default:
                     break;
@@ -162,8 +155,8 @@
     void WidgetWindowAgentPrivate::setupWindows10BorderWorkaround() {
         // Install painting hook
         auto ctx = context.get();
-        if (ctx->property("needBorderPainter").toBool()) {
-            std::ignore = new WidgetBorderHandler(hostWidget, ctx);
+        if (ctx->windowAttribute(QStringLiteral("win10-border-needed")).toBool()) {
+            borderHandler = std::make_unique<WidgetBorderHandler>(hostWidget, ctx);
         }
     }
 #endif

--
Gitblit v1.9.1