README.md | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/core/contexts/cocoawindowcontext.mm | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/core/contexts/qtwindowcontext.cpp | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/core/qwkglobal_p.h | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
README.md
@@ -6,12 +6,11 @@ ## TODO + Fix 5.15 window unsupported behavior + 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 + Make Linux system move/resize more robust + Fix unhandled WinIdChange when adding a QWebEngineView as sub-widget (Win32 and Qt fixed) ## Supported Platforms @@ -90,30 +89,35 @@ ### Qt Widgets Application First, setup `WidgetWindowAgent` for your QWidget instance. (Each widget needs its own agent.) First, setup `WidgetWindowAgent` for your top `QWidget` instance. (Each window needs its own agent.) ```c++ #include <QWKWidgets/widgetwindowagent.h> MyWidget::MyWidget(QWidget *parent) { // ... auto agent = new WidgetWindowAgent(w); agent->setup(w); // ... } ``` You can also initialize the agent after the window constructs. ```c++ auto w = new MyWidget(); auto agent = new WidgetWindowAgent(w); agent->setup(w); ``` You can also initialize the agent in the widget constructor. ```c++ MyWidget::MyWidget(QWidget *parent) { // ... auto agent = new WidgetWindowAgent(w); agent->setup(w); } ``` Then, construct your title bar widget, without which the window lacks the basic interaction feature, and it's better to put it into the window's layout. Then, construct your title bar widget, without which the window is lacking in basic interaction feature. You can use the [`WindowBar`](examples/shared/widgetframe/windowbar.h) provided by `WidgetFrame` in the examples as the container for your title bar components. You can use the [`WindowBar`](examples/shared/widgetframe/windowbar.h) provided by `WidgetFrame` in the examples as the container of your title bar components. Let `WidgetWindowAgent` know which widget the title bar is. ```c++ agent->setTitleBarWidget(myTitleBar); ``` Set system button hints to let `WidgetWindowAgent` know the role of the widgets, which is important for the Snap Layout to work. Set system button hints to let `WidgetWindowAgent` know the role of the child widgets, which is important for the Snap Layout to work. ```c++ agent->setSystemButton(QWK::WindowAgent::Base::Maximize, maxButton); ``` @@ -122,7 +126,7 @@ ```c++ agent->setHitTestVisible(myTitleBar->menuBar(), true); ``` Other region inside the title bar will be regarded as the draggable area for user to move the window. The rest region within the title bar will be regarded as the draggable area for the user to move the window. Check [`MainWindow`](examples/mainwindow/mainwindow.cpp#L108) example to get detailed information. src/core/contexts/cocoawindowcontext.mm
@@ -5,6 +5,8 @@ #include <QtGui/QGuiApplication> #include "qwkglobal_p.h" namespace QWK { struct NSWindowProxy { @@ -261,13 +263,10 @@ 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 = me->scenePosition().toPoint(); QPoint globalPos = me->globalPosition().toPoint(); #else QPoint scenePos = me->windowPos().toPoint(); QPoint globalPos = me->screenPos().toPoint(); #endif QPoint scenePos = getMouseEventScenePos(me); QPoint globalPos = getMouseEventGlobalPos(me); bool inTitleBar = m_context->isInTitleBarDraggableArea(scenePos); switch (type) { case QEvent::MouseButtonPress: { @@ -281,7 +280,6 @@ event->accept(); return true; } m_windowStatus = WaitingRelease; break; } case Qt::RightButton: { @@ -291,6 +289,7 @@ default: break; } m_windowStatus = WaitingRelease; break; } src/core/contexts/qtwindowcontext.cpp
@@ -2,6 +2,8 @@ #include <QtCore/QDebug> #include "qwkglobal_p.h" namespace QWK { static constexpr const quint8 kDefaultResizeBorderThickness = 8; @@ -74,6 +76,125 @@ #endif } #ifdef Q_OS_LINUX class WindowMoveManipulator : public QObject { public: explicit WindowMoveManipulator(QWindow *targetWindow) : QObject(targetWindow), target(targetWindow), initialMousePosition(QCursor::pos()), initialWindowPosition(targetWindow->position()) { target->installEventFilter(this); } protected: bool eventFilter(QObject *obj, QEvent *event) override { switch (event->type()) { case QEvent::MouseMove: { auto mouseEvent = static_cast<QMouseEvent *>(event); QPoint delta = getMouseEventGlobalPos(mouseEvent) - initialMousePosition; target->setPosition(initialWindowPosition + delta); return true; } case QEvent::MouseButtonRelease: { if (target->y() < 0) { target->setPosition(target->x(), 0); } target->removeEventFilter(this); this->deleteLater(); } default: break; } return false; } private: QWindow *target; QPoint initialMousePosition; QPoint initialWindowPosition; }; #endif #if defined(Q_OS_MAC) || defined(Q_OS_LINUX) class WindowResizeManipulator : public QObject { public: WindowResizeManipulator(QWindow *targetWindow, Qt::Edges edges) : QObject(targetWindow), target(targetWindow), resizeEdges(edges), initialMousePosition(QCursor::pos()), initialWindowRect(target->geometry()) { target->installEventFilter(this); } protected: bool eventFilter(QObject *obj, QEvent *event) override { switch (event->type()) { case QEvent::MouseMove: { auto mouseEvent = static_cast<QMouseEvent *>(event); QPoint globalMousePos = getMouseEventGlobalPos(mouseEvent); QRect windowRect = initialWindowRect; if (resizeEdges & Qt::LeftEdge) { int delta = globalMousePos.x() - initialMousePosition.x(); windowRect.setLeft(initialWindowRect.left() + delta); } if (resizeEdges & Qt::RightEdge) { int delta = globalMousePos.x() - initialMousePosition.x(); windowRect.setRight(initialWindowRect.right() + delta); } if (resizeEdges & Qt::TopEdge) { int delta = globalMousePos.y() - initialMousePosition.y(); windowRect.setTop(initialWindowRect.top() + delta); } if (resizeEdges & Qt::BottomEdge) { int delta = globalMousePos.y() - initialMousePosition.y(); windowRect.setBottom(initialWindowRect.bottom() + delta); } target->setGeometry(windowRect); return true; } case QEvent::MouseButtonRelease: { target->removeEventFilter(this); this->deleteLater(); } default: break; } return false; } private: QWindow *target; QPoint initialMousePosition; QRect initialWindowRect; Qt::Edges resizeEdges; }; #endif static inline void startSystemMove(QWindow *window) { #ifdef Q_OS_LINUX if (window->startSystemMove()) { return; } std::ignore = new WindowMoveManipulator(window); #else window->startSystemMove(); #endif } static inline void startSystemResize(QWindow *window, Qt::Edges edges) { #if defined(Q_OS_MAC) || defined(Q_OS_LINUX) if (window->startSystemResize(edges)) { return; } std::ignore = new WindowResizeManipulator(window, edges); #else window->startSystemResize(edges); #endif } class QtWindowEventFilter : public QObject { public: explicit QtWindowEventFilter(AbstractWindowContext *context, QObject *parent = nullptr); @@ -114,13 +235,10 @@ WindowItemDelegate *delegate = m_context->delegate(); bool fixedSize = delegate->isHostSizeFixed(host); auto me = static_cast<const QMouseEvent *>(event); #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QPoint scenePos = me->scenePosition().toPoint(); QPoint globalPos = me->globalPosition().toPoint(); #else QPoint scenePos = me->windowPos().toPoint(); QPoint globalPos = me->screenPos().toPoint(); #endif QPoint scenePos = getMouseEventScenePos(me); QPoint globalPos = getMouseEventGlobalPos(me); bool inTitleBar = m_context->isInTitleBarDraggableArea(scenePos); switch (type) { case QEvent::MouseButtonPress: { @@ -130,7 +248,7 @@ Qt::Edges edges = calculateWindowEdges(window, scenePos); if (edges != Qt::Edges()) { m_windowStatus = Resizing; window->startSystemResize(edges); startSystemResize(window, edges); event->accept(); return true; } @@ -143,7 +261,6 @@ event->accept(); return true; } m_windowStatus = WaitingRelease; break; } case Qt::RightButton: { @@ -153,6 +270,7 @@ default: break; } m_windowStatus = WaitingRelease; break; } @@ -187,7 +305,7 @@ } case PreparingMove: { m_windowStatus = Moving; window->startSystemMove(); startSystemMove(window); event->accept(); return true; } src/core/qwkglobal_p.h
@@ -2,6 +2,7 @@ #define QWKGLOBAL_P_H #include <QtCore/QLoggingCategory> #include <QtGui/QMouseEvent> #include <QWKCore/qwkglobal.h> @@ -30,4 +31,23 @@ # define QWK_USED __attribute__((used)) #endif namespace QWK { inline QPoint getMouseEventScenePos(const QMouseEvent *event) { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) return event->scenePosition().toPoint(); #else return event->windowPos().toPoint(); #endif } inline QPoint getMouseEventGlobalPos(const QMouseEvent *event) { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) return event->globalPosition().toPoint(); #else return event->screenPos().toPoint(); #endif } } #endif // QWKGLOBAL_P_H