1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-16 00:34:19 +00:00

HWNDComponentPeer: Add setBoundsPhysical() method to set window size in physical pixels

This commit is contained in:
reuk 2025-09-18 16:14:59 +01:00
parent 0fab062726
commit 3f13cdb314
No known key found for this signature in database
2 changed files with 67 additions and 53 deletions

View file

@ -1422,20 +1422,7 @@ public:
void setBounds (const Rectangle<int>& bounds, bool isNowFullScreen) override
{
// If we try to set new bounds while handling an existing position change,
// Windows may get confused about our current scale and size.
// This can happen when moving a window between displays, because the mouse-move
// generator in handlePositionChanged can cause the window to move again.
if (inHandlePositionChanged)
return;
if (isNowFullScreen != isFullScreen())
setFullScreen (isNowFullScreen);
const ScopedValueSetter<bool> scope (shouldIgnoreModalDismiss, true);
const auto borderSize = findPhysicalBorderSize().value_or (BorderSize<int>{});
auto newBounds = borderSize.addedTo ([&]
setBoundsPhysical (std::invoke ([&]
{
ScopedThreadDPIAwarenessSetter setter { hwnd };
@ -1445,47 +1432,12 @@ public:
if (inDpiChange)
return convertLogicalScreenRectangleToPhysical (bounds, hwnd);
if (GetParent (hwnd) != nullptr)
return (bounds.toDouble() * getPlatformScaleFactor()).toNearestInt();
return convertLogicalScreenRectangleToPhysical (bounds, hwnd)
.withPosition (Desktop::getInstance().getDisplays().logicalToPhysical (bounds.getTopLeft()));
}());
if (getTransparencyKind() == TransparencyKind::perPixel)
{
if (auto parentHwnd = GetParent (hwnd))
{
auto parentRect = convertPhysicalScreenRectangleToLogical (D2DUtilities::toRectangle (getWindowScreenRect (parentHwnd)), hwnd);
newBounds.translate (parentRect.getX(), parentRect.getY());
}
}
const auto oldBounds = [this]
{
ScopedThreadDPIAwarenessSetter setter { hwnd };
RECT result;
GetWindowRect (hwnd, &result);
return D2DUtilities::toRectangle (result);
}();
const bool hasMoved = (oldBounds.getPosition() != bounds.getPosition());
const bool hasResized = (oldBounds.getWidth() != bounds.getWidth()
|| oldBounds.getHeight() != bounds.getHeight());
DWORD flags = SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED;
if (! hasMoved) flags |= SWP_NOMOVE;
if (! hasResized) flags |= SWP_NOSIZE;
SetWindowPos (hwnd,
nullptr,
newBounds.getX(),
newBounds.getY(),
newBounds.getWidth(),
newBounds.getHeight(),
flags);
if (hasResized && isValidPeer (this))
{
repaintNowIfTransparent();
}
}), isNowFullScreen);
}
Rectangle<int> getBounds() const override
@ -4305,6 +4257,62 @@ private:
return DefWindowProc (h, message, wParam, lParam);
}
void setBoundsPhysical (const Rectangle<int>& bounds, bool isNowFullScreen)
{
// If we try to set new bounds while handling an existing position change,
// Windows may get confused about our current scale and size.
// This can happen when moving a window between displays, because the mouse-move
// generator in handlePositionChanged can cause the window to move again.
if (inHandlePositionChanged)
return;
if (isNowFullScreen != isFullScreen())
setFullScreen (isNowFullScreen);
const ScopedValueSetter scope (shouldIgnoreModalDismiss, true);
const auto borderSize = findPhysicalBorderSize().value_or (BorderSize<int>{});
auto newBounds = borderSize.addedTo (bounds);
if (getTransparencyKind() == TransparencyKind::perPixel)
{
if (auto parentHwnd = GetParent (hwnd))
{
auto parentRect = convertPhysicalScreenRectangleToLogical (D2DUtilities::toRectangle (getWindowScreenRect (parentHwnd)), hwnd);
newBounds.translate (parentRect.getX(), parentRect.getY());
}
}
const auto oldBounds = std::invoke ([this]
{
ScopedThreadDPIAwarenessSetter setter { hwnd };
RECT result;
GetWindowRect (hwnd, &result);
return D2DUtilities::toRectangle (result);
});
const bool hasMoved = (oldBounds.getPosition() != bounds.getPosition());
const bool hasResized = (oldBounds.getWidth() != bounds.getWidth()
|| oldBounds.getHeight() != bounds.getHeight());
DWORD flags = SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED;
if (! hasMoved) flags |= SWP_NOMOVE;
if (! hasResized) flags |= SWP_NOSIZE;
SetWindowPos (hwnd,
nullptr,
newBounds.getX(),
newBounds.getY(),
newBounds.getWidth(),
newBounds.getHeight(),
flags);
if (hasResized && isValidPeer (this))
{
repaintNowIfTransparent();
}
}
bool sendInputAttemptWhenModalMessage()
{
if (! component.isCurrentlyBlockedByAnotherModalComponent())

View file

@ -194,6 +194,12 @@ public:
If the native window is contained in another window, then the coordinates are
relative to the parent window's origin, not the screen origin.
In this case, the position is specified in the same coordinate space as the size.
As an example, imagine that setBounds() is called on a contained ComponentPeer
with newBounds set to { 10, 20, 30, 40 }, where the peer's native scale factor is 1.5.
The new bounds will be converted to physical pixels, { 15, 30, 45, 60 }, meaning that
the peer will be positioned at { 15, 30 } *physical pixels* in the parent.
This should result in a callback to handleMovedOrResized().
*/