From f874811443991759df4231b5127788af059a0df9 Mon Sep 17 00:00:00 2001
From: Sine Striker <trueful@163.com>
Date: 周二, 19 12月 2023 15:55:52 +0800
Subject: [PATCH] Add raise hook

---
 src/core/contexts/qtwindowcontext.cpp |  214 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 205 insertions(+), 9 deletions(-)

diff --git a/src/core/contexts/qtwindowcontext.cpp b/src/core/contexts/qtwindowcontext.cpp
index 732ecf1..4bbb0e6 100644
--- a/src/core/contexts/qtwindowcontext.cpp
+++ b/src/core/contexts/qtwindowcontext.cpp
@@ -1,8 +1,13 @@
 #include "qtwindowcontext_p.h"
 
+#include <QtCore/QDebug>
+
+#include "qwkglobal_p.h"
+#include "systemwindow_p.h"
+
 namespace QWK {
 
-    static constexpr const int kDefaultResizeBorderThickness = 8;
+    static constexpr const quint8 kDefaultResizeBorderThickness = 8;
 
     static Qt::CursorShape calculateCursorShape(const QWindow *window, const QPoint &pos) {
 #ifdef Q_OS_MACOS
@@ -40,22 +45,213 @@
 #endif
     }
 
-    QtWindowContext::QtWindowContext(QObject *host, WindowItemDelegate *delegate)
-        : AbstractWindowContext(host, delegate) {
+    static inline Qt::Edges calculateWindowEdges(const QWindow *window, const QPoint &pos) {
+#ifdef Q_OS_MACOS
+        Q_UNUSED(window);
+        Q_UNUSED(pos);
+        return {};
+#else
+        Q_ASSERT(window);
+        if (!window) {
+            return {};
+        }
+        if (window->visibility() != QWindow::Windowed) {
+            return {};
+        }
+        Qt::Edges edges = {};
+        const int x = pos.x();
+        const int y = pos.y();
+        if (x < kDefaultResizeBorderThickness) {
+            edges |= Qt::LeftEdge;
+        }
+        if (x >= (window->width() - kDefaultResizeBorderThickness)) {
+            edges |= Qt::RightEdge;
+        }
+        if (y < kDefaultResizeBorderThickness) {
+            edges |= Qt::TopEdge;
+        }
+        if (y >= (window->height() - kDefaultResizeBorderThickness)) {
+            edges |= Qt::BottomEdge;
+        }
+        return edges;
+#endif
     }
 
-    QtWindowContext::~QtWindowContext() {
+    class QtWindowEventFilter : public QObject {
+    public:
+        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_cursorShapeChanged;
+        WindowStatus m_windowStatus;
+    };
+
+    QtWindowEventFilter::QtWindowEventFilter(AbstractWindowContext *context, QObject *parent)
+        : QObject(parent), m_context(context), m_cursorShapeChanged(false), m_windowStatus(Idle) {
+        m_context->window()->installEventFilter(this);
     }
 
-    bool QtWindowContext::setup() {
-        if (!m_windowHandle) {
+    QtWindowEventFilter::~QtWindowEventFilter() = default;
+
+    bool QtWindowEventFilter::eventFilter(QObject *obj, QEvent *event) {
+        Q_UNUSED(obj)
+        auto type = event->type();
+        if (type < QEvent::MouseButtonPress || type > QEvent::MouseMove) {
             return false;
+        }
+        auto host = m_context->host();
+        auto window = m_context->window();
+        auto delegate = m_context->delegate();
+        auto me = static_cast<const QMouseEvent *>(event);
+        bool fixedSize = delegate->isHostSizeFixed(host);
+
+        QPoint scenePos = getMouseEventScenePos(me);
+        QPoint globalPos = getMouseEventGlobalPos(me);
+
+        bool inTitleBar = m_context->isInTitleBarDraggableArea(scenePos);
+        switch (type) {
+            case QEvent::MouseButtonPress: {
+                switch (me->button()) {
+                    case Qt::LeftButton: {
+                        if (!fixedSize) {
+                            Qt::Edges edges = calculateWindowEdges(window, scenePos);
+                            if (edges != Qt::Edges()) {
+                                m_windowStatus = Resizing;
+                                startSystemResize(window, 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;
+                        }
+                        break;
+                    }
+                    case Qt::RightButton: {
+                        m_context->showSystemMenu(globalPos);
+                        break;
+                    }
+                    default:
+                        break;
+                }
+                m_windowStatus = WaitingRelease;
+                break;
+            }
+
+            case QEvent::MouseButtonRelease: {
+                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;
+                        startSystemMove(window);
+                        event->accept();
+                        return true;
+                    }
+                    case Idle: {
+                        if (!fixedSize) {
+                            const Qt::CursorShape shape = calculateCursorShape(window, scenePos);
+                            if (shape == Qt::ArrowCursor) {
+                                if (m_cursorShapeChanged) {
+                                    delegate->restoreCursorShape(host);
+                                    m_cursorShapeChanged = false;
+                                }
+                            } else {
+                                delegate->setCursorShape(host, shape);
+                                m_cursorShapeChanged = true;
+                            }
+                        }
+                        break;
+                    }
+                    default:
+                        break;
+                }
+                break;
+            }
+
+            case QEvent::MouseButtonDblClick: {
+                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);
+                        } else {
+                            delegate->setWindowState(host, windowState | Qt::WindowMaximized);
+                        }
+                        event->accept();
+                        return true;
+                    }
+                }
+                break;
+            }
+
+            default:
+                break;
         }
         return false;
     }
 
-    bool QtWindowContext::eventFilter(QObject *obj, QEvent *event) {
-        return AbstractWindowContext::eventFilter(obj, event);
+    QtWindowContext::QtWindowContext() : AbstractWindowContext() {
     }
 
-}
\ No newline at end of file
+    QtWindowContext::~QtWindowContext() = default;
+
+    QString QtWindowContext::key() const {
+        return QStringLiteral("qt");
+    }
+
+    void QtWindowContext::virtual_hook(int id, void *data) {
+        AbstractWindowContext::virtual_hook(id, data);
+    }
+
+    void QtWindowContext::winIdChanged(QWindow *oldWindow) {
+        Q_UNUSED(oldWindow)
+        m_delegate->setWindowFlags(m_host,
+                                   m_delegate->getWindowFlags(m_host) | Qt::FramelessWindowHint);
+        qtWindowEventFilter = std::make_unique<QtWindowEventFilter>(this);
+    }
+
+}

--
Gitblit v1.9.1