Zhao Yuhang
2023-12-22 e331fb1feda8891baba2a2dc1caeed67834d9d93
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include "quickwindowagent_p.h"
 
#include <QtQuick/QQuickPaintedItem>
#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 {
    public:
        explicit BorderItem(QQuickItem *parent, AbstractWindowContext *context);
        ~BorderItem() override;
 
        void updateGeometry();
 
    public:
        void paint(QPainter *painter) override;
        void itemChange(ItemChange change, const ItemChangeData &data) override;
 
    protected:
        bool nativeEventFilter(const QByteArray &eventType, void *message,
                               QT_NATIVE_EVENT_RESULT_TYPE *result) override;
 
        AbstractWindowContext *context;
 
    private:
        void _q_windowActivityChanged();
    };
 
    BorderItem::BorderItem(QQuickItem *parent, AbstractWindowContext *context)
        : QQuickPaintedItem(parent), context(context) {
        setAntialiasing(true);   // We needs anti-aliasing to give us better result.
        setFillColor({});        // Will improve the performance a little bit.
        setOpaquePainting(true); // Will also improve the performance, we don't draw
                                 // semi-transparent borders of course.
 
        auto parentPri = QQuickItemPrivate::get(parent);
        auto anchors = QQuickItemPrivate::get(this)->anchors();
        anchors->setTop(parentPri->top());
        anchors->setLeft(parentPri->left());
        anchors->setRight(parentPri->right());
 
        setZ(9999); // Make sure our fake border always above everything in the window.
 
        context->installNativeEventFilter(this);
        connect(window(), &QQuickWindow::activeChanged, this,
                &BorderItem::_q_windowActivityChanged);
        updateGeometry();
    }
 
    BorderItem::~BorderItem() = default;
 
    void BorderItem::updateGeometry() {
        setHeight(context->property("borderThickness").toInt());
    }
 
    void BorderItem::paint(QPainter *painter) {
        QRect rect(QPoint(0, 0), size().toSize());
        QRegion region(rect);
        void *args[] = {
            painter,
            &rect,
            &region,
        };
        context->virtual_hook(AbstractWindowContext::DrawWindows10BorderHook, args);
    }
 
    void BorderItem::itemChange(ItemChange change, const ItemChangeData &data) {
        QQuickPaintedItem::itemChange(change, data);
        switch (change) {
            case ItemVisibleHasChanged:
            case ItemDevicePixelRatioHasChanged: {
                updateGeometry();
                break;
            }
            default:
                break;
        }
    }
 
    bool BorderItem::nativeEventFilter(const QByteArray &eventType, void *message,
                                       QT_NATIVE_EVENT_RESULT_TYPE *result) {
        Q_UNUSED(eventType)
        const auto msg = static_cast<const MSG *>(message);
        switch (msg->message) {
            case WM_THEMECHANGED:
            case WM_SYSCOLORCHANGE:
            case WM_DWMCOLORIZATIONCOLORCHANGED: {
                update();
                break;
            }
 
            case WM_SETTINGCHANGE: {
                if (!msg->wParam && msg->lParam &&
                    std::wcscmp(reinterpret_cast<LPCWSTR>(msg->lParam), L"ImmersiveColorSet") ==
                        0) {
                    update();
                }
                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()) {
            std::ignore = new BorderItem(hostWindow->contentItem(), ctx);
        }
#endif
    }
 
}