Sine Striker
2023-12-26 6b2d31247dc2c2804e571b31a71c8a423c1db9d4
Totally fix top border issue on Win10 for QtWidgets
13个文件已修改
417 ■■■■ 已修改文件
README.md 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
examples/mainwindow/mainwindow.cpp 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/abstractwindowcontext.cpp 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/abstractwindowcontext_p.h 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/win32windowcontext.cpp 158 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/win32windowcontext_p.h 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/qwindowkit_windows.h 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/shared/qwkwindowsextra_p.h 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/quick/quickwindowagent.cpp 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/quick/quickwindowagent_p.h 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/quick/quickwindowagent_win.cpp 41 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/widgets/widgetwindowagent_p.h 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/widgets/widgetwindowagent_win.cpp 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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
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]() {
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) {
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 {
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)));
    }
}
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;
    };
}
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
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
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;
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
    };
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
}
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
    };
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