Sine Striker
2023-12-13 a51b5688e1c33d3ce96b48c869603b00f908f513
Make better code structure for border handlers
15个文件已修改
4个文件已添加
1 文件已重命名
2个文件已删除
695 ■■■■■ 已修改文件
qmsetup @ 8afc40 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/CMakeLists.txt 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/abstractwindowcontext.cpp 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/abstractwindowcontext_p.h 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/win32windowcontext.cpp 138 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/win32windowcontext_p.h 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/kernel/eventobserver.cpp 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/kernel/eventobserver_p.h 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/kernel/nativeeventfilter.cpp 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/kernel/nativeeventfilter_p.h 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/platforms/win10borderhandler.cpp 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/platforms/win10borderhandler_p.h 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/quick/CMakeLists.txt 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/quick/quickitemdelegate.cpp 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/quick/quickwindowagent.cpp 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/quick/quickwindowagent_p.h 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/quick/quickwindowagent_win.cpp 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/quick/qwkquickglobal.cpp 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/widgets/CMakeLists.txt 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/widgets/widgetwindowagent.cpp 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/widgets/widgetwindowagent_p.h 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/widgets/widgetwindowagent_win.cpp 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
qmsetup
@@ -1 +1 @@
Subproject commit 54a068c54436d87329e483dedc63b594be1762e0
Subproject commit 8afc40a5443899b779957fb006098ce8155aacee
src/core/CMakeLists.txt
@@ -12,12 +12,12 @@
    windowagentbase.cpp
    windowitemdelegate_p.h
    windowitemdelegate.cpp
    kernel/nativeeventfilter.h
    kernel/eventobserver_p.h
    kernel/eventobserver.cpp
    kernel/nativeeventfilter_p.h
    kernel/nativeeventfilter.cpp
    contexts/abstractwindowcontext_p.h
    contexts/abstractwindowcontext.cpp
    platforms/win10borderhandler_p.h
    platforms/win10borderhandler.cpp
)
if(WIN32)
@@ -26,7 +26,6 @@
        qwindowkit_windows.cpp
        contexts/win32windowcontext_p.h
        contexts/win32windowcontext.cpp
        platforms
    )
else()
    list(APPEND _src
src/core/contexts/abstractwindowcontext.cpp
@@ -98,10 +98,6 @@
        return true;
    }
    void AbstractWindowContext::showSystemMenu(const QPoint &pos) {
        virtual_hook(ShowSystemMenuHook, &const_cast<QPoint &>(pos));
    }
    QRegion AbstractWindowContext::hitTestShape() const {
        if (hitTestVisibleShapeDirty) {
            hitTestVisibleShape = {};
@@ -204,4 +200,8 @@
        }
    }
    void AbstractWindowContext::showSystemMenu(const QPoint &pos) {
        virtual_hook(ShowSystemMenuHook, &const_cast<QPoint &>(pos));
    }
}
src/core/contexts/abstractwindowcontext_p.h
@@ -9,11 +9,12 @@
#include <QtGui/QPolygon>
#include <QWKCore/windowagentbase.h>
#include <QWKCore/private/eventobserver_p.h>
#include <QWKCore/private/windowitemdelegate_p.h>
namespace QWK {
    class QWK_CORE_EXPORT AbstractWindowContext : public QObject {
    class QWK_CORE_EXPORT AbstractWindowContext : public QObject, public EventDispatcher {
        Q_OBJECT
    public:
        AbstractWindowContext();
@@ -35,8 +36,6 @@
        inline QObject *titleBar() const;
        bool setTitleBar(QObject *obj);
        void showSystemMenu(const QPoint &pos);
        QRegion hitTestShape() const;
        bool isInSystemButtons(const QPoint &pos, WindowAgentBase::SystemButton *button) const;
        bool isInTitleBarDraggableArea(const QPoint &pos) const;
@@ -47,9 +46,12 @@
            CentralizeHook = 1,
            ShowSystemMenuHook,
            DefaultColorsHook,
            DrawWindows10BorderHook, // Only works on Windows 10
        };
        virtual void virtual_hook(int id, void *data);
        void showSystemMenu(const QPoint &pos);
    protected:
        virtual bool setupHost() = 0;
src/core/contexts/win32windowcontext.cpp
@@ -4,6 +4,7 @@
#include <QtCore/QHash>
#include <QtCore/QScopeGuard>
#include <QtCore/QTimer>
#include <QtGui/QGuiApplication>
#include <QtGui/QPainter>
#include <QtGui/QPalette>
@@ -26,10 +27,8 @@
#include <dwmapi.h>
#include <timeapi.h>
#include "nativeeventfilter.h"
#include "nativeeventfilter_p.h"
#include "qwkglobal_p.h"
#include "win10borderhandler_p.h"
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
Q_DECLARE_METATYPE(QMargins)
@@ -814,6 +813,45 @@
                return;
            }
            case DrawWindows10BorderHook: {
                auto args = static_cast<void **>(data);
                auto &painter = *static_cast<QPainter *>(args[0]);
                const auto &rect = *static_cast<const QRect *>(args[1]);
                const auto &region = *static_cast<const QRegion *>(args[2]);
                const auto hwnd = reinterpret_cast<HWND>(m_windowHandle->winId());
                QPen pen;
                pen.setWidth(getWindowFrameBorderThickness(hwnd) * 2);
                const bool dark = isDarkThemeActive() && isDarkWindowFrameEnabled(hwnd);
                if (m_delegate->isWindowActive(m_host)) {
                    if (isWindowFrameBorderColorized()) {
                        pen.setColor(getAccentColor());
                    } else {
                        static QColor frameBorderActiveColorLight(kWindowsColorSet.activeLight);
                        static QColor frameBorderActiveColorDark(kWindowsColorSet.activeDark);
                        pen.setColor(dark ? frameBorderActiveColorDark
                                          : frameBorderActiveColorLight);
                    }
                } else {
                    static QColor frameBorderInactiveColorLight(kWindowsColorSet.inactiveLight);
                    static QColor frameBorderInactiveColorDark(kWindowsColorSet.inactiveDark);
                    pen.setColor(dark ? frameBorderInactiveColorDark
                                      : frameBorderInactiveColorLight);
                }
                painter.save();
                // ### TODO: do we need to enable or disable it?
                painter.setRenderHint(QPainter::Antialiasing);
                painter.setPen(pen);
                painter.drawLine(QLine{
                    QPoint{0,                       0},
                    QPoint{m_windowHandle->width(), 0}
                });
                painter.restore();
            }
            default: {
                // unreachable
                break;
@@ -822,14 +860,12 @@
        AbstractWindowContext::virtual_hook(id, data);
    }
    bool Win32WindowContext::needWin10BorderHandler() const {
    bool Win32WindowContext::needBorderPainter() const {
        return isWin10OrGreater() && !isWin11OrGreater();
    }
    void Win32WindowContext::setWin10BorderHandler(Win10BorderHandler *handler) {
        win10BorderHandler.reset(handler);
        handler->setBorderThickness(
            int(getWindowFrameBorderThickness(reinterpret_cast<HWND>(windowId))));
    int Win32WindowContext::borderThickness() const {
        return getWindowFrameBorderThickness(reinterpret_cast<HWND>(windowId));
    }
    bool Win32WindowContext::setupHost() {
@@ -905,8 +941,8 @@
    }
    QWK_USED static constexpr const struct {
        const WPARAM wParam = 0xF1C9ADD4;
        const LPARAM lParam = 0xAFB6F4C6;
        const WPARAM wParam = MAKEWPARAM(44500, 61897);
        const LPARAM lParam = MAKELPARAM(62662, 44982); // Not used. Reserve for future use.
    } kMessageTag;
    static inline quint64 getKeyState() {
@@ -1887,81 +1923,83 @@
        return false;
    }
    bool Win32WindowContext::themeStuffHandler(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam,
                           LRESULT *resul)
    {
    bool Win32WindowContext::themeStuffHandler(HWND hWnd, UINT message, WPARAM wParam,
                                               LPARAM lParam, LRESULT *resul) {
        switch (message) {
            case WM_DPICHANGED: {
                const auto dpiX = UINT(LOWORD(wParam));
                const auto dpiY = UINT(HIWORD(wParam));
                QEvent e(QEvent::ScreenChangeInternal);
                dispatch(&e);
                break;
            }
            case WM_THEMECHANGED:
            case WM_SYSCOLORCHANGE: {
                QEvent e(QEvent::UpdateRequest);
                dispatch(&e);
                break;
            }
            case WM_DWMCOLORIZATIONCOLORCHANGED: {
                const QColor color = QColor::fromRgba(wParam);
                const auto blendWithOpacity = *reinterpret_cast<LPBOOL>(lParam);
                QEvent e(QEvent::UpdateRequest);
                dispatch(&e);
                break;
            }
            case WM_SETTINGCHANGE: {
                if (!wParam && lParam && std::wcscmp(reinterpret_cast<LPCWSTR>(lParam), L"ImmersiveColorSet") == 0) {
                if (!wParam && lParam &&
                    std::wcscmp(reinterpret_cast<LPCWSTR>(lParam), L"ImmersiveColorSet") == 0) {
                    const QColor color = getAccentColor();
                }
                QEvent e(QEvent::UpdateRequest);
                dispatch(&e);
                break;
            }
            case WM_SIZE: {
                const bool max = wParam == SIZE_MAXIMIZED;
                const bool min = wParam == SIZE_MINIMIZED;
                const bool full = isFullScreen(hWnd);
                Qt::WindowStates states{};
                if (max) {
                    states |= Qt::WindowMaximized;
                }
                if (min) {
                    states |= Qt::WindowMinimized;
                }
                if (full) {
                    states |= Qt::WindowFullScreen;
                }
                QTimer::singleShot(0, this, [this, states] {
                    QWindowStateChangeEvent e(states);
                    dispatch(&e);
                });
                break;
            }
            case WM_ACTIVATE: {
                const auto state = LOWORD(wParam);
                const bool active = state == WA_ACTIVE || state == WA_CLICKACTIVE;
                Q_UNUSED(state)
                QTimer::singleShot(0, this, [this, active] {
                    QEvent e(active ? QEvent::WindowActivate : QEvent::WindowDeactivate);
                    dispatch(&e);
                });
                break;
            }
            default:
                break;
        }
        return false;
    }
    void Win10BorderHandler::paintBorder(QPainter &painter, const QRect &rect,
                                         const QRegion &region) {
        Q_UNUSED(rect)
        Q_UNUSED(region)
        QPen pen;
        pen.setWidth(m_borderThickness * 2);
        const bool dark = isDarkThemeActive() &&
                          isDarkWindowFrameEnabled(reinterpret_cast<HWND>(m_window->winId()));
        if (isActive()) {
            if (isWindowFrameBorderColorized()) {
                pen.setColor(getAccentColor());
            } else {
                static QColor frameBorderActiveColorLight(kWindowsColorSet.activeLight);
                static QColor frameBorderActiveColorDark(kWindowsColorSet.activeDark);
                pen.setColor(dark ? frameBorderActiveColorDark : frameBorderActiveColorLight);
            }
        } else {
            static QColor frameBorderInactiveColorLight(kWindowsColorSet.inactiveLight);
            static QColor frameBorderInactiveColorDark(kWindowsColorSet.inactiveDark);
            pen.setColor(dark ? frameBorderInactiveColorDark : frameBorderInactiveColorLight);
        }
        painter.save();
        // ### TODO: do we need to enable or disable it?
        painter.setRenderHint(QPainter::Antialiasing);
        painter.setPen(pen);
        painter.drawLine(QLine{
            QPoint{0,                 0},
            QPoint{m_window->width(), 0}
        });
        painter.restore();
    }
}
src/core/contexts/win32windowcontext_p.h
@@ -6,10 +6,10 @@
namespace QWK {
    class Win10BorderHandler;
    class QWK_CORE_EXPORT Win32WindowContext : public AbstractWindowContext {
        Q_OBJECT
        Q_PROPERTY(bool needBorderPainter READ needBorderPainter FINAL)
        Q_PROPERTY(int borderThickness READ borderThickness FINAL)
    public:
        Win32WindowContext();
        ~Win32WindowContext() override;
@@ -26,8 +26,8 @@
        QString key() const override;
        void virtual_hook(int id, void *data) override;
        Q_INVOKABLE bool needWin10BorderHandler() const;
        Q_INVOKABLE void setWin10BorderHandler(Win10BorderHandler *handler);
        bool needBorderPainter() const;
        int borderThickness() const;
    protected:
        bool setupHost() override;
@@ -65,8 +65,6 @@
        bool mouseLeaveBlocked = false;
        bool centered = false;
        std::unique_ptr<Win10BorderHandler> win10BorderHandler;
    };
}
src/core/kernel/eventobserver.cpp
New file
@@ -0,0 +1,44 @@
#include "eventobserver_p.h"
namespace QWK {
    EventObserver::EventObserver() : m_dispatcher(nullptr) {
    }
    EventObserver::~EventObserver() {
        if (m_dispatcher)
            m_dispatcher->removeObserver(this);
    }
    EventDispatcher::EventDispatcher() = default;
    EventDispatcher::~EventDispatcher() {
        for (const auto &observer : qAsConst(m_observers)) {
            observer->m_dispatcher = nullptr;
        }
    }
    bool EventDispatcher::dispatch(QEvent *event) {
        for (const auto &observer : qAsConst(m_observers)) {
            if (observer->observe(event))
                return true;
        }
        return true;
    }
    void EventDispatcher::addObserver(EventObserver *observer) {
        if (!observer || observer->m_dispatcher)
            return;
        m_observers.append(observer);
        observer->m_dispatcher = this;
    }
    void EventDispatcher::removeObserver(EventObserver *observer) {
        if (!m_observers.removeOne(observer)) {
            return;
        }
        observer->m_dispatcher = nullptr;
    }
}
src/core/kernel/eventobserver_p.h
New file
@@ -0,0 +1,47 @@
#ifndef EVENTFILTER_P_H
#define EVENTFILTER_P_H
#include <QtGui/QtEvents>
#include <QWKCore/qwkglobal.h>
namespace QWK {
    class EventDispatcher;
    class QWK_CORE_EXPORT EventObserver {
    public:
        EventObserver();
        virtual ~EventObserver();
    protected:
        virtual bool observe(QEvent *event) = 0;
    protected:
        EventDispatcher *m_dispatcher;
        Q_DISABLE_COPY(EventObserver)
        friend class EventDispatcher;
    };
    class QWK_CORE_EXPORT EventDispatcher {
    public:
        EventDispatcher();
        virtual ~EventDispatcher();
        virtual bool dispatch(QEvent *event);
    public:
        void addObserver(EventObserver *observer);
        void removeObserver(EventObserver *observer);
    protected:
        QVector<EventObserver *> m_observers;
        Q_DISABLE_COPY(EventDispatcher)
    };
}
#endif // EVENTFILTER_P_H
src/core/kernel/nativeeventfilter.cpp
@@ -1,4 +1,4 @@
#include "nativeeventfilter.h"
#include "nativeeventfilter_p.h"
#include <QtCore/QAbstractNativeEventFilter>
#include <QtCore/QCoreApplication>
src/core/kernel/nativeeventfilter_p.h
File was renamed from src/core/kernel/nativeeventfilter.h
@@ -1,5 +1,5 @@
#ifndef NATIVEEVENTFILTER_H
#define NATIVEEVENTFILTER_H
#ifndef NATIVEEVENTFILTER_P_H
#define NATIVEEVENTFILTER_P_H
#include <QWKCore/qwkglobal.h>
@@ -20,4 +20,4 @@
}
#endif // NATIVEEVENTFILTER_H
#endif // NATIVEEVENTFILTER_P_H
src/core/platforms/win10borderhandler.cpp
File was deleted
src/core/platforms/win10borderhandler_p.h
File was deleted
src/quick/CMakeLists.txt
@@ -13,6 +13,10 @@
    quickwindowagent.cpp
)
if(WIN32)
    list(APPEND _src quickwindowagent_win.cpp)
endif()
qwk_add_library(${PROJECT_NAME} AUTOGEN
    SOURCES ${_src}
    LINKS QWKCore
src/quick/quickitemdelegate.cpp
@@ -39,7 +39,7 @@
    }
    bool QuickItemDelegate::isWindowActive(const QObject *host) const {
        return static_cast<QQuickWindow *>(const_cast<QObject *>(host))->isActive();
        return static_cast<const QQuickWindow *>(host)->isActive();
    }
}
src/quick/quickwindowagent.cpp
@@ -2,69 +2,11 @@
#include "quickwindowagent_p.h"
#include <QtQuick/QQuickWindow>
#include <QtQuick/QQuickPaintedItem>
#include <QtQuick/private/qquickitem_p.h>
#include <QtQuick/private/qquickanchors_p.h>
#ifdef Q_OS_WINDOWS
#  include <QWKCore/private/win10borderhandler_p.h>
#endif
#include "quickitemdelegate_p.h"
namespace QWK {
    class BorderItem : public QQuickPaintedItem, public Win10BorderHandler {
        Q_OBJECT
    public:
        explicit BorderItem(QQuickItem *parent = nullptr);
        ~BorderItem() override;
        void updateGeometry() override;
        void requestUpdate() override;
        bool isActive() const override;
    public:
        void paint(QPainter *painter) override;
    };
    BorderItem::BorderItem(QQuickItem *parent)
        : Win10BorderHandler(parent->window()), QQuickPaintedItem(parent) {
        setAntialiasing(true);   // ### FIXME: do we need to enable or disable this?
        setMipmap(true);         // ### FIXME: do we need to enable or disable this?
        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(10);
    }
    BorderItem::~BorderItem() = default;
    void BorderItem::updateGeometry() {
        setHeight(m_borderThickness);
    }
    void BorderItem::requestUpdate() {
        update();
    }
    bool BorderItem::isActive() const {
        return static_cast<QQuickWindow *>(m_window)->isActive();
    }
    void BorderItem::paint(QPainter *painter) {
        QRect rect(QPoint(0, 0), size().toSize());
        QRegion region(rect);
        Win10BorderHandler::paintBorder(*painter, rect, region);
    }
    QuickWindowAgentPrivate::QuickWindowAgentPrivate() {
    }
@@ -99,15 +41,7 @@
        d->hostWindow = window;
#ifdef Q_OS_WINDOWS
        // Install painting hook
        if (bool needPaintBorder;
            QMetaObject::invokeMethod(d->context.get(), "needWin10BorderHandler",
                                      Qt::DirectConnection, Q_RETURN_ARG(bool, needPaintBorder)),
            needPaintBorder) {
            QMetaObject::invokeMethod(
                d->context.get(), "setWin10BorderHandler", Qt::DirectConnection,
                Q_ARG(Win10BorderHandler *, new BorderItem(window->contentItem())));
        }
        d->setupWindows10BorderWorkaround();
#endif
        return true;
    }
@@ -158,6 +92,4 @@
        d.init();
    }
}
#include "quickwindowagent.moc"
}
src/quick/quickwindowagent_p.h
@@ -16,6 +16,10 @@
        // Host
        QQuickWindow *hostWindow{};
#ifdef Q_OS_WINDOWS
        void setupWindows10BorderWorkaround();
#endif
    };
}
src/quick/quickwindowagent_win.cpp
New file
@@ -0,0 +1,110 @@
#include "quickwindowagent_p.h"
#include <QtQuick/QQuickPaintedItem>
#include <QtQuick/private/qquickitem_p.h>
#include <QWKCore/private/eventobserver_p.h>
namespace QWK {
    class BorderItem : public QQuickPaintedItem, public EventObserver {
        Q_OBJECT
    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 observe(QEvent *event) override;
        AbstractWindowContext *context;
    private:
        void _q_windowActivityChanged();
    };
    BorderItem::BorderItem(QQuickItem *parent, AbstractWindowContext *context)
        : QQuickPaintedItem(parent), context(context) {
        setAntialiasing(true);   // ### FIXME: do we need to enable or disable this?
        setMipmap(true);         // ### FIXME: do we need to enable or disable this?
        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(10);
        context->addObserver(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::observe(QEvent *event) {
        switch (event->type()) {
            case QEvent::UpdateRequest: {
                update();
                break;
            }
            default:
                break;
        }
        return false;
    }
    void BorderItem::_q_windowActivityChanged() {
        update();
    }
    void QuickWindowAgentPrivate::setupWindows10BorderWorkaround() {
        // Install painting hook
        auto ctx = context.get();
        if (ctx->property("needBorderPainter").toBool()) {
            std::ignore = new BorderItem(hostWindow->contentItem(), ctx);
        }
    }
}
#include "quickwindowagent_win.moc"
src/quick/qwkquickglobal.cpp
@@ -1,7 +1,9 @@
#include "qwkquickglobal.h"
#include "quickwindowagent.h"
#include <QtQml/QQmlEngine>
#include "quickwindowagent.h"
namespace QWK {
    static constexpr const char kModuleUri[] = "QWindowKit";
src/widgets/CMakeLists.txt
@@ -12,6 +12,10 @@
    widgetwindowagent.cpp
)
if(WIN32)
    list(APPEND _src widgetwindowagent_win.cpp)
endif()
qwk_add_library(${PROJECT_NAME} AUTOGEN
    SOURCES ${_src}
    LINKS QWKCore
src/widgets/widgetwindowagent.cpp
@@ -5,58 +5,9 @@
#include <QtGui/QPainter>
#include <QtCore/QDebug>
#ifdef Q_OS_WINDOWS
#  include <QWKCore/private/win10borderhandler_p.h>
#endif
#include "widgetitemdelegate_p.h"
namespace QWK {
#ifdef Q_OS_WINDOWS
    class WidgetBorderHandler : public QObject, public Win10BorderHandler {
    public:
        explicit WidgetBorderHandler(QWidget *widget)
            : Win10BorderHandler(widget->windowHandle()), widget(widget) {
            widget->installEventFilter(this);
        }
        void updateGeometry() override {
            if (widget->windowState() & (Qt::WindowMaximized | Qt::WindowFullScreen)) {
                widget->setContentsMargins({});
            } else {
                widget->setContentsMargins({0, int(m_borderThickness), 0, 0});
            }
        }
        void requestUpdate() override {
            widget->update();
        }
        bool isActive() const override {
            return widget->isActiveWindow();
        }
    protected:
        bool eventFilter(QObject *obj, QEvent *event) override {
            switch (event->type()) {
                case QEvent::Paint: {
                    if (widget->windowState() & (Qt::WindowMaximized | Qt::WindowFullScreen))
                        break;
                    auto paintEvent = static_cast<QPaintEvent *>(event);
                    QPainter painter(widget);
                    paintBorder(painter, paintEvent->rect(), paintEvent->region());
                    return true;
                }
                default:
                    break;
            }
            return false;
        }
        QWidget *widget;
    };
#endif
    WidgetWindowAgentPrivate::WidgetWindowAgentPrivate() {
    }
@@ -94,15 +45,7 @@
        d->hostWidget = w;
#ifdef Q_OS_WINDOWS
        // Install painting hook
        if (bool needPaintBorder;
            QMetaObject::invokeMethod(d->context.get(), "needWin10BorderHandler",
                                      Qt::DirectConnection, Q_RETURN_ARG(bool, needPaintBorder)),
            needPaintBorder) {
            QMetaObject::invokeMethod(d->context.get(), "setWin10BorderHandler",
                                      Qt::DirectConnection,
                                      Q_ARG(Win10BorderHandler *, new WidgetBorderHandler(w)));
        }
        d->setupWindows10BorderWorkaround();
#endif
        return true;
    }
src/widgets/widgetwindowagent_p.h
@@ -16,6 +16,10 @@
        // Host
        QWidget *hostWidget{};
#ifdef Q_OS_WINDOWS
        void setupWindows10BorderWorkaround();
#endif
    };
}
src/widgets/widgetwindowagent_win.cpp
New file
@@ -0,0 +1,104 @@
#include "widgetwindowagent_p.h"
#include <QtGui/QPainter>
#include <QWKCore/private/eventobserver_p.h>
namespace QWK {
    class WidgetBorderHandler : public QObject, public EventObserver {
        Q_OBJECT
    public:
        explicit WidgetBorderHandler(QWidget *widget, AbstractWindowContext *ctx,
                                     QObject *parent = nullptr)
            : QObject(parent), widget(widget), ctx(ctx) {
            widget->installEventFilter(this);
            ctx->addObserver(this);
            updateGeometry();
        }
        void updateGeometry() {
            if (widget->windowState() & (Qt::WindowMaximized | Qt::WindowFullScreen)) {
                widget->setContentsMargins({});
            } else {
                widget->setContentsMargins({
                    0,
                    ctx->property("borderThickness").toInt(),
                    0,
                    0,
                });
            }
        }
    protected:
        bool observe(QEvent *event) override {
            switch (event->type()) {
                case QEvent::UpdateRequest: {
                    widget->update();
                    break;
                }
                case QEvent::ScreenChangeInternal: {
                    updateGeometry();
                    break;
                }
                default:
                    break;
            }
            return false;
        }
        bool eventFilter(QObject *obj, QEvent *event) override {
            switch (event->type()) {
                case QEvent::Paint: {
                    if (widget->windowState() & (Qt::WindowMaximized | Qt::WindowFullScreen))
                        break;
                    auto paintEvent = static_cast<QPaintEvent *>(event);
                    auto rect = paintEvent->rect();
                    auto region = paintEvent->region();
                    QPainter painter(widget);
                    void *args[] = {
                        &painter,
                        &rect,
                        &region,
                    };
                    ctx->virtual_hook(AbstractWindowContext::DrawWindows10BorderHook, args);
                    return true;
                }
                case QEvent::WindowStateChange: {
                    updateGeometry();
                    break;
                }
                case QEvent::WindowActivate:
                case QEvent::WindowDeactivate: {
                    widget->update();
                    break;
                }
                default:
                    break;
            }
            return false;
        }
        QWidget *widget;
        AbstractWindowContext *ctx;
    };
    void WidgetWindowAgentPrivate::setupWindows10BorderWorkaround() {
        // Install painting hook
        auto ctx = context.get();
        if (ctx->property("needBorderPainter").toBool()) {
            std::ignore = new WidgetBorderHandler(hostWidget, ctx, ctx);
        }
    }
}
#include "widgetwindowagent_win.moc"