From d0e19a2b1eb197386d8c42fcb5d5417aae55fb25 Mon Sep 17 00:00:00 2001 From: Yuhang Zhao <2546789017@qq.com> Date: Sat, 12 Mar 2022 16:58:58 +0800 Subject: [PATCH] wip Signed-off-by: Yuhang Zhao <2546789017@qq.com> --- examples/widget/widget.cpp | 41 ++++++++++++++++++++-- examples/widget/widget.h | 5 ++- framelesshelper.cpp | 65 +++------------------------------- utilities.cpp | 53 ++++++++++++++++++++++++++++ utilities.h | 5 +++ utilities_win32.cpp | 71 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 175 insertions(+), 65 deletions(-) diff --git a/examples/widget/widget.cpp b/examples/widget/widget.cpp index df76d1e..d25a6c7 100644 --- a/examples/widget/widget.cpp +++ b/examples/widget/widget.cpp @@ -25,6 +25,7 @@ #include "widget.h" #include #include +#include #include #include #include @@ -87,7 +88,7 @@ Widget::~Widget() = default; void Widget::showEvent(QShowEvent *event) { QWidget::showEvent(event); - initOnce(); + initFramelessHelperOnce(); } void Widget::timerEvent(QTimerEvent *event) @@ -140,13 +141,30 @@ void Widget::paintEvent(QPaintEvent *event) #endif } -void Widget::initOnce() +void Widget::mousePressEvent(QMouseEvent *event) +{ + QWidget::mousePressEvent(event); + if (isInTitleBarDraggableArea(event->pos())) { + Utilities::startSystemMove(windowHandle()); + } +} + +void Widget::mouseDoubleClickEvent(QMouseEvent *event) +{ + QWidget::mouseDoubleClickEvent(event); + if (isInTitleBarDraggableArea(event->pos())) { + if (m_maximizeButton) { + m_maximizeButton->click(); + } + } +} + +void Widget::initFramelessHelperOnce() { if (m_inited) { return; } m_inited = true; - resetContentsMargins(); FramelessWindowsManager::addWindow(windowHandle()); connect(FramelessWindowsManager::instance(), &FramelessWindowsManager::themeChanged, this, [this](){ updateStyleSheet(); @@ -233,9 +251,26 @@ void Widget::setupUi() mainLayout->addLayout(contentLayout); mainLayout->addStretch(); setLayout(mainLayout); + resetContentsMargins(); updateStyleSheet(); } +bool Widget::isInTitleBarDraggableArea(const QPoint &pos) const +{ + Q_ASSERT(m_titleBarWidget); + Q_ASSERT(m_minimizeButton); + Q_ASSERT(m_maximizeButton); + Q_ASSERT(m_closeButton); + if (!m_titleBarWidget || !m_minimizeButton || !m_maximizeButton || !m_closeButton) { + return false; + } + QRegion draggableArea = {0, 0, m_titleBarWidget->width(), m_titleBarWidget->height()}; + draggableArea -= m_minimizeButton->geometry(); + draggableArea -= m_maximizeButton->geometry(); + draggableArea -= m_closeButton->geometry(); + return draggableArea.contains(pos); +} + void Widget::updateStyleSheet() { const bool active = isActiveWindow(); diff --git a/examples/widget/widget.h b/examples/widget/widget.h index b97bb45..5fb9277 100644 --- a/examples/widget/widget.h +++ b/examples/widget/widget.h @@ -44,10 +44,13 @@ protected: void timerEvent(QTimerEvent *event) override; void changeEvent(QEvent *event) override; void paintEvent(QPaintEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseDoubleClickEvent(QMouseEvent *event) override; private: - void initOnce(); + void initFramelessHelperOnce(); void setupUi(); + bool isInTitleBarDraggableArea(const QPoint &pos) const; private Q_SLOTS: void updateStyleSheet(); diff --git a/framelesshelper.cpp b/framelesshelper.cpp index aaa6304..ee21e36 100644 --- a/framelesshelper.cpp +++ b/framelesshelper.cpp @@ -25,65 +25,10 @@ #include "framelesshelper.h" #include #include -#include "framelesswindowsmanager.h" +#include "utilities.h" FRAMELESSHELPER_BEGIN_NAMESPACE -static constexpr const int g_resizeBorderThickness = kDefaultResizeBorderThicknessAero; - -[[nodiscard]] static inline Qt::CursorShape calculateCursorShape - (const QWindow * const window, const QPointF &pos) -{ - Q_ASSERT(window); - if (!window) { - return Qt::ArrowCursor; - } - if (window->visibility() != QWindow::Windowed) { - return Qt::ArrowCursor; - } - if (((pos.x() < g_resizeBorderThickness) && (pos.y() < g_resizeBorderThickness)) - || ((pos.x() >= (window->width() - g_resizeBorderThickness)) && (pos.y() >= (window->height() - g_resizeBorderThickness)))) { - return Qt::SizeFDiagCursor; - } - if (((pos.x() >= (window->width() - g_resizeBorderThickness)) && (pos.y() < g_resizeBorderThickness)) - || ((pos.x() < g_resizeBorderThickness) && (pos.y() >= (window->height() - g_resizeBorderThickness)))) { - return Qt::SizeBDiagCursor; - } - if ((pos.x() < g_resizeBorderThickness) || (pos.x() >= (window->width() - g_resizeBorderThickness))) { - return Qt::SizeHorCursor; - } - if ((pos.y() < g_resizeBorderThickness) || (pos.y() >= (window->height() - g_resizeBorderThickness))) { - return Qt::SizeVerCursor; - } - return Qt::ArrowCursor; -} - -[[nodiscard]] static inline Qt::Edges calculateWindowEdges - (const QWindow * const window, const QPointF &pos) -{ - Q_ASSERT(window); - if (!window) { - return {}; - } - if (window->visibility() != QWindow::Windowed) { - return {}; - } - Qt::Edges edges = {}; - if (pos.x() < g_resizeBorderThickness) { - edges |= Qt::LeftEdge; - } - if (pos.x() >= (window->width() - g_resizeBorderThickness)) { - edges |= Qt::RightEdge; - } - if (pos.y() < g_resizeBorderThickness) { - edges |= Qt::TopEdge; - } - if (pos.y() >= (window->height() - g_resizeBorderThickness)) { - edges |= Qt::BottomEdge; - } - return edges; -} - FramelessHelper::FramelessHelper(QObject *parent) : QObject(parent) {} FramelessHelper::~FramelessHelper() = default; @@ -133,18 +78,16 @@ bool FramelessHelper::eventFilter(QObject *object, QEvent *event) const QPointF localPos = mouseEvent->windowPos(); #endif if (type == QEvent::MouseMove) { - const Qt::CursorShape cs = calculateCursorShape(window, localPos); + const Qt::CursorShape cs = Utilities::calculateCursorShape(window, localPos); if (cs == Qt::ArrowCursor) { window->unsetCursor(); } else { window->setCursor(cs); } } else if (type == QEvent::MouseButtonPress) { - const Qt::Edges edges = calculateWindowEdges(window, localPos); + const Qt::Edges edges = Utilities::calculateWindowEdges(window, localPos); if (edges != Qt::Edges{}) { - if (!window->startSystemResize(edges)) { - qWarning() << "Current platform doesn't support \"QWindow::startSystemResize()\"."; - } + Utilities::startSystemResize(window, edges); } } return false; diff --git a/utilities.cpp b/utilities.cpp index ab4de13..790712c 100644 --- a/utilities.cpp +++ b/utilities.cpp @@ -26,4 +26,57 @@ FRAMELESSHELPER_BEGIN_NAMESPACE +static constexpr const int g_resizeBorderThickness = kDefaultResizeBorderThicknessAero; + +Qt::CursorShape Utilities::calculateCursorShape(const QWindow *window, const QPointF &pos) +{ + Q_ASSERT(window); + if (!window) { + return Qt::ArrowCursor; + } + if (window->visibility() != QWindow::Windowed) { + return Qt::ArrowCursor; + } + if (((pos.x() < g_resizeBorderThickness) && (pos.y() < g_resizeBorderThickness)) + || ((pos.x() >= (window->width() - g_resizeBorderThickness)) && (pos.y() >= (window->height() - g_resizeBorderThickness)))) { + return Qt::SizeFDiagCursor; + } + if (((pos.x() >= (window->width() - g_resizeBorderThickness)) && (pos.y() < g_resizeBorderThickness)) + || ((pos.x() < g_resizeBorderThickness) && (pos.y() >= (window->height() - g_resizeBorderThickness)))) { + return Qt::SizeBDiagCursor; + } + if ((pos.x() < g_resizeBorderThickness) || (pos.x() >= (window->width() - g_resizeBorderThickness))) { + return Qt::SizeHorCursor; + } + if ((pos.y() < g_resizeBorderThickness) || (pos.y() >= (window->height() - g_resizeBorderThickness))) { + return Qt::SizeVerCursor; + } + return Qt::ArrowCursor; +} + +Qt::Edges Utilities::calculateWindowEdges(const QWindow *window, const QPointF &pos) +{ + Q_ASSERT(window); + if (!window) { + return {}; + } + if (window->visibility() != QWindow::Windowed) { + return {}; + } + Qt::Edges edges = {}; + if (pos.x() < g_resizeBorderThickness) { + edges |= Qt::LeftEdge; + } + if (pos.x() >= (window->width() - g_resizeBorderThickness)) { + edges |= Qt::RightEdge; + } + if (pos.y() < g_resizeBorderThickness) { + edges |= Qt::TopEdge; + } + if (pos.y() >= (window->height() - g_resizeBorderThickness)) { + edges |= Qt::BottomEdge; + } + return edges; +} + FRAMELESSHELPER_END_NAMESPACE diff --git a/utilities.h b/utilities.h index 957f293..6f2400f 100644 --- a/utilities.h +++ b/utilities.h @@ -32,6 +32,11 @@ FRAMELESSHELPER_BEGIN_NAMESPACE namespace Utilities { +[[nodiscard]] FRAMELESSHELPER_API Qt::CursorShape calculateCursorShape(const QWindow *window, const QPointF &pos); +[[nodiscard]] FRAMELESSHELPER_API Qt::Edges calculateWindowEdges(const QWindow *window, const QPointF &pos); +FRAMELESSHELPER_API void startSystemMove(QWindow *window); +FRAMELESSHELPER_API void startSystemResize(QWindow *window, const Qt::Edges edges); + #ifdef Q_OS_WINDOWS [[nodiscard]] FRAMELESSHELPER_API bool isWin8OrGreater(); [[nodiscard]] FRAMELESSHELPER_API bool isWin8Point1OrGreater(); diff --git a/utilities_win32.cpp b/utilities_win32.cpp index 6472f8b..2ba39c4 100644 --- a/utilities_win32.cpp +++ b/utilities_win32.cpp @@ -115,6 +115,34 @@ FRAMELESSHELPER_BEGIN_NAMESPACE } } +#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) +[[nodiscard]] static inline DWORD qtEdgesToWin32Orientation(const Qt::Edges edges) +{ + if (edges == Qt::Edges{}) { + return 0; + } + if (edges == (Qt::LeftEdge)) { + return 0xF001; // SC_SIZELEFT + } else if (edges == (Qt::RightEdge)) { + return 0xF002; // SC_SIZERIGHT + } else if (edges == (Qt::TopEdge)) { + return 0xF003; // SC_SIZETOP + } else if (edges == (Qt::TopEdge | Qt::LeftEdge)) { + return 0xF004; // SC_SIZETOPLEFT + } else if (edges == (Qt::TopEdge | Qt::RightEdge)) { + return 0xF005; // SC_SIZETOPRIGHT + } else if (edges == (Qt::BottomEdge)) { + return 0xF006; // SC_SIZEBOTTOM + } else if (edges == (Qt::BottomEdge | Qt::LeftEdge)) { + return 0xF007; // SC_SIZEBOTTOMLEFT + } else if (edges == (Qt::BottomEdge | Qt::RightEdge)) { + return 0xF008; // SC_SIZEBOTTOMRIGHT + } else { + return 0xF000; // SC_SIZE + } +} +#endif + bool Utilities::isWin8OrGreater() { #if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)) @@ -766,4 +794,47 @@ void Utilities::fixupQtInternals(const WId winId) } } +void Utilities::startSystemMove(QWindow *window) +{ + Q_ASSERT(window); + if (!window) { + return; + } +#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) + window->startSystemMove(); +#else + if (ReleaseCapture() == FALSE) { + qWarning() << getSystemErrorMessage(QStringLiteral("ReleaseCapture")); + return; + } + const auto hwnd = reinterpret_cast(window->winId()); + if (PostMessageW(hwnd, WM_SYSCOMMAND, 0xF012 /*SC_DRAGMOVE*/, 0) == FALSE) { + qWarning() << getSystemErrorMessage(QStringLiteral("PostMessageW")); + } +#endif +} + +void Utilities::startSystemResize(QWindow *window, const Qt::Edges edges) +{ + Q_ASSERT(window); + if (!window) { + return; + } +#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) + window->startSystemResize(edges); +#else + if (edges == Qt::Edges{}) { + return; + } + if (ReleaseCapture() == FALSE) { + qWarning() << getSystemErrorMessage(QStringLiteral("ReleaseCapture")); + return; + } + const auto hwnd = reinterpret_cast(window->winId()); + if (PostMessageW(hwnd, WM_SYSCOMMAND, qtEdgesToWin32Orientation(edges), 0) == FALSE) { + qWarning() << getSystemErrorMessage(QStringLiteral("PostMessageW")); + } +#endif +} + FRAMELESSHELPER_END_NAMESPACE