Sine Striker
2023-12-17 9619357769518e277237812e82d7c32d38cb20e6
Optimize Qt and Cocoa context
9个文件已修改
305 ■■■■ 已修改文件
README.md 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/cocoawindowcontext.mm 147 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/cocoawindowcontext_p.h 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/contexts/qtwindowcontext.cpp 127 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/core/windowitemdelegate_p.h 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/quick/quickitemdelegate.cpp 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/quick/quickitemdelegate_p.h 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/widgets/widgetitemdelegate.cpp 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/widgets/widgetitemdelegate_p.h 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
README.md
@@ -14,7 +14,7 @@
| Component | Requirement |               Detailed               |
|:---------:|:-----------:|:------------------------------------:|
|    Qt     |  \>=5.15.2  |      Core, Gui, Widgets, Quick       |
|    Qt     |   \>=5.15   |      Core, Gui, Widgets, Quick       |
| Compiler  |  \>=C++17   |        MSVC 2019, GCC, Clang         |
|   CMake   |   \>=3.17   |        >=3.20 is recommended         |
src/core/contexts/cocoawindowcontext.mm
@@ -104,7 +104,8 @@
            nswindow.hasShadow = YES;
            nswindow.showsToolbarButton = NO;
            nswindow.movableByWindowBackground = NO;
            //nswindow.movable = NO; // This line causes the window in the wrong position when become fullscreen.
            // nswindow.movable = NO; // This line causes the window in the wrong position when
            // become fullscreen.
            // For some unknown reason, we don't need the following hack in Qt versions below or
            // equal to 6.2.4.
#if (QT_VERSION > QT_VERSION_CHECK(6, 2, 4))
@@ -238,9 +239,145 @@
        return it.value();
    }
    CocoaWindowContext::CocoaWindowContext() : AbstractWindowContext() {}
    class CocoaWindowEventFilter : public QObject {
    public:
        explicit CocoaWindowEventFilter(AbstractWindowContext *context, QObject *parent = nullptr);
        ~CocoaWindowEventFilter() override;
    CocoaWindowContext::~CocoaWindowContext() = default;
        enum WindowStatus {
            Idle,
            WaitingRelease,
            PreparingMove,
            Moving,
        };
    protected:
        bool eventFilter(QObject *object, QEvent *event) override;
    private:
        AbstractWindowContext *m_context;
        bool m_cursorShapeChanged;
        WindowStatus m_windowStatus;
    };
    CocoaWindowEventFilter::CocoaWindowEventFilter(AbstractWindowContext *context, QObject *parent)
        : QObject(parent), m_context(context), m_cursorShapeChanged(false), m_windowStatus(Idle) {
        m_context->window()->installEventFilter(this);
    }
    CocoaWindowEventFilter::~CocoaWindowEventFilter() = default;
    bool CocoaWindowEventFilter::eventFilter(QObject *object, QEvent *event) {
        auto type = event->type();
        if (type < QEvent::MouseButtonPress || type > QEvent::MouseMove) {
            return false;
        }
        QObject *host = m_context->host();
        QWindow *window = m_context->window();
        WindowItemDelegate *delegate = m_context->delegate();
        auto me = static_cast<const QMouseEvent *>(event);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
        QPoint scenePos = mouseEvent->scenePosition().toPoint();
        QPoint globalPos = mouseEvent->globalPosition().toPoint();
#else
        QPoint scenePos = me->windowPos().toPoint();
        QPoint globalPos = me->screenPos().toPoint();
#endif
        bool inTitleBar = m_context->isInTitleBarDraggableArea(scenePos);
        switch (type) {
            case QEvent::MouseButtonPress: {
                switch (me->button()) {
                    case Qt::LeftButton: {
                        if (inTitleBar) {
                            // If we call startSystemMove() now but release the mouse without actual
                            // movement, there will be no MouseReleaseEvent, so we defer it when the
                            // mouse is actually moving for the first time
                            m_windowStatus = PreparingMove;
                            event->accept();
                            return true;
                        }
                        m_windowStatus = WaitingRelease;
                        break;
                    }
                    case Qt::RightButton: {
                        m_context->showSystemMenu(globalPos);
                        break;
                    }
                    default:
                        break;
                }
                break;
            }
            case QEvent::MouseButtonRelease: {
                switch (m_windowStatus) {
                    case PreparingMove:
                    case Moving: {
                        m_windowStatus = Idle;
                        event->accept();
                        return true;
                    }
                    case WaitingRelease: {
                        m_windowStatus = Idle;
                        break;
                    }
                    default: {
                        if (inTitleBar) {
                            event->accept();
                            return true;
                        }
                        break;
                    }
                }
                break;
            }
            case QEvent::MouseMove: {
                switch (m_windowStatus) {
                    case Moving: {
                        return true;
                    }
                    case PreparingMove: {
                        m_windowStatus = Moving;
                        window->startSystemMove();
                        event->accept();
                        return true;
                    }
                    default:
                        break;
                }
                break;
            }
            case QEvent::MouseButtonDblClick: {
                if (me->button() == Qt::LeftButton && inTitleBar &&
                    !delegate->isHostSizeFixed(host)) {
                    Qt::WindowStates windowState = delegate->getWindowState(host);
                    if (!(windowState & Qt::WindowFullScreen)) {
                        if (windowState & Qt::WindowMaximized) {
                            delegate->setWindowState(host, windowState & ~Qt::WindowMaximized);
                        } else {
                            delegate->setWindowState(host, windowState | Qt::WindowMaximized);
                        }
                        event->accept();
                        return true;
                    }
                }
                break;
            }
            default:
                break;
        }
        return false;
    }
    CocoaWindowContext::CocoaWindowContext() : AbstractWindowContext() {
    }
    CocoaWindowContext::~CocoaWindowContext() {
        // TODO: deref something?
    }
    QString CocoaWindowContext::key() const {
        return QStringLiteral("cocoa");
@@ -250,10 +387,12 @@
    }
    bool CocoaWindowContext::setupHost() {
        windowId = m_windowHandle->winId();
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
        m_windowHandle->setProperty("_q_mac_wantsLayer", 1);
#endif
        ensureWindowProxy(m_windowHandle->winId())->setSystemTitleBarVisible(false);
        ensureWindowProxy(windowId)->setSystemTitleBarVisible(false);
        std::ignore = new CocoaWindowEventFilter(this, this);
        return true;
    }
src/core/contexts/cocoawindowcontext_p.h
@@ -1,7 +1,6 @@
#ifndef COCOAWINDOWCONTEXT_P_H
#define COCOAWINDOWCONTEXT_P_H
#include <QWKCore/private/abstractwindowcontext_p.h>
namespace QWK {
src/core/contexts/qtwindowcontext.cpp
@@ -1,5 +1,7 @@
#include "qtwindowcontext_p.h"
#include <QtCore/QDebug>
namespace QWK {
    static constexpr const quint8 kDefaultResizeBorderThickness = 8;
@@ -40,8 +42,7 @@
#endif
    }
    static inline Qt::Edges calculateWindowEdges(const QWindow *window, const QPoint &pos)
    {
    static inline Qt::Edges calculateWindowEdges(const QWindow *window, const QPoint &pos) {
#ifdef Q_OS_MACOS
        Q_UNUSED(window);
        Q_UNUSED(pos);
@@ -73,72 +74,123 @@
#endif
    }
    class WindowEventFilter : public QObject {
    class QtWindowEventFilter : public QObject {
    public:
        explicit WindowEventFilter(AbstractWindowContext *context, QObject *parent = nullptr);
        ~WindowEventFilter() override;
        explicit QtWindowEventFilter(AbstractWindowContext *context, QObject *parent = nullptr);
        ~QtWindowEventFilter() override;
        enum WindowStatus {
            Idle,
            WaitingRelease,
            PreparingMove,
            Moving,
            Resizing,
        };
    protected:
        bool eventFilter(QObject *object, QEvent *event) override;
    private:
        AbstractWindowContext *m_context;
        bool m_leftButtonPressed;
        bool m_cursorShapeChanged;
        WindowStatus m_windowStatus;
    };
    WindowEventFilter::WindowEventFilter(AbstractWindowContext *context, QObject *parent) : QObject(parent), m_context(context), m_leftButtonPressed(false), m_cursorShapeChanged(false) {}
    QtWindowEventFilter::QtWindowEventFilter(AbstractWindowContext *context, QObject *parent)
        : QObject(parent), m_context(context), m_cursorShapeChanged(false), m_windowStatus(Idle) {
        m_context->window()->installEventFilter(this);
    }
    WindowEventFilter::~WindowEventFilter() = default;
    QtWindowEventFilter::~QtWindowEventFilter() = default;
    bool WindowEventFilter::eventFilter(QObject *object, QEvent *event) {
        const auto type = event->type();
    bool QtWindowEventFilter::eventFilter(QObject *object, QEvent *event) {
        auto type = event->type();
        if (type < QEvent::MouseButtonPress || type > QEvent::MouseMove) {
            return false;
        }
        QObject *host = m_context->host();
        QWindow *window = m_context->window();
        WindowItemDelegate *delegate = m_context->delegate();
        const bool fixedSize = delegate->isHostSizeFixed(host);
        const auto mouseEvent = static_cast<const QMouseEvent *>(event);
        bool fixedSize = delegate->isHostSizeFixed(host);
        auto me = static_cast<const QMouseEvent *>(event);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
        const QPoint scenePos = mouseEvent->scenePosition().toPoint();
        const QPoint globalPos = mouseEvent->globalPosition().toPoint();
        QPoint scenePos = mouseEvent->scenePosition().toPoint();
        QPoint globalPos = mouseEvent->globalPosition().toPoint();
#else
        const QPoint scenePos = mouseEvent->windowPos().toPoint();
        const QPoint globalPos = mouseEvent->screenPos().toPoint();
        QPoint scenePos = me->windowPos().toPoint();
        QPoint globalPos = me->screenPos().toPoint();
#endif
        const bool inTitleBar = m_context->isInTitleBarDraggableArea(scenePos);
        bool inTitleBar = m_context->isInTitleBarDraggableArea(scenePos);
        switch (type) {
            case QEvent::MouseButtonPress: {
                if (mouseEvent->button() == Qt::LeftButton) {
                    m_leftButtonPressed = true;
                switch (me->button()) {
                    case Qt::LeftButton: {
                    if (!fixedSize) {
                        const Qt::Edges edges = calculateWindowEdges(window, scenePos);
                        if (edges != Qt::Edges{}) {
                            Qt::Edges edges = calculateWindowEdges(window, scenePos);
                            if (edges != Qt::Edges()) {
                                m_windowStatus = Resizing;
                            window->startSystemResize(edges);
                            event->accept();
                            return true;
                        }
                    }
                    if (inTitleBar) {
                            // If we call startSystemMove() now but release the mouse without actual
                            // movement, there will be no MouseReleaseEvent, so we defer it when the
                            // mouse is actually moving for the first time
                            m_windowStatus = PreparingMove;
                        event->accept();
                        return true;
                    }
                        m_windowStatus = WaitingRelease;
                        break;
                    }
                    case Qt::RightButton: {
                        m_context->showSystemMenu(globalPos);
                        break;
                    }
                    default:
                        break;
                }
                break;
            }
            case QEvent::MouseButtonRelease: {
                if (mouseEvent->button() == Qt::LeftButton) {
                    m_leftButtonPressed = false;
                switch (m_windowStatus) {
                    case PreparingMove:
                    case Moving:
                    case Resizing: {
                        m_windowStatus = Idle;
                        event->accept();
                        return true;
                    }
                    case WaitingRelease: {
                        m_windowStatus = Idle;
                        break;
                    }
                    default: {
                    if (inTitleBar) {
                        event->accept();
                        return true;
                    }
                        break;
                    }
                }
                break;
            }
            case QEvent::MouseMove: {
                switch (m_windowStatus) {
                    case Moving: {
                        return true;
                    }
                    case PreparingMove: {
                        m_windowStatus = Moving;
                        window->startSystemMove();
                        event->accept();
                        return true;
                    }
                    case Idle: {
                if (!fixedSize) {
                    const Qt::CursorShape shape = calculateCursorShape(window, scenePos);
                    if (shape == Qt::ArrowCursor) {
@@ -151,16 +203,17 @@
                        m_cursorShapeChanged = true;
                    }
                }
                if (m_leftButtonPressed && inTitleBar) {
                    window->startSystemMove();
                    event->accept();
                    return true;
                        break;
                    }
                    default:
                        break;
                }
                break;
            }
            case QEvent::MouseButtonDblClick: {
                if (mouseEvent->button() == Qt::LeftButton && inTitleBar && !fixedSize) {
                    const Qt::WindowStates windowState = delegate->getWindowState(host);
                if (me->button() == Qt::LeftButton && inTitleBar && !fixedSize) {
                    Qt::WindowStates windowState = delegate->getWindowState(host);
                    if (!(windowState & Qt::WindowFullScreen)) {
                        if (windowState & Qt::WindowMaximized) {
                            delegate->setWindowState(host, windowState & ~Qt::WindowMaximized);
@@ -173,10 +226,9 @@
                }
                break;
            }
            default: {
                Q_UNREACHABLE();
                return false;
            }
            default:
                break;
        }
        return false;
    }
@@ -191,11 +243,18 @@
    }
    void QtWindowContext::virtual_hook(int id, void *data) {
        switch (id) {
            case ShowSystemMenuHook:
                return;
            default:
                break;
        }
        AbstractWindowContext::virtual_hook(id, data);
    }
    bool QtWindowContext::setupHost() {
        m_delegate->setWindowFlags(m_host, Qt::FramelessWindowHint);
        m_windowHandle->installEventFilter(new WindowEventFilter(this, m_windowHandle));
        std::ignore = new QtWindowEventFilter(this, this);
        return true;
    }
src/core/windowitemdelegate_p.h
@@ -30,10 +30,10 @@
        // Callbacks
        virtual void resetQtGrabbedControl(QObject *host) const;
        virtual void setWindowState(QObject *host, const Qt::WindowStates &state) const = 0;
        virtual void setCursorShape(QObject *host, const Qt::CursorShape shape) const = 0;
        virtual void setWindowState(QObject *host, Qt::WindowStates state) const = 0;
        virtual void setCursorShape(QObject *host, Qt::CursorShape shape) const = 0;
        virtual void restoreCursorShape(QObject *host) const = 0;
        virtual void setWindowFlags(QObject *host, const Qt::WindowFlags &flags) const = 0;
        virtual void setWindowFlags(QObject *host, Qt::WindowFlags flags) const = 0;
    private:
        Q_DISABLE_COPY(WindowItemDelegate)
src/quick/quickitemdelegate.cpp
@@ -46,7 +46,7 @@
        return static_cast<const QQuickWindow *>(host)->windowStates();
    }
    void QuickItemDelegate::setWindowState(QObject *host, const Qt::WindowStates &state) const {
    void QuickItemDelegate::setWindowState(QObject *host, Qt::WindowStates state) const {
        static_cast<QQuickWindow *>(host)->setWindowStates(state);
    }
@@ -62,7 +62,7 @@
        return static_cast<const QQuickWindow *>(host)->flags();
    }
    void QuickItemDelegate::setWindowFlags(QObject *host, const Qt::WindowFlags &flags) const {
    void QuickItemDelegate::setWindowFlags(QObject *host, Qt::WindowFlags flags) const {
        static_cast<QQuickWindow *>(host)->setFlags(flags);
    }
src/quick/quickitemdelegate_p.h
@@ -26,10 +26,10 @@
        Qt::WindowStates getWindowState(const QObject *host) const override;
        Qt::WindowFlags getWindowFlags(const QObject *host) const override;
        void setWindowState(QObject *host, const Qt::WindowStates &state) const override;
        void setCursorShape(QObject *host, const Qt::CursorShape shape) const override;
        void setWindowState(QObject *host, Qt::WindowStates state) const override;
        void setCursorShape(QObject *host, Qt::CursorShape shape) const override;
        void restoreCursorShape(QObject *host) const override;
        void setWindowFlags(QObject *host, const Qt::WindowFlags &flags) const override;
        void setWindowFlags(QObject *host, Qt::WindowFlags flags) const override;
    };
}
src/widgets/widgetitemdelegate.cpp
@@ -78,11 +78,11 @@
        return static_cast<const QWidget *>(host)->windowState();
    }
    void WidgetItemDelegate::setWindowState(QObject *host, const Qt::WindowStates &state) const {
    void WidgetItemDelegate::setWindowState(QObject *host, Qt::WindowStates state) const {
        static_cast<QWidget *>(host)->setWindowState(state);
    }
    void WidgetItemDelegate::setCursorShape(QObject *host, const Qt::CursorShape shape) const {
    void WidgetItemDelegate::setCursorShape(QObject *host, Qt::CursorShape shape) const {
        static_cast<QWidget *>(host)->setCursor(QCursor(shape));
    }
@@ -94,7 +94,7 @@
        return static_cast<const QWidget *>(host)->windowFlags();
    }
    void WidgetItemDelegate::setWindowFlags(QObject *host, const Qt::WindowFlags &flags) const {
    void WidgetItemDelegate::setWindowFlags(QObject *host, Qt::WindowFlags flags) const {
        static_cast<QWidget *>(host)->setWindowFlags(flags);
    }
src/widgets/widgetitemdelegate_p.h
@@ -27,10 +27,10 @@
        Qt::WindowFlags getWindowFlags(const QObject *host) const override;
        void resetQtGrabbedControl(QObject *host) const override;
        void setWindowState(QObject *host, const Qt::WindowStates &state) const override;
        void setCursorShape(QObject *host, const Qt::CursorShape shape) const override;
        void setWindowState(QObject *host, Qt::WindowStates state) const override;
        void setCursorShape(QObject *host, Qt::CursorShape shape) const override;
        void restoreCursorShape(QObject *host) const override;
        void setWindowFlags(QObject *host, const Qt::WindowFlags &flags) const override;
        void setWindowFlags(QObject *host, Qt::WindowFlags flags) const override;
    };
}