@@ -547,44 +547,46 @@ JUCE_API double getScaleFactorForWindow (HWND h) | |||||
return 1.0; | return 1.0; | ||||
} | } | ||||
#if JUCE_WIN_PER_MONITOR_DPI_AWARE | |||||
JUCE_API void setThreadDPIAwarenessForWindow (HWND nativeWindow) | |||||
{ | |||||
// NB. Using local functions here because we need to call this method from the plug-in wrappers | |||||
// which don't load the DPI-awareness functions on startup | |||||
static SetThreadDPIAwarenessContextFunc localSetThreadDPIAwarenessContext = nullptr; | |||||
static GetWindowDPIAwarenessContextFunc localGetWindowDPIAwarenessContext = nullptr; | |||||
static GetThreadDPIAwarenessContextFunc localGetThreadDPIAwarenessContext = nullptr; | |||||
static GetAwarenessFromDpiAwarenessContextFunc localGetAwarenessFromDPIAwarenessContext = nullptr; | |||||
static bool hasChecked = false; | |||||
static bool loadedOK = false; | |||||
if (! hasChecked) | |||||
{ | |||||
hasChecked = true; | |||||
localSetThreadDPIAwarenessContext = (SetThreadDPIAwarenessContextFunc) getUser32Function ("SetThreadDpiAwarenessContext"); | |||||
localGetWindowDPIAwarenessContext = (GetWindowDPIAwarenessContextFunc) getUser32Function ("GetWindowDpiAwarenessContext"); | |||||
localGetThreadDPIAwarenessContext = (GetThreadDPIAwarenessContextFunc) getUser32Function ("GetThreadDpiAwarenessContext"); | |||||
localGetAwarenessFromDPIAwarenessContext = (GetAwarenessFromDpiAwarenessContextFunc) getUser32Function ("GetAwarenessFromDpiAwarenessContext"); | |||||
loadedOK = (localSetThreadDPIAwarenessContext != nullptr && localGetWindowDPIAwarenessContext != nullptr | |||||
&& localGetThreadDPIAwarenessContext != nullptr && localGetAwarenessFromDPIAwarenessContext != nullptr); | |||||
} | |||||
if (loadedOK) | |||||
{ | |||||
auto dpiAwareWindow = localGetAwarenessFromDPIAwarenessContext (localGetWindowDPIAwarenessContext (nativeWindow)) == DPI_Awareness::DPI_Awareness_Per_Monitor_Aware; | |||||
auto dpiAwareThread = localGetAwarenessFromDPIAwarenessContext (localGetThreadDPIAwarenessContext()) == DPI_Awareness::DPI_Awareness_Per_Monitor_Aware; | |||||
if (dpiAwareWindow && ! dpiAwareThread) | |||||
localSetThreadDPIAwarenessContext (DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE); | |||||
else if (! dpiAwareWindow && dpiAwareThread) | |||||
localSetThreadDPIAwarenessContext (DPI_AWARENESS_CONTEXT_UNAWARE); | |||||
} | |||||
} | |||||
#endif | |||||
JUCE_API void setThreadDPIAwarenessForWindow (HWND nativeWindow) | |||||
{ | |||||
#if JUCE_WIN_PER_MONITOR_DPI_AWARE | |||||
// NB. Using local functions here because we need to call this method from the plug-in wrappers | |||||
// which don't load the DPI-awareness functions on startup | |||||
static SetThreadDPIAwarenessContextFunc localSetThreadDPIAwarenessContext = nullptr; | |||||
static GetWindowDPIAwarenessContextFunc localGetWindowDPIAwarenessContext = nullptr; | |||||
static GetThreadDPIAwarenessContextFunc localGetThreadDPIAwarenessContext = nullptr; | |||||
static GetAwarenessFromDpiAwarenessContextFunc localGetAwarenessFromDPIAwarenessContext = nullptr; | |||||
static bool hasChecked = false; | |||||
static bool loadedOK = false; | |||||
if (! hasChecked) | |||||
{ | |||||
hasChecked = true; | |||||
localSetThreadDPIAwarenessContext = (SetThreadDPIAwarenessContextFunc) getUser32Function ("SetThreadDpiAwarenessContext"); | |||||
localGetWindowDPIAwarenessContext = (GetWindowDPIAwarenessContextFunc) getUser32Function ("GetWindowDpiAwarenessContext"); | |||||
localGetThreadDPIAwarenessContext = (GetThreadDPIAwarenessContextFunc) getUser32Function ("GetThreadDpiAwarenessContext"); | |||||
localGetAwarenessFromDPIAwarenessContext = (GetAwarenessFromDpiAwarenessContextFunc) getUser32Function ("GetAwarenessFromDpiAwarenessContext"); | |||||
loadedOK = (localSetThreadDPIAwarenessContext != nullptr && localGetWindowDPIAwarenessContext != nullptr | |||||
&& localGetThreadDPIAwarenessContext != nullptr && localGetAwarenessFromDPIAwarenessContext != nullptr); | |||||
} | |||||
if (loadedOK) | |||||
{ | |||||
auto dpiAwareWindow = localGetAwarenessFromDPIAwarenessContext (localGetWindowDPIAwarenessContext (nativeWindow)) == DPI_Awareness::DPI_Awareness_Per_Monitor_Aware; | |||||
auto dpiAwareThread = localGetAwarenessFromDPIAwarenessContext (localGetThreadDPIAwarenessContext()) == DPI_Awareness::DPI_Awareness_Per_Monitor_Aware; | |||||
if (dpiAwareWindow && ! dpiAwareThread) | |||||
localSetThreadDPIAwarenessContext (DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE); | |||||
else if (! dpiAwareWindow && dpiAwareThread) | |||||
localSetThreadDPIAwarenessContext (DPI_AWARENESS_CONTEXT_UNAWARE); | |||||
} | |||||
#else | |||||
ignoreUnused (nativeWindow); | |||||
#endif | |||||
} | |||||
//============================================================================== | //============================================================================== | ||||
static void setWindowPos (HWND hwnd, Rectangle<int> bounds, UINT flags, bool adjustTopLeft = false) | static void setWindowPos (HWND hwnd, Rectangle<int> bounds, UINT flags, bool adjustTopLeft = false) | ||||
@@ -71,6 +71,9 @@ public: | |||||
/** Resizes this component to fit the HWND that it contains. */ | /** Resizes this component to fit the HWND that it contains. */ | ||||
void resizeToFit(); | void resizeToFit(); | ||||
/** @internal */ | |||||
void paint (Graphics&) override; | |||||
private: | private: | ||||
class Pimpl; | class Pimpl; | ||||
std::unique_ptr<Pimpl> pimpl; | std::unique_ptr<Pimpl> pimpl; | ||||
@@ -26,6 +26,8 @@ | |||||
namespace juce | namespace juce | ||||
{ | { | ||||
void setThreadDPIAwarenessForWindow (HWND); | |||||
class HWNDComponent::Pimpl : public ComponentMovementWatcher | class HWNDComponent::Pimpl : public ComponentMovementWatcher | ||||
{ | { | ||||
public: | public: | ||||
@@ -44,27 +46,21 @@ public: | |||||
DestroyWindow (hwnd); | DestroyWindow (hwnd); | ||||
} | } | ||||
using ComponentMovementWatcher::componentMovedOrResized; | |||||
void componentMovedOrResized (bool wasMoved, bool wasResized) override | |||||
void componentMovedOrResized (bool, bool) override | |||||
{ | { | ||||
auto* topComponent = owner.getTopLevelComponent(); | |||||
if (auto* peer = owner.getPeer()) | |||||
if (auto* peer = owner.getTopLevelComponent()->getPeer()) | |||||
{ | { | ||||
auto pos = topComponent->getLocalPoint (&owner, Point<int>()); | |||||
auto area = (peer->getAreaCoveredBy (owner).toFloat() * peer->getPlatformScaleFactor()).toNearestInt(); | |||||
auto scaled = (Rectangle<int> (pos.x, pos.y, owner.getWidth(), owner.getHeight()).toDouble() | |||||
* peer->getPlatformScaleFactor()).getSmallestIntegerContainer(); | |||||
setThreadDPIAwarenessForWindow (hwnd); | |||||
DWORD windowFlags = SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER; | |||||
if (! wasMoved) windowFlags |= SWP_NOMOVE; | |||||
if (! wasResized) windowFlags |= SWP_NOSIZE; | |||||
SetWindowPos (hwnd, nullptr, scaled.getX(), scaled.getY(), scaled.getWidth(), scaled.getHeight(), windowFlags); | |||||
SetWindowPos (hwnd, nullptr, area.getX(), area.getY(), area.getWidth(), area.getHeight(), | |||||
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER); | |||||
} | } | ||||
} | } | ||||
using ComponentMovementWatcher::componentMovedOrResized; | |||||
void componentPeerChanged() override | void componentPeerChanged() override | ||||
{ | { | ||||
auto* peer = owner.getPeer(); | auto* peer = owner.getPeer(); | ||||
@@ -85,13 +81,13 @@ public: | |||||
InvalidateRect (hwnd, nullptr, 0); | InvalidateRect (hwnd, nullptr, 0); | ||||
} | } | ||||
using ComponentMovementWatcher::componentVisibilityChanged; | |||||
void componentVisibilityChanged() override | void componentVisibilityChanged() override | ||||
{ | { | ||||
componentPeerChanged(); | componentPeerChanged(); | ||||
} | } | ||||
using ComponentMovementWatcher::componentVisibilityChanged; | |||||
void componentBroughtToFront (Component& comp) override | void componentBroughtToFront (Component& comp) override | ||||
{ | { | ||||
ComponentMovementWatcher::componentBroughtToFront (comp); | ComponentMovementWatcher::componentBroughtToFront (comp); | ||||
@@ -101,11 +97,13 @@ public: | |||||
{ | { | ||||
if (auto* peer = owner.getPeer()) | if (auto* peer = owner.getPeer()) | ||||
{ | { | ||||
setThreadDPIAwarenessForWindow (hwnd); | |||||
RECT r; | RECT r; | ||||
GetWindowRect (hwnd, &r); | GetWindowRect (hwnd, &r); | ||||
Rectangle<int> windowRectangle (r.right - r.left, r.bottom - r.top); | |||||
return (Rectangle<int>::leftTopRightBottom (r.left, r.top, r.right, r.bottom).toDouble() | |||||
/ peer->getPlatformScaleFactor()).getSmallestIntegerContainer(); | |||||
return (windowRectangle.toFloat() / peer->getPlatformScaleFactor()).toNearestInt(); | |||||
} | } | ||||
return {}; | return {}; | ||||
@@ -120,7 +118,8 @@ private: | |||||
{ | { | ||||
auto windowFlags = GetWindowLongPtr (hwnd, -16); | auto windowFlags = GetWindowLongPtr (hwnd, -16); | ||||
windowFlags &= ~(WS_POPUP | WS_CHILD); | |||||
windowFlags &= ~WS_POPUP; | |||||
windowFlags |= WS_CHILD; | |||||
SetWindowLongPtr (hwnd, -16, windowFlags); | SetWindowLongPtr (hwnd, -16, windowFlags); | ||||
SetParent (hwnd, (HWND) currentPeer->getNativeHandle()); | SetParent (hwnd, (HWND) currentPeer->getNativeHandle()); | ||||
@@ -131,6 +130,7 @@ private: | |||||
void removeFromParent() | void removeFromParent() | ||||
{ | { | ||||
ShowWindow (hwnd, SW_HIDE); | |||||
SetParent (hwnd, NULL); | SetParent (hwnd, NULL); | ||||
} | } | ||||
@@ -141,12 +141,11 @@ private: | |||||
}; | }; | ||||
//============================================================================== | //============================================================================== | ||||
HWNDComponent::HWNDComponent() | |||||
{ | |||||
} | |||||
HWNDComponent::HWNDComponent() {} | |||||
HWNDComponent::~HWNDComponent() {} | HWNDComponent::~HWNDComponent() {} | ||||
void HWNDComponent::paint (Graphics&) {} | |||||
void HWNDComponent::setHWND (void* hwnd) | void HWNDComponent::setHWND (void* hwnd) | ||||
{ | { | ||||
if (hwnd != getHWND()) | if (hwnd != getHWND()) | ||||