From 5ade3cfb74dbcb8a154cde596e3ab8b066d0526c Mon Sep 17 00:00:00 2001 From: Yuhang Zhao Date: Thu, 30 Mar 2023 11:39:05 +0800 Subject: [PATCH] fix hidpi position calculation Task-number: #210 Signed-off-by: Yuhang Zhao --- include/FramelessHelper/Core/utils.h | 4 ++ src/core/framelesshelper_win.cpp | 8 +-- src/core/utils.cpp | 88 ++++++++++++++++++++++++-- src/core/utils_linux.cpp | 4 +- src/core/utils_win.cpp | 2 +- src/quick/framelessquickhelper.cpp | 3 +- src/widgets/framelesswidgetshelper.cpp | 3 +- 7 files changed, 95 insertions(+), 17 deletions(-) diff --git a/include/FramelessHelper/Core/utils.h b/include/FramelessHelper/Core/utils.h index a2e5597..af10a80 100644 --- a/include/FramelessHelper/Core/utils.h +++ b/include/FramelessHelper/Core/utils.h @@ -76,6 +76,10 @@ FRAMELESSHELPER_CORE_API void registerThemeChangeNotification(); [[nodiscard]] FRAMELESSHELPER_CORE_API QPoint fromNativePixels(const QWindow *window, const QPoint &point); [[nodiscard]] FRAMELESSHELPER_CORE_API QSize fromNativePixels(const QWindow *window, const QSize &size); [[nodiscard]] FRAMELESSHELPER_CORE_API QRect fromNativePixels(const QWindow *window, const QRect &rect); +[[nodiscard]] FRAMELESSHELPER_CORE_API QPoint toNativeLocalPosition(const QWindow *window, const QPoint &point); +[[nodiscard]] FRAMELESSHELPER_CORE_API QPoint toNativeGlobalPosition(const QWindow *window, const QPoint &point); +[[nodiscard]] FRAMELESSHELPER_CORE_API QPoint fromNativeLocalPosition(const QWindow *window, const QPoint &point); +[[nodiscard]] FRAMELESSHELPER_CORE_API QPoint fromNativeGlobalPosition(const QWindow *window, const QPoint &point); [[nodiscard]] FRAMELESSHELPER_CORE_API int horizontalAdvance(const QFontMetrics &fm, const QString &str); #ifdef Q_OS_WINDOWS diff --git a/src/core/framelesshelper_win.cpp b/src/core/framelesshelper_win.cpp index f0745c1..443727a 100644 --- a/src/core/framelesshelper_win.cpp +++ b/src/core/framelesshelper_win.cpp @@ -202,8 +202,8 @@ Q_GLOBAL_STATIC(Win32Helper, g_win32Helper) WARNING << Utils::getSystemErrorMessage(kScreenToClient); break; } - const QPoint qtScenePos = Utils::fromNativePixels(data.params.getWindowHandle(), - QPoint(nativeLocalPos.x, nativeLocalPos.y)); + const QPoint qtScenePos = Utils::fromNativeLocalPosition( + data.params.getWindowHandle(), QPoint(nativeLocalPos.x, nativeLocalPos.y)); SystemButtonType buttonType = SystemButtonType::Unknown; if (data.params.isInsideSystemButtons(qtScenePos, &buttonType)) { switch (buttonType) { @@ -1001,8 +1001,8 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me WARNING << Utils::getSystemErrorMessage(kScreenToClient); break; } - const QPoint qtScenePos = Utils::fromNativePixels(data.params.getWindowHandle(), - QPoint(nativeLocalPos.x, nativeLocalPos.y)); + const QPoint qtScenePos = Utils::fromNativeLocalPosition( + data.params.getWindowHandle(), QPoint(nativeLocalPos.x, nativeLocalPos.y)); const bool max = IsMaximized(hWnd); const bool full = Utils::isFullScreen(windowId); const int frameSizeY = Utils::getResizeBorderThickness(windowId, false, true); diff --git a/src/core/utils.cpp b/src/core/utils.cpp index 35316bc..e1bd2d3 100644 --- a/src/core/utils.cpp +++ b/src/core/utils.cpp @@ -78,6 +78,24 @@ static const QHash g_fontIconsTable = { }; #endif // FRAMELESSHELPER_CORE_NO_BUNDLE_RESOURCE +#ifdef FRAMELESSHELPER_CORE_NO_PRIVATE +[[nodiscard]] static inline QPoint getScaleOrigin(const QWindow *window) +{ + Q_ASSERT(window); + if (!window) { + return {}; + } + QScreen *screen = window->screen(); + if (!screen) { + screen = QGuiApplication::primaryScreen(); + } + if (!screen) { + return {}; + } + return screen->virtualGeometry().topLeft(); +} +#endif // FRAMELESSHELPER_CORE_NO_PRIVATE + Qt::CursorShape Utils::calculateCursorShape(const QWindow *window, const QPoint &pos) { #ifdef Q_OS_MACOS @@ -304,7 +322,7 @@ bool Utils::shouldAppsUseDarkMode() qreal Utils::roundScaleFactor(const qreal factor) { // Qt can't handle scale factors less than 1.0 (according to the comments in qhighdpiscaling.cpp). - Q_ASSERT(factor >= 1); + Q_ASSERT((factor > 1) || qFuzzyCompare(factor, qreal(1))); if (factor < 1) { return 1; } @@ -315,11 +333,15 @@ qreal Utils::roundScaleFactor(const qreal factor) case Qt::HighDpiScaleFactorRoundingPolicy::Round: return std::round(factor); case Qt::HighDpiScaleFactorRoundingPolicy::Ceil: - return qCeil(factor); + return std::ceil(factor); case Qt::HighDpiScaleFactorRoundingPolicy::Floor: - return qFloor(factor); + return std::floor(factor); case Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor: - return (((factor - qreal(int(factor))) >= qreal(0.75)) ? std::round(factor) : qFloor(factor)); + { + static constexpr const auto flag = qreal(0.75); + const qreal gap = (factor - qreal(int(factor))); + return (((gap > flag) || qFuzzyCompare(gap, flag)) ? std::round(factor) : std::floor(factor)); + } case Qt::HighDpiScaleFactorRoundingPolicy::PassThrough: case Qt::HighDpiScaleFactorRoundingPolicy::Unset: // According to Qt source code, this enum value is the same with PassThrough. return factor; @@ -353,7 +375,8 @@ QPoint Utils::toNativePixels(const QWindow *window, const QPoint &point) return {}; } #ifdef FRAMELESSHELPER_CORE_NO_PRIVATE - return QPointF(QPointF(point) * window->devicePixelRatio()).toPoint(); + const QPoint origin = getScaleOrigin(window); + return QPointF(QPointF(point - origin) * window->devicePixelRatio()).toPoint() + origin; #else // !FRAMELESSHELPER_CORE_NO_PRIVATE return QHighDpi::toNativePixels(point, window); #endif // FRAMELESSHELPER_CORE_NO_PRIVATE @@ -405,7 +428,8 @@ QPoint Utils::fromNativePixels(const QWindow *window, const QPoint &point) return {}; } #ifdef FRAMELESSHELPER_CORE_NO_PRIVATE - return QPointF(QPointF(point) / window->devicePixelRatio()).toPoint(); + const QPoint origin = getScaleOrigin(window); + return QPointF(QPointF(point - origin) / window->devicePixelRatio()).toPoint() + origin; #else // !FRAMELESSHELPER_CORE_NO_PRIVATE return QHighDpi::fromNativePixels(point, window); #endif // FRAMELESSHELPER_CORE_NO_PRIVATE @@ -437,6 +461,58 @@ QRect Utils::fromNativePixels(const QWindow *window, const QRect &rect) #endif // FRAMELESSHELPER_CORE_NO_PRIVATE } +QPoint Utils::toNativeLocalPosition(const QWindow *window, const QPoint &point) +{ + Q_ASSERT(window); + if (!window) { + return {}; + } +#ifdef FRAMELESSHELPER_CORE_NO_PRIVATE + return QPointF(QPointF(point) * window->devicePixelRatio()).toPoint(); +#else // !FRAMELESSHELPER_CORE_NO_PRIVATE + return QHighDpi::toNativeLocalPosition(point, window); +#endif // FRAMELESSHELPER_CORE_NO_PRIVATE +} + +QPoint Utils::toNativeGlobalPosition(const QWindow *window, const QPoint &point) +{ + Q_ASSERT(window); + if (!window) { + return {}; + } +#ifdef FRAMELESSHELPER_CORE_NO_PRIVATE + return toNativePixels(window, point); +#else // !FRAMELESSHELPER_CORE_NO_PRIVATE + return QHighDpi::toNativeGlobalPosition(point, window); +#endif // FRAMELESSHELPER_CORE_NO_PRIVATE +} + +QPoint Utils::fromNativeLocalPosition(const QWindow *window, const QPoint &point) +{ + Q_ASSERT(window); + if (!window) { + return {}; + } +#ifdef FRAMELESSHELPER_CORE_NO_PRIVATE + return QPointF(QPointF(point) / window->devicePixelRatio()).toPoint(); +#else // !FRAMELESSHELPER_CORE_NO_PRIVATE + return QHighDpi::fromNativeLocalPosition(point, window); +#endif // FRAMELESSHELPER_CORE_NO_PRIVATE +} + +QPoint Utils::fromNativeGlobalPosition(const QWindow *window, const QPoint &point) +{ + Q_ASSERT(window); + if (!window) { + return {}; + } +#ifdef FRAMELESSHELPER_CORE_NO_PRIVATE + return fromNativePixels(window, point); +#else // !FRAMELESSHELPER_CORE_NO_PRIVATE + return QHighDpi::fromNativeGlobalPosition(point, window); +#endif // FRAMELESSHELPER_CORE_NO_PRIVATE +} + int Utils::horizontalAdvance(const QFontMetrics &fm, const QString &str) { #if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)) diff --git a/src/core/utils_linux.cpp b/src/core/utils_linux.cpp index 7082d46..ce5bc8c 100644 --- a/src/core/utils_linux.cpp +++ b/src/core/utils_linux.cpp @@ -360,7 +360,7 @@ void Utils::startSystemMove(QWindow *window, const QPoint &globalPos) Q_UNUSED(globalPos); window->startSystemMove(); #else // (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - const QPoint nativeGlobalPos = Utils::toNativePixels(window, globalPos); + const QPoint nativeGlobalPos = Utils::toNativeGlobalPosition(window, globalPos); sendMoveResizeMessage(window->winId(), _NET_WM_MOVERESIZE_MOVE, nativeGlobalPos); #endif // (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) } @@ -378,7 +378,7 @@ void Utils::startSystemResize(QWindow *window, const Qt::Edges edges, const QPoi Q_UNUSED(globalPos); window->startSystemResize(edges); #else // (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) - const QPoint nativeGlobalPos = Utils::toNativePixels(window, globalPos); + const QPoint nativeGlobalPos = Utils::toNativeGlobalPosition(window, globalPos); const int netWmOperation = qtEdgesToWmMoveOrResizeOperation(edges); sendMoveResizeMessage(window->winId(), netWmOperation, nativeGlobalPos); #endif // (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) diff --git a/src/core/utils_win.cpp b/src/core/utils_win.cpp index 26da6c9..34ae1cc 100644 --- a/src/core/utils_win.cpp +++ b/src/core/utils_win.cpp @@ -513,7 +513,7 @@ static inline void moveWindowToMonitor(const HWND hwnd, const MONITORINFOEXW &ac switch (uMsg) { case WM_RBUTTONUP: { const QPoint nativeLocalPos = getNativePosFromMouse(); - const QPoint qtScenePos = Utils::fromNativePixels(data.params.getWindowHandle(), nativeLocalPos); + const QPoint qtScenePos = Utils::fromNativeLocalPosition(data.params.getWindowHandle(), nativeLocalPos); if (data.params.isInsideTitleBarDraggableArea(qtScenePos)) { POINT pos = {nativeLocalPos.x(), nativeLocalPos.y()}; if (ClientToScreen(hWnd, &pos) == FALSE) { diff --git a/src/quick/framelessquickhelper.cpp b/src/quick/framelessquickhelper.cpp index d0b25f6..6be512b 100644 --- a/src/quick/framelessquickhelper.cpp +++ b/src/quick/framelessquickhelper.cpp @@ -361,8 +361,7 @@ void FramelessQuickHelperPrivate::showSystemMenu(const QPoint &pos) return; } const WId windowId = window->winId(); - const QPoint globalPos = window->mapToGlobal(pos); - const QPoint nativePos = Utils::toNativePixels(window, globalPos); + const QPoint nativePos = Utils::toNativeGlobalPosition(window, pos); #ifdef Q_OS_WINDOWS const SystemParameters params = getWindowData().params; Utils::showSystemMenu(windowId, nativePos, false, ¶ms); diff --git a/src/widgets/framelesswidgetshelper.cpp b/src/widgets/framelesswidgetshelper.cpp index 540b192..34561b3 100644 --- a/src/widgets/framelesswidgetshelper.cpp +++ b/src/widgets/framelesswidgetshelper.cpp @@ -818,8 +818,7 @@ void FramelessWidgetsHelperPrivate::showSystemMenu(const QPoint &pos) return; } const WId windowId = m_window->winId(); - const QPoint globalPos = m_window->mapToGlobal(pos); - const QPoint nativePos = Utils::toNativePixels(m_window->windowHandle(), globalPos); + const QPoint nativePos = Utils::toNativeGlobalPosition(m_window->windowHandle(), pos); #ifdef Q_OS_WINDOWS const SystemParameters params = getWindowData().params; Utils::showSystemMenu(windowId, nativePos, false, ¶ms);