From 3d378d03846264d0e1ed7b9dc4bc438418a3fca9 Mon Sep 17 00:00:00 2001 From: ed Date: Thu, 18 Feb 2021 17:39:40 +0000 Subject: [PATCH] Windows: Avoid setting WINDOWPOS in handlePositionChanging() when "new" coordinates are floating-point rounding errors due to scale factor conversion --- .../native/juce_win32_Windowing.cpp | 57 +++++++++++-------- 1 file changed, 34 insertions(+), 23 deletions(-) mode change 100644 => 100755 modules/juce_gui_basics/native/juce_win32_Windowing.cpp diff --git a/modules/juce_gui_basics/native/juce_win32_Windowing.cpp b/modules/juce_gui_basics/native/juce_win32_Windowing.cpp old mode 100644 new mode 100755 index 5fa99a5bdf..43eeb6657d --- a/modules/juce_gui_basics/native/juce_win32_Windowing.cpp +++ b/modules/juce_gui_basics/native/juce_win32_Windowing.cpp @@ -492,16 +492,17 @@ using SettingChangeCallbackFunc = void (*)(void); extern SettingChangeCallbackFunc settingChangeCallback; //============================================================================== -static Rectangle rectangleFromRECT (const RECT& r) noexcept { return { r.left, r.top, r.right - r.left, r.bottom - r.top }; } -static RECT RECTFromRectangle (const Rectangle& r) noexcept { return { r.getX(), r.getY(), r.getRight(), r.getBottom() }; } +static Rectangle rectangleFromRECT (RECT r) noexcept { return { r.left, r.top, r.right - r.left, r.bottom - r.top }; } +static RECT RECTFromRectangle (Rectangle r) noexcept { return { r.getX(), r.getY(), r.getRight(), r.getBottom() }; } -static Point pointFromPOINT (const POINT& p) noexcept { return { p.x, p.y }; } -static POINT POINTFromPoint (const Point& p) noexcept { return { p.x, p.y }; } +static Point pointFromPOINT (POINT p) noexcept { return { p.x, p.y }; } +static POINT POINTFromPoint (Point p) noexcept { return { p.x, p.y }; } //============================================================================== static const Displays::Display* getCurrentDisplayFromScaleFactor (HWND hwnd); -static Rectangle convertPhysicalScreenRectangleToLogical (const Rectangle& r, HWND h) noexcept +template +static Rectangle convertPhysicalScreenRectangleToLogical (Rectangle r, HWND h) noexcept { if (isPerMonitorDPIAwareWindow (h)) return Desktop::getInstance().getDisplays().physicalToLogical (r, getCurrentDisplayFromScaleFactor (h)); @@ -509,7 +510,8 @@ static Rectangle convertPhysicalScreenRectangleToLogical (const Rectangle convertLogicalScreenRectangleToPhysical (const Rectangle& r, HWND h) noexcept +template +static Rectangle convertLogicalScreenRectangleToPhysical (Rectangle r, HWND h) noexcept { if (isPerMonitorDPIAwareWindow (h)) return Desktop::getInstance().getDisplays().logicalToPhysical (r, getCurrentDisplayFromScaleFactor (h)); @@ -517,7 +519,7 @@ static Rectangle convertLogicalScreenRectangleToPhysical (const Rectangle convertPhysicalScreenPointToLogical (const Point& p, HWND h) noexcept +static Point convertPhysicalScreenPointToLogical (Point p, HWND h) noexcept { if (isPerMonitorDPIAwareWindow (h)) return Desktop::getInstance().getDisplays().physicalToLogical (p, getCurrentDisplayFromScaleFactor (h)); @@ -3198,17 +3200,19 @@ private: { if (isConstrainedNativeWindow()) { - auto pos = ScalingHelpers::unscaledScreenPosToScaled (component, convertPhysicalScreenRectangleToLogical (rectangleFromRECT (r), hwnd)); - auto current = getCurrentScaledBounds(); + const auto logicalBounds = convertPhysicalScreenRectangleToLogical (rectangleFromRECT (r).toFloat(), hwnd); + auto pos = ScalingHelpers::unscaledScreenPosToScaled (component, logicalBounds).toNearestInt(); - constrainer->checkBounds (pos, current, + const auto original = getCurrentScaledBounds(); + + constrainer->checkBounds (pos, original, Desktop::getInstance().getDisplays().getTotalBounds (true), wParam == WMSZ_TOP || wParam == WMSZ_TOPLEFT || wParam == WMSZ_TOPRIGHT, wParam == WMSZ_LEFT || wParam == WMSZ_TOPLEFT || wParam == WMSZ_BOTTOMLEFT, wParam == WMSZ_BOTTOM || wParam == WMSZ_BOTTOMLEFT || wParam == WMSZ_BOTTOMRIGHT, wParam == WMSZ_RIGHT || wParam == WMSZ_TOPRIGHT || wParam == WMSZ_BOTTOMRIGHT); - r = RECTFromRectangle (convertLogicalScreenRectangleToPhysical (ScalingHelpers::scaledScreenPosToUnscaled (component, pos), hwnd)); + r = RECTFromRectangle (convertLogicalScreenRectangleToPhysical (ScalingHelpers::scaledScreenPosToUnscaled (component, pos.toFloat()).toNearestInt(), hwnd)); } return TRUE; @@ -3222,22 +3226,29 @@ private: && (wp.x > -32000 && wp.y > -32000) && ! Component::isMouseButtonDownAnywhere()) { - auto pos = ScalingHelpers::unscaledScreenPosToScaled (component, convertPhysicalScreenRectangleToLogical (rectangleFromRECT ({ wp.x, wp.y, wp.x + wp.cx, wp.y + wp.cy }), hwnd)); - auto current = getCurrentScaledBounds(); + const auto logicalBounds = convertPhysicalScreenRectangleToLogical (rectangleFromRECT ({ wp.x, wp.y, wp.x + wp.cx, wp.y + wp.cy }).toFloat(), hwnd); + auto pos = ScalingHelpers::unscaledScreenPosToScaled (component, logicalBounds).toNearestInt(); - constrainer->checkBounds (pos, current, + const auto original = getCurrentScaledBounds(); + + constrainer->checkBounds (pos, original, Desktop::getInstance().getDisplays().getTotalBounds (true), - pos.getY() != current.getY() && pos.getBottom() == current.getBottom(), - pos.getX() != current.getX() && pos.getRight() == current.getRight(), - pos.getY() == current.getY() && pos.getBottom() != current.getBottom(), - pos.getX() == current.getX() && pos.getRight() != current.getRight()); + pos.getY() != original.getY() && pos.getBottom() == original.getBottom(), + pos.getX() != original.getX() && pos.getRight() == original.getRight(), + pos.getY() == original.getY() && pos.getBottom() != original.getBottom(), + pos.getX() == original.getX() && pos.getRight() != original.getRight()); - pos = convertLogicalScreenRectangleToPhysical (ScalingHelpers::scaledScreenPosToUnscaled (component, pos), hwnd); + auto physicalBounds = convertLogicalScreenRectangleToPhysical (ScalingHelpers::scaledScreenPosToUnscaled (component, pos.toFloat()), hwnd); - wp.x = pos.getX(); - wp.y = pos.getY(); - wp.cx = pos.getWidth(); - wp.cy = pos.getHeight(); + auto getNewPositionIfNotRoundingError = [] (int pos, float newPos) + { + return (std::abs ((float) pos - newPos) >= 1.0f) ? roundToInt (newPos) : pos; + }; + + wp.x = getNewPositionIfNotRoundingError (wp.x, physicalBounds.getX()); + wp.y = getNewPositionIfNotRoundingError (wp.y, physicalBounds.getY()); + wp.cx = getNewPositionIfNotRoundingError (wp.cx, physicalBounds.getWidth()); + wp.cy = getNewPositionIfNotRoundingError (wp.cy, physicalBounds.getHeight()); } }