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

ComponentPeer: Add method for overriding native scale factor

This commit is contained in:
reuk 2025-09-18 16:21:03 +01:00
parent 6648e13fa6
commit b4c28db765
No known key found for this signature in database
3 changed files with 98 additions and 22 deletions

View file

@ -106,7 +106,7 @@ public:
updateScaleFactorFromNewBounds (bounds, false); updateScaleFactorFromNewBounds (bounds, false);
auto physicalBounds = parentWindow == 0 ? Desktop::getInstance().getDisplays().logicalToPhysical (bounds) auto physicalBounds = parentWindow == 0 ? Desktop::getInstance().getDisplays().logicalToPhysical (bounds)
: bounds * currentScaleFactor; : bounds * getPlatformScaleFactor();
WeakReference<Component> deletionChecker (&component); WeakReference<Component> deletionChecker (&component);
@ -140,14 +140,14 @@ public:
{ {
auto physicalParentPosition = XWindowSystem::getInstance()->getPhysicalParentScreenPosition(); auto physicalParentPosition = XWindowSystem::getInstance()->getPhysicalParentScreenPosition();
auto parentPosition = parentWindow == 0 ? Desktop::getInstance().getDisplays().physicalToLogical (physicalParentPosition) auto parentPosition = parentWindow == 0 ? Desktop::getInstance().getDisplays().physicalToLogical (physicalParentPosition)
: physicalParentPosition / currentScaleFactor; : physicalParentPosition / getPlatformScaleFactor();
auto screenBounds = parentWindow == 0 ? bounds auto screenBounds = parentWindow == 0 ? bounds
: bounds.translated (parentPosition.x, parentPosition.y); : bounds.translated (parentPosition.x, parentPosition.y);
if (physical) if (physical)
return parentWindow == 0 ? Desktop::getInstance().getDisplays().logicalToPhysical (screenBounds.getTopLeft()) return parentWindow == 0 ? Desktop::getInstance().getDisplays().logicalToPhysical (screenBounds.getTopLeft())
: screenBounds.getTopLeft() * currentScaleFactor; : screenBounds.getTopLeft() * getPlatformScaleFactor();
return screenBounds.getTopLeft(); return screenBounds.getTopLeft();
} }
@ -270,7 +270,7 @@ public:
if (trueIfInAChildWindow) if (trueIfInAChildWindow)
return true; return true;
return XWindowSystem::getInstance()->contains (windowH, localPos * currentScaleFactor); return XWindowSystem::getInstance()->contains (windowH, localPos * getPlatformScaleFactor());
} }
void toFront (bool makeActive) override void toFront (bool makeActive) override
@ -332,7 +332,24 @@ public:
double getPlatformScaleFactor() const noexcept override double getPlatformScaleFactor() const noexcept override
{ {
return currentScaleFactor; return scaleFactorOverride.value_or (currentScaleFactor);
}
void setCustomPlatformScaleFactor (std::optional<double> scaleIn) override
{
const auto prev = getPlatformScaleFactor();
scaleFactorOverride = scaleIn;
const auto next = getPlatformScaleFactor();
if (approximatelyEqual (prev, next))
return;
scaleFactorListeners.call ([&] (ScaleFactorListener& l) { l.nativeScaleFactorChanged (next); });
}
std::optional<double> getCustomPlatformScaleFactor() const override
{
return scaleFactorOverride;
} }
void setAlpha (float) override {} void setAlpha (float) override {}
@ -386,7 +403,7 @@ public:
updateScaleFactorFromNewBounds (physicalBounds, true); updateScaleFactorFromNewBounds (physicalBounds, true);
bounds = parentWindow == 0 ? Desktop::getInstance().getDisplays().physicalToLogical (physicalBounds) bounds = parentWindow == 0 ? Desktop::getInstance().getDisplays().physicalToLogical (physicalBounds)
: physicalBounds / currentScaleFactor; : physicalBounds / getPlatformScaleFactor();
updateVBlankTimer(); updateVBlankTimer();
} }
@ -403,7 +420,7 @@ public:
windowBorder = [&]() windowBorder = [&]()
{ {
if (auto unscaledBorderSize = XWindowSystem::getInstance()->getBorderSize (windowH)) if (auto unscaledBorderSize = XWindowSystem::getInstance()->getBorderSize (windowH))
return OptionalBorderSize { (*unscaledBorderSize).multipliedBy (1.0 / currentScaleFactor) }; return OptionalBorderSize { (*unscaledBorderSize).multipliedBy (1.0 / getPlatformScaleFactor()) };
return OptionalBorderSize {}; return OptionalBorderSize {};
}(); }();
@ -460,7 +477,7 @@ private:
void repaint (Rectangle<int> area) void repaint (Rectangle<int> area)
{ {
regionsNeedingRepaint.add (area * peer.currentScaleFactor); regionsNeedingRepaint.add (area * peer.getPlatformScaleFactor());
} }
void performAnyPendingRepaintsNow() void performAnyPendingRepaintsNow()
@ -511,7 +528,7 @@ private:
auto context = peer.getComponent().getLookAndFeel() auto context = peer.getComponent().getLookAndFeel()
.createGraphicsContext (image, -totalArea.getPosition(), adjustedList); .createGraphicsContext (image, -totalArea.getPosition(), adjustedList);
context->addTransform (AffineTransform::scale ((float) peer.currentScaleFactor)); context->addTransform (AffineTransform::scale ((float) peer.getPlatformScaleFactor()));
peer.handlePaint (*context); peer.handlePaint (*context);
} }
@ -607,6 +624,7 @@ private:
Rectangle<int> bounds; Rectangle<int> bounds;
ComponentPeer::OptionalBorderSize windowBorder; ComponentPeer::OptionalBorderSize windowBorder;
bool fullScreen = false, isAlwaysOnTop = false; bool fullScreen = false, isAlwaysOnTop = false;
std::optional<double> scaleFactorOverride;
double currentScaleFactor = 1.0; double currentScaleFactor = 1.0;
Array<Component*> glRepaintListeners; Array<Component*> glRepaintListeners;
ScopedWindowAssociation association; ScopedWindowAssociation association;

View file

@ -558,7 +558,8 @@ static Rectangle<ValueType> convertLogicalScreenRectangleToPhysical (Rectangle<V
return r; return r;
} }
static Point<int> convertPhysicalScreenPointToLogical (Point<int> p, HWND h) noexcept template <typename ValueType>
static Point<ValueType> convertPhysicalScreenPointToLogical (Point<ValueType> p, HWND h) noexcept
{ {
if (isPerMonitorDPIAwareWindow (h)) if (isPerMonitorDPIAwareWindow (h))
return Desktop::getInstance().getDisplays().physicalToLogical (p, getCurrentDisplayFromScaleFactor (h)); return Desktop::getInstance().getDisplays().physicalToLogical (p, getCurrentDisplayFromScaleFactor (h));
@ -566,7 +567,8 @@ static Point<int> convertPhysicalScreenPointToLogical (Point<int> p, HWND h) noe
return p; return p;
} }
static Point<int> convertLogicalScreenPointToPhysical (Point<int> p, HWND h) noexcept template <typename ValueType>
static Point<ValueType> convertLogicalScreenPointToPhysical (Point<ValueType> p, HWND h) noexcept
{ {
if (isPerMonitorDPIAwareWindow (h)) if (isPerMonitorDPIAwareWindow (h))
return Desktop::getInstance().getDisplays().logicalToPhysical (p, getCurrentDisplayFromScaleFactor (h)); return Desktop::getInstance().getDisplays().logicalToPhysical (p, getCurrentDisplayFromScaleFactor (h));
@ -1471,8 +1473,19 @@ public:
return convertPhysicalScreenPointToLogical (getClientRectInScreen().getPosition(), hwnd); return convertPhysicalScreenPointToLogical (getClientRectInScreen().getPosition(), hwnd);
} }
Point<float> localToGlobal (Point<float> relativePosition) override { return relativePosition + getScreenPosition().toFloat(); } Point<float> localToGlobal (Point<float> relativePosition) override
Point<float> globalToLocal (Point<float> screenPosition) override { return screenPosition - getScreenPosition().toFloat(); } {
const auto localPhysical = relativePosition * getPlatformScaleFactor();
const auto physical = localPhysical + getClientRectInScreen().getPosition().toFloat();
return convertPhysicalScreenPointToLogical (physical, hwnd);
}
Point<float> globalToLocal (Point<float> screenPosition) override
{
const auto physical = convertLogicalScreenPointToPhysical (screenPosition, hwnd);
const auto localPhysical = physical - getClientRectInScreen().getPosition().toFloat();
return localPhysical / getPlatformScaleFactor();
}
using ComponentPeer::localToGlobal; using ComponentPeer::localToGlobal;
using ComponentPeer::globalToLocal; using ComponentPeer::globalToLocal;
@ -1578,12 +1591,13 @@ public:
bool contains (Point<int> localPos, bool trueIfInAChildWindow) const override bool contains (Point<int> localPos, bool trueIfInAChildWindow) const override
{ {
auto r = convertPhysicalScreenRectangleToLogical (D2DUtilities::toRectangle (getWindowScreenRect (hwnd)), hwnd); const auto localPhysical = localPos.toFloat() / getPlatformScaleFactor();
auto r = D2DUtilities::toRectangle (getWindowScreenRect (hwnd)).toFloat();
if (! r.withZeroOrigin().contains (localPos)) if (! r.withZeroOrigin().contains (localPhysical))
return false; return false;
const auto screenPos = convertLogicalScreenPointToPhysical (localPos + getScreenPosition(), hwnd); const auto screenPos = (localPhysical + getClientRectInScreen().getPosition().toFloat()).roundToInt();
auto w = WindowFromPoint (D2DUtilities::toPOINT (screenPos)); auto w = WindowFromPoint (D2DUtilities::toPOINT (screenPos));
return w == hwnd || (trueIfInAChildWindow && (IsChild (hwnd, w) != 0)); return w == hwnd || (trueIfInAChildWindow && (IsChild (hwnd, w) != 0));
@ -1596,7 +1610,7 @@ public:
BorderSize<int> getFrameSize() const override BorderSize<int> getFrameSize() const override
{ {
return findPhysicalBorderSize().value_or (BorderSize<int>{}).multipliedBy (1.0 / scaleFactor); return findPhysicalBorderSize().value_or (BorderSize<int>{}).multipliedBy (1.0 / getPlatformScaleFactor());
} }
bool setAlwaysOnTop (bool alwaysOnTop) override bool setAlwaysOnTop (bool alwaysOnTop) override
@ -1993,7 +2007,7 @@ public:
return peer->doKeyUp (msg.wParam); return peer->doKeyUp (msg.wParam);
} }
double getPlatformScaleFactor() const noexcept override double getPlatformScaleFactorWithoutOverride() const noexcept
{ {
#if ! JUCE_WIN_PER_MONITOR_DPI_AWARE #if ! JUCE_WIN_PER_MONITOR_DPI_AWARE
return 1.0; return 1.0;
@ -2013,6 +2027,31 @@ public:
#endif #endif
} }
double getPlatformScaleFactor() const noexcept override
{
if (scaleFactorOverride.has_value())
return *scaleFactorOverride;
return getPlatformScaleFactorWithoutOverride();
}
void setCustomPlatformScaleFactor (std::optional<double> scaleIn) override
{
const auto prev = getPlatformScaleFactor();
scaleFactorOverride = scaleIn;
const auto next = getPlatformScaleFactor();
if (approximatelyEqual (prev, next))
return;
scaleFactorListeners.call ([&] (ScaleFactorListener& l) { l.nativeScaleFactorChanged (next); });
}
std::optional<double> getCustomPlatformScaleFactor() const override
{
return scaleFactorOverride;
}
static void getLastError() static void getLastError()
{ {
TCHAR messageBuffer[256] = {}; TCHAR messageBuffer[256] = {};
@ -2065,7 +2104,6 @@ public:
} }
bool hasTitleBar() const { return (styleFlags & windowHasTitleBar) != 0; } bool hasTitleBar() const { return (styleFlags & windowHasTitleBar) != 0; }
double getScaleFactor() const { return scaleFactor; }
private: private:
HWND hwnd, parentToAddTo; HWND hwnd, parentToAddTo;
@ -2083,6 +2121,7 @@ private:
#endif #endif
double scaleFactor = 1.0; double scaleFactor = 1.0;
std::optional<double> scaleFactorOverride;
bool inDpiChange = 0, inHandlePositionChanged = 0; bool inDpiChange = 0, inHandlePositionChanged = 0;
HMONITOR currentMonitor = nullptr; HMONITOR currentMonitor = nullptr;
@ -4264,8 +4303,8 @@ private:
{ {
if (auto parentHwnd = GetParent (hwnd)) if (auto parentHwnd = GetParent (hwnd))
{ {
auto parentRect = convertPhysicalScreenRectangleToLogical (D2DUtilities::toRectangle (getWindowScreenRect (parentHwnd)), hwnd); const auto parentRect = convertPhysicalScreenRectangleToLogical (D2DUtilities::toRectangle (getWindowScreenRect (parentHwnd)), hwnd);
newBounds.translate (parentRect.getX(), parentRect.getY()); newBounds += parentRect.getPosition();
} }
} }
@ -5787,7 +5826,7 @@ static const Displays::Display* getCurrentDisplayFromScaleFactor (HWND hwnd)
const auto scaleToLookFor = [&] const auto scaleToLookFor = [&]
{ {
if (auto* peer = HWNDComponentPeer::getOwnerOfWindow (hwnd)) if (auto* peer = HWNDComponentPeer::getOwnerOfWindow (hwnd))
return peer->getPlatformScaleFactor(); return peer->getPlatformScaleFactorWithoutOverride();
return getScaleFactorForWindow (hwnd); return getScaleFactorForWindow (hwnd);
}(); }();

View file

@ -544,6 +544,25 @@ public:
*/ */
virtual double getPlatformScaleFactor() const noexcept { return 1.0; } virtual double getPlatformScaleFactor() const noexcept { return 1.0; }
/** On Windows and Linux, calling this with a non-null optional will override whatever scale
factor the platform has specified for this window. The new scale factor will persist even
in the case that the platform attempts to set a new scale! Pass a null optional to revert
back to the platform-provided scale.
This is intended for use by plugin wrappers, where hosts may attempt to set a scale factor
different from the platform scale. You should never need to call this directly.
*/
virtual void setCustomPlatformScaleFactor (std::optional<double>) {}
/** Returns the custom scale factor set using setCustomPlatformScaleFactor(), if any.
If a custom scale factor has been set, getPlatformScaleFactor() will always return that
value, effectively overriding any scale factor requested by the system.
Otherwise, if the custom platform scale factor is nullopt, then the system will update the
scale factor automatically.
*/
virtual std::optional<double> getCustomPlatformScaleFactor() const { return {}; }
/** On platforms that support it, this will update the window's titlebar in some /** On platforms that support it, this will update the window's titlebar in some
way to indicate that the window's document needs saving. way to indicate that the window's document needs saving.
*/ */