mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Windows: Added ScopedThreadDPIAwarenessSetter for correctly setting and resetting thread DPI-awareness for methods which interact with an HWND and removed some DPI workarounds
This commit is contained in:
parent
3a0af69eff
commit
f6338c0f8e
11 changed files with 236 additions and 157 deletions
|
|
@ -83,9 +83,6 @@ JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4355)
|
|||
//==============================================================================
|
||||
namespace juce
|
||||
{
|
||||
#if JUCE_WINDOWS
|
||||
extern void setThreadDPIAwarenessForWindow (HWND);
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
namespace
|
||||
|
|
@ -2865,7 +2862,7 @@ public:
|
|||
#if JUCE_WINDOWS
|
||||
if (pluginHWND != 0)
|
||||
{
|
||||
setThreadDPIAwarenessForWindow (pluginHWND);
|
||||
ScopedThreadDPIAwarenessSetter threadDpiAwarenessSetter { pluginHWND };
|
||||
|
||||
MoveWindow (pluginHWND, pos.getX(), pos.getY(),
|
||||
roundToInt (getWidth() * nativeScaleFactor),
|
||||
|
|
@ -3128,7 +3125,7 @@ private:
|
|||
// very dodgy logic to decide which size is right.
|
||||
if (std::abs (rw - w) > 350 || std::abs (rh - h) > 350)
|
||||
{
|
||||
setThreadDPIAwarenessForWindow (pluginHWND);
|
||||
ScopedThreadDPIAwarenessSetter threadDpiAwarenessSetter { pluginHWND };
|
||||
|
||||
SetWindowPos (pluginHWND, 0,
|
||||
0, 0, roundToInt (rw * nativeScaleFactor), roundToInt (rh * nativeScaleFactor),
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1
|
||||
#define JUCE_CORE_INCLUDE_OBJC_HELPERS 1
|
||||
#define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1
|
||||
#define JUCE_GUI_BASICS_INCLUDE_SCOPED_THREAD_DPI_AWARENESS_SETTER 1
|
||||
|
||||
#include "juce_audio_processors.h"
|
||||
#include <juce_gui_extra/juce_gui_extra.h>
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#define JUCE_EVENTS_INCLUDE_WIN32_MESSAGE_WINDOW 1
|
||||
#define JUCE_GRAPHICS_INCLUDE_COREGRAPHICS_HELPERS 1
|
||||
#define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1
|
||||
#define JUCE_GUI_BASICS_INCLUDE_SCOPED_THREAD_DPI_AWARENESS_SETTER 1
|
||||
|
||||
#include "juce_gui_basics.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -342,6 +342,10 @@ namespace juce
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if JUCE_GUI_BASICS_INCLUDE_SCOPED_THREAD_DPI_AWARENESS_SETTER && JUCE_WINDOWS
|
||||
#include "native/juce_win32_ScopedThreadDPIAwarenessSetter.h"
|
||||
#endif
|
||||
|
||||
#include "layout/juce_FlexItem.h"
|
||||
#include "layout/juce_FlexBox.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
class ScopedThreadDPIAwarenessSetter
|
||||
{
|
||||
public:
|
||||
explicit ScopedThreadDPIAwarenessSetter (void* nativeWindow);
|
||||
~ScopedThreadDPIAwarenessSetter();
|
||||
|
||||
private:
|
||||
class NativeImpl;
|
||||
std::unique_ptr<NativeImpl> pimpl;
|
||||
|
||||
JUCE_LEAK_DETECTOR (ScopedThreadDPIAwarenessSetter)
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
302
modules/juce_gui_basics/native/juce_win32_Windowing.cpp
Executable file → Normal file
302
modules/juce_gui_basics/native/juce_win32_Windowing.cpp
Executable file → Normal file
|
|
@ -63,6 +63,12 @@ static bool shouldDeactivateTitleBar = true;
|
|||
|
||||
void* getUser32Function (const char*);
|
||||
|
||||
#if JUCE_DEBUG
|
||||
int numActiveScopedDpiAwarenessDisablers = 0;
|
||||
bool isInScopedDPIAwarenessDisabler() { return numActiveScopedDpiAwarenessDisablers > 0; }
|
||||
extern HWND juce_messageWindowHandle;
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
#ifndef WM_TOUCH
|
||||
enum
|
||||
|
|
@ -408,7 +414,10 @@ static void setDPIAwareness()
|
|||
|
||||
static bool isPerMonitorDPIAwareProcess()
|
||||
{
|
||||
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
|
||||
#if ! JUCE_WIN_PER_MONITOR_DPI_AWARE
|
||||
return false;
|
||||
#endif
|
||||
|
||||
static bool dpiAware = []() -> bool
|
||||
{
|
||||
setDPIAwareness();
|
||||
|
|
@ -423,40 +432,43 @@ static bool isPerMonitorDPIAwareProcess()
|
|||
}();
|
||||
|
||||
return dpiAware;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool isPerMonitorDPIAwareWindow (HWND h)
|
||||
static bool isPerMonitorDPIAwareWindow (HWND nativeWindow)
|
||||
{
|
||||
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
|
||||
jassert (h != nullptr);
|
||||
|
||||
setDPIAwareness();
|
||||
|
||||
if (getWindowDPIAwarenessContext != nullptr && getAwarenessFromDPIAwarenessContext != nullptr)
|
||||
return getAwarenessFromDPIAwarenessContext (getWindowDPIAwarenessContext (h)) == DPI_Awareness::DPI_Awareness_Per_Monitor_Aware;
|
||||
|
||||
return isPerMonitorDPIAwareProcess();
|
||||
#else
|
||||
#if ! JUCE_WIN_PER_MONITOR_DPI_AWARE
|
||||
ignoreUnused (h);
|
||||
return false;
|
||||
#endif
|
||||
|
||||
setDPIAwareness();
|
||||
|
||||
if (getWindowDPIAwarenessContext != nullptr
|
||||
&& getAwarenessFromDPIAwarenessContext != nullptr)
|
||||
{
|
||||
return (getAwarenessFromDPIAwarenessContext (getWindowDPIAwarenessContext (nativeWindow))
|
||||
== DPI_Awareness::DPI_Awareness_Per_Monitor_Aware);
|
||||
}
|
||||
|
||||
return isPerMonitorDPIAwareProcess();
|
||||
}
|
||||
|
||||
static bool isPerMonitorDPIAwareThread()
|
||||
{
|
||||
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
|
||||
setDPIAwareness();
|
||||
|
||||
if (getThreadDPIAwarenessContext != nullptr && getAwarenessFromDPIAwarenessContext != nullptr)
|
||||
return getAwarenessFromDPIAwarenessContext (getThreadDPIAwarenessContext()) == DPI_Awareness::DPI_Awareness_Per_Monitor_Aware;
|
||||
|
||||
return isPerMonitorDPIAwareProcess();
|
||||
#else
|
||||
#if ! JUCE_WIN_PER_MONITOR_DPI_AWARE
|
||||
return false;
|
||||
#endif
|
||||
|
||||
setDPIAwareness();
|
||||
|
||||
if (getThreadDPIAwarenessContext != nullptr
|
||||
&& getAwarenessFromDPIAwarenessContext != nullptr)
|
||||
{
|
||||
return (getAwarenessFromDPIAwarenessContext (getThreadDPIAwarenessContext())
|
||||
== DPI_Awareness::DPI_Awareness_Per_Monitor_Aware);
|
||||
}
|
||||
|
||||
return isPerMonitorDPIAwareProcess();
|
||||
}
|
||||
|
||||
static double getGlobalDPI()
|
||||
|
|
@ -470,6 +482,83 @@ static double getGlobalDPI()
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
class ScopedThreadDPIAwarenessSetter::NativeImpl
|
||||
{
|
||||
public:
|
||||
explicit NativeImpl (HWND nativeWindow)
|
||||
{
|
||||
ignoreUnused (nativeWindow);
|
||||
|
||||
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
|
||||
if (auto* functionSingleton = FunctionSingleton::getInstance())
|
||||
{
|
||||
if (! functionSingleton->isLoaded())
|
||||
return;
|
||||
|
||||
auto dpiAwareWindow = (functionSingleton->getAwarenessFromContext (functionSingleton->getWindowAwareness (nativeWindow))
|
||||
== DPI_Awareness::DPI_Awareness_Per_Monitor_Aware);
|
||||
|
||||
auto dpiAwareThread = (functionSingleton->getAwarenessFromContext (functionSingleton->getThreadAwareness())
|
||||
== DPI_Awareness::DPI_Awareness_Per_Monitor_Aware);
|
||||
|
||||
if (dpiAwareWindow && ! dpiAwareThread)
|
||||
oldContext = functionSingleton->setThreadAwareness (DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
|
||||
else if (! dpiAwareWindow && dpiAwareThread)
|
||||
oldContext = functionSingleton->setThreadAwareness (DPI_AWARENESS_CONTEXT_UNAWARE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
~NativeImpl()
|
||||
{
|
||||
if (oldContext != nullptr)
|
||||
if (auto* functionSingleton = FunctionSingleton::getInstance())
|
||||
functionSingleton->setThreadAwareness (oldContext);
|
||||
}
|
||||
|
||||
private:
|
||||
struct FunctionSingleton : public DeletedAtShutdown
|
||||
{
|
||||
FunctionSingleton() = default;
|
||||
~FunctionSingleton() override { clearSingletonInstance(); }
|
||||
|
||||
SetThreadDPIAwarenessContextFunc setThreadAwareness = (SetThreadDPIAwarenessContextFunc) getUser32Function ("SetThreadDpiAwarenessContext");
|
||||
GetWindowDPIAwarenessContextFunc getWindowAwareness = (GetWindowDPIAwarenessContextFunc) getUser32Function ("GetWindowDpiAwarenessContext");
|
||||
GetThreadDPIAwarenessContextFunc getThreadAwareness = (GetThreadDPIAwarenessContextFunc) getUser32Function ("GetThreadDpiAwarenessContext");
|
||||
GetAwarenessFromDpiAwarenessContextFunc getAwarenessFromContext = (GetAwarenessFromDpiAwarenessContextFunc) getUser32Function ("GetAwarenessFromDpiAwarenessContext");
|
||||
|
||||
bool isLoaded() const noexcept
|
||||
{
|
||||
return setThreadAwareness != nullptr
|
||||
&& getWindowAwareness != nullptr
|
||||
&& getThreadAwareness != nullptr
|
||||
&& getAwarenessFromContext != nullptr;
|
||||
}
|
||||
|
||||
JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL (FunctionSingleton)
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (FunctionSingleton)
|
||||
JUCE_DECLARE_NON_MOVEABLE (FunctionSingleton)
|
||||
};
|
||||
|
||||
DPI_AWARENESS_CONTEXT oldContext = nullptr;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeImpl)
|
||||
JUCE_DECLARE_NON_MOVEABLE (NativeImpl)
|
||||
};
|
||||
|
||||
|
||||
JUCE_IMPLEMENT_SINGLETON (ScopedThreadDPIAwarenessSetter::NativeImpl::FunctionSingleton)
|
||||
|
||||
ScopedThreadDPIAwarenessSetter::ScopedThreadDPIAwarenessSetter (void* nativeWindow)
|
||||
{
|
||||
pimpl = std::make_unique<NativeImpl> ((HWND) nativeWindow);
|
||||
}
|
||||
|
||||
ScopedThreadDPIAwarenessSetter::~ScopedThreadDPIAwarenessSetter()
|
||||
{
|
||||
}
|
||||
|
||||
#if JUCE_MODULE_AVAILABLE_juce_gui_extra
|
||||
ScopedDPIAwarenessDisabler::ScopedDPIAwarenessDisabler()
|
||||
{
|
||||
|
|
@ -477,13 +566,25 @@ static double getGlobalDPI()
|
|||
return;
|
||||
|
||||
if (setThreadDPIAwarenessContext != nullptr)
|
||||
{
|
||||
previousContext = setThreadDPIAwarenessContext (DPI_AWARENESS_CONTEXT_UNAWARE);
|
||||
|
||||
#if JUCE_DEBUG
|
||||
++numActiveScopedDpiAwarenessDisablers;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
ScopedDPIAwarenessDisabler::~ScopedDPIAwarenessDisabler()
|
||||
{
|
||||
if (previousContext != nullptr)
|
||||
{
|
||||
setThreadDPIAwarenessContext ((DPI_AWARENESS_CONTEXT) previousContext);
|
||||
|
||||
#if JUCE_DEBUG
|
||||
--numActiveScopedDpiAwarenessDisablers;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -527,6 +628,14 @@ static Point<int> convertPhysicalScreenPointToLogical (Point<int> p, HWND h) noe
|
|||
return p;
|
||||
}
|
||||
|
||||
static Point<int> convertLogicalScreenPointToPhysical (Point<int> p, HWND h) noexcept
|
||||
{
|
||||
if (isPerMonitorDPIAwareWindow (h))
|
||||
return Desktop::getInstance().getDisplays().logicalToPhysical (p, getCurrentDisplayFromScaleFactor (h));
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
JUCE_API double getScaleFactorForWindow (HWND h)
|
||||
{
|
||||
// NB. Using a local function here because we need to call this method from the plug-in wrappers
|
||||
|
|
@ -549,50 +658,11 @@ JUCE_API double getScaleFactorForWindow (HWND h)
|
|||
return 1.0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
ScopedThreadDPIAwarenessSetter setter { hwnd };
|
||||
|
||||
if (isPerMonitorDPIAwareWindow (hwnd))
|
||||
{
|
||||
if (adjustTopLeft)
|
||||
|
|
@ -607,9 +677,7 @@ static void setWindowPos (HWND hwnd, Rectangle<int> bounds, UINT flags, bool adj
|
|||
|
||||
static RECT getWindowScreenRect (HWND hwnd)
|
||||
{
|
||||
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
|
||||
setThreadDPIAwarenessForWindow (hwnd);
|
||||
#endif
|
||||
ScopedThreadDPIAwarenessSetter setter { hwnd };
|
||||
|
||||
RECT rect;
|
||||
GetWindowRect (hwnd, &rect);
|
||||
|
|
@ -621,7 +689,10 @@ static RECT getWindowClientRect (HWND hwnd)
|
|||
auto rect = getWindowScreenRect (hwnd);
|
||||
|
||||
if (auto parentH = GetParent (hwnd))
|
||||
{
|
||||
ScopedThreadDPIAwarenessSetter setter { hwnd };
|
||||
MapWindowPoints (HWND_DESKTOP, parentH, (LPPOINT) &rect, 2);
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
|
@ -634,14 +705,8 @@ static void setWindowZOrder (HWND hwnd, HWND insertAfter)
|
|||
//==============================================================================
|
||||
double Desktop::getDefaultMasterScale()
|
||||
{
|
||||
if (! JUCEApplicationBase::isStandaloneApp()
|
||||
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
|
||||
|| isPerMonitorDPIAwareProcess()
|
||||
#endif
|
||||
)
|
||||
{
|
||||
if (! JUCEApplicationBase::isStandaloneApp() || isPerMonitorDPIAwareProcess())
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
return getGlobalDPI() / USER_DEFAULT_SCREEN_DPI;
|
||||
}
|
||||
|
|
@ -893,8 +958,8 @@ Image createSnapshotOfNativeWindow (void* nativeWindowHandle)
|
|||
auto hwnd = (HWND) nativeWindowHandle;
|
||||
|
||||
auto r = convertPhysicalScreenRectangleToLogical (rectangleFromRECT (getWindowScreenRect (hwnd)), hwnd);
|
||||
const int w = r.getWidth();
|
||||
const int h = r.getHeight();
|
||||
const auto w = r.getWidth();
|
||||
const auto h = r.getHeight();
|
||||
|
||||
auto nativeBitmap = new WindowsBitmapImage (Image::RGB, w, h, true);
|
||||
Image bitmap (nativeBitmap);
|
||||
|
|
@ -1433,10 +1498,8 @@ public:
|
|||
|
||||
auto localBounds = rectangleFromRECT (getWindowClientRect (hwnd));
|
||||
|
||||
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
|
||||
if (isPerMonitorDPIAwareWindow (hwnd))
|
||||
return (localBounds.toDouble() / getPlatformScaleFactor()).toNearestInt();
|
||||
#endif
|
||||
|
||||
return localBounds;
|
||||
}();
|
||||
|
|
@ -1554,16 +1617,10 @@ public:
|
|||
if (! r.withZeroOrigin().contains (localPos))
|
||||
return false;
|
||||
|
||||
auto globalPos = localPos + getScreenPosition();
|
||||
auto w = WindowFromPoint (POINTFromPoint (convertLogicalScreenPointToPhysical (localPos + getScreenPosition(),
|
||||
hwnd)));
|
||||
|
||||
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
|
||||
if (isPerMonitorDPIAwareThread() || isPerMonitorDPIAwareWindow (hwnd))
|
||||
globalPos = Desktop::getInstance().getDisplays().logicalToPhysical (globalPos);
|
||||
#endif
|
||||
|
||||
auto w = WindowFromPoint (POINTFromPoint (globalPos));
|
||||
|
||||
return w == hwnd || (trueIfInAChildWindow && (IsChild (hwnd, w) != 0));
|
||||
return w == hwnd || (trueIfInAChildWindow && (IsChild (hwnd, w) != 0));
|
||||
}
|
||||
|
||||
BorderSize<int> getFrameSize() const override
|
||||
|
|
@ -1663,18 +1720,7 @@ public:
|
|||
|
||||
void repaint (const Rectangle<int>& area) override
|
||||
{
|
||||
auto scale = getPlatformScaleFactor();
|
||||
|
||||
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
|
||||
// if the calling thread is DPI-aware but we are invalidating a non-DPI aware window RECT, we actually have to
|
||||
// divide the bounds by the scale factor as it will get multiplied for the virtualised paint callback...
|
||||
if (isPerMonitorDPIAwareThread() && ! isPerMonitorDPIAwareWindow (hwnd))
|
||||
scale = 1.0 / Desktop::getInstance().getDisplays().getPrimaryDisplay()->scale;
|
||||
#endif
|
||||
|
||||
auto scaled = area.toDouble() * scale;
|
||||
auto r = RECTFromRectangle (scaled.getSmallestIntegerContainer());
|
||||
|
||||
auto r = RECTFromRectangle ((area.toDouble() * getPlatformScaleFactor()).getSmallestIntegerContainer());
|
||||
InvalidateRect (hwnd, &r, FALSE);
|
||||
}
|
||||
|
||||
|
|
@ -1795,19 +1841,8 @@ public:
|
|||
private:
|
||||
Point<float> getMousePos (POINTL mousePos) const
|
||||
{
|
||||
auto screenPos = pointFromPOINT ({ mousePos.x, mousePos.y }).toFloat();
|
||||
|
||||
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
|
||||
auto h = (HWND) peer.getNativeHandle();
|
||||
|
||||
if (isPerMonitorDPIAwareWindow (h))
|
||||
screenPos = convertPhysicalScreenPointToLogical (screenPos.roundToInt(), h).toFloat();
|
||||
#else
|
||||
if (JUCEApplication::isStandaloneApp())
|
||||
screenPos /= static_cast<float> (getGlobalDPI() / USER_DEFAULT_SCREEN_DPI);
|
||||
#endif
|
||||
|
||||
return peer.getComponent().getLocalPoint (nullptr, screenPos);
|
||||
return peer.getComponent().getLocalPoint (nullptr, convertPhysicalScreenPointToLogical (pointFromPOINT ({ mousePos.x, mousePos.y }),
|
||||
(HWND) peer.getNativeHandle()).toFloat());
|
||||
}
|
||||
|
||||
struct DroppedData
|
||||
|
|
@ -1902,7 +1937,10 @@ public:
|
|||
|
||||
double getPlatformScaleFactor() const noexcept override
|
||||
{
|
||||
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
|
||||
#if ! JUCE_WIN_PER_MONITOR_DPI_AWARE
|
||||
return 1.0;
|
||||
#endif
|
||||
|
||||
if (! isPerMonitorDPIAwareWindow (hwnd))
|
||||
return 1.0;
|
||||
|
||||
|
|
@ -1916,9 +1954,6 @@ public:
|
|||
}
|
||||
|
||||
return scaleFactor;
|
||||
#else
|
||||
return 1.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -2153,6 +2188,14 @@ private:
|
|||
L"", type, 0, 0, 0, 0, parentToAddTo, nullptr,
|
||||
(HINSTANCE) Process::getCurrentModuleInstanceHandle(), nullptr);
|
||||
|
||||
#if JUCE_DEBUG
|
||||
// The DPI-awareness context of this window and JUCE's hidden message window are different.
|
||||
// You normally want these to match otherwise timer events and async messages will happen
|
||||
// in a different context to normal HWND messages which can cause issues with UI scaling.
|
||||
jassert (isPerMonitorDPIAwareWindow (hwnd) == isPerMonitorDPIAwareWindow (juce_messageWindowHandle)
|
||||
|| isInScopedDPIAwarenessDisabler());
|
||||
#endif
|
||||
|
||||
if (hwnd != nullptr)
|
||||
{
|
||||
SetWindowLongPtr (hwnd, 0, 0);
|
||||
|
|
@ -2179,19 +2222,8 @@ private:
|
|||
|
||||
setDPIAwareness();
|
||||
|
||||
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
|
||||
if (isPerMonitorDPIAwareThread())
|
||||
{
|
||||
auto bounds = component.getBounds();
|
||||
|
||||
if (bounds.isEmpty())
|
||||
scaleFactor = Desktop::getInstance().getDisplays().getPrimaryDisplay()->scale;
|
||||
else
|
||||
scaleFactor = Desktop::getInstance().getDisplays().getDisplayForRect (bounds)->scale;
|
||||
|
||||
scaleFactor /= Desktop::getInstance().getGlobalScaleFactor();
|
||||
}
|
||||
#endif
|
||||
scaleFactor = getScaleFactorForWindow (hwnd);
|
||||
|
||||
setMessageFilter();
|
||||
updateBorderSize();
|
||||
|
|
@ -3508,20 +3540,18 @@ private:
|
|||
|
||||
Point<float> getPointFromLocalLParam (LPARAM lParam) noexcept
|
||||
{
|
||||
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
|
||||
auto p = pointFromPOINT (getPOINTFromLParam (lParam));
|
||||
|
||||
if (isPerMonitorDPIAwareWindow (hwnd))
|
||||
{
|
||||
// LPARAM is relative to this window's top-left but may be on a different monitor so we need to calculate the
|
||||
// physical screen position and then convert this to local logical coordinates
|
||||
auto localPos = getPOINTFromLParam (lParam);
|
||||
auto r = getWindowScreenRect (hwnd);
|
||||
|
||||
return globalToLocal (Desktop::getInstance().getDisplays().physicalToLogical (pointFromPOINT ({ r.left + localPos.x + roundToInt (windowBorder.getLeft() * scaleFactor),
|
||||
r.top + localPos.y + roundToInt (windowBorder.getTop() * scaleFactor) })).toFloat());
|
||||
return globalToLocal (Desktop::getInstance().getDisplays().physicalToLogical (pointFromPOINT ({ r.left + p.x + roundToInt (windowBorder.getLeft() * scaleFactor),
|
||||
r.top + p.y + roundToInt (windowBorder.getTop() * scaleFactor) })).toFloat());
|
||||
}
|
||||
#endif
|
||||
|
||||
return { static_cast<float> (GET_X_LPARAM (lParam)), static_cast<float> (GET_Y_LPARAM (lParam)) };
|
||||
return p.toFloat();
|
||||
}
|
||||
|
||||
Point<float> getCurrentMousePos() noexcept
|
||||
|
|
@ -4431,10 +4461,8 @@ Point<float> MouseInputSource::getCurrentRawMousePosition()
|
|||
|
||||
auto p = pointFromPOINT (mousePos);
|
||||
|
||||
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
|
||||
if (isPerMonitorDPIAwareThread())
|
||||
p = Desktop::getInstance().getDisplays().physicalToLogical (p);
|
||||
#endif
|
||||
|
||||
return p.toFloat();
|
||||
}
|
||||
|
|
|
|||
0
modules/juce_gui_extra/embedding/juce_ScopedDPIAwarenessDisabler.h
Normal file → Executable file
0
modules/juce_gui_extra/embedding/juce_ScopedDPIAwarenessDisabler.h
Normal file → Executable file
1
modules/juce_gui_extra/juce_gui_extra.cpp
Normal file → Executable file
1
modules/juce_gui_extra/juce_gui_extra.cpp
Normal file → Executable file
|
|
@ -39,6 +39,7 @@
|
|||
#define JUCE_EVENTS_INCLUDE_WIN32_MESSAGE_WINDOW 1
|
||||
#define JUCE_GRAPHICS_INCLUDE_COREGRAPHICS_HELPERS 1
|
||||
#define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1
|
||||
#define JUCE_GUI_BASICS_INCLUDE_SCOPED_THREAD_DPI_AWARENESS_SETTER 1
|
||||
|
||||
#ifndef JUCE_PUSH_NOTIFICATIONS
|
||||
#define JUCE_PUSH_NOTIFICATIONS 0
|
||||
|
|
|
|||
|
|
@ -26,8 +26,6 @@
|
|||
namespace juce
|
||||
{
|
||||
|
||||
void setThreadDPIAwarenessForWindow (HWND);
|
||||
|
||||
class HWNDComponent::Pimpl : public ComponentMovementWatcher
|
||||
{
|
||||
public:
|
||||
|
|
@ -52,13 +50,13 @@ public:
|
|||
{
|
||||
auto area = (peer->getAreaCoveredBy (owner).toFloat() * peer->getPlatformScaleFactor()).getSmallestIntegerContainer();
|
||||
|
||||
setThreadDPIAwarenessForWindow (hwnd);
|
||||
|
||||
UINT flagsToSend = SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER;
|
||||
|
||||
if (! wasMoved) flagsToSend |= SWP_NOMOVE;
|
||||
if (! wasResized) flagsToSend |= SWP_NOSIZE;
|
||||
|
||||
ScopedThreadDPIAwarenessSetter threadDpiAwarenessSetter { hwnd };
|
||||
|
||||
SetWindowPos (hwnd, nullptr, area.getX(), area.getY(), area.getWidth(), area.getHeight(), flagsToSend);
|
||||
}
|
||||
}
|
||||
|
|
@ -101,7 +99,7 @@ public:
|
|||
{
|
||||
if (auto* peer = owner.getPeer())
|
||||
{
|
||||
setThreadDPIAwarenessForWindow (hwnd);
|
||||
ScopedThreadDPIAwarenessSetter threadDpiAwarenessSetter { hwnd };
|
||||
|
||||
RECT r;
|
||||
GetWindowRect (hwnd, &r);
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1
|
||||
#define JUCE_GRAPHICS_INCLUDE_COREGRAPHICS_HELPERS 1
|
||||
#define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1
|
||||
#define JUCE_GUI_BASICS_INCLUDE_SCOPED_THREAD_DPI_AWARENESS_SETTER 1
|
||||
|
||||
#include "juce_opengl.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -28,10 +28,6 @@ namespace juce
|
|||
|
||||
extern ComponentPeer* createNonRepaintingEmbeddedWindowsPeer (Component&, void* parent);
|
||||
|
||||
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
|
||||
extern void setThreadDPIAwarenessForWindow (HWND);
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
class OpenGLContext::NativeContext
|
||||
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
|
||||
|
|
@ -97,15 +93,17 @@ public:
|
|||
|
||||
bool initialiseOnRenderThread (OpenGLContext& c)
|
||||
{
|
||||
#if JUCE_WIN_PER_MONITOR_DPI_AWARE
|
||||
setThreadDPIAwarenessForWindow ((HWND) nativeWindow->getNativeHandle());
|
||||
#endif
|
||||
|
||||
threadAwarenessSetter = std::make_unique<ScopedThreadDPIAwarenessSetter> (nativeWindow->getNativeHandle());
|
||||
context = &c;
|
||||
return true;
|
||||
}
|
||||
|
||||
void shutdownOnRenderThread() { deactivateCurrentContext(); context = nullptr; }
|
||||
void shutdownOnRenderThread()
|
||||
{
|
||||
deactivateCurrentContext();
|
||||
context = nullptr;
|
||||
threadAwarenessSetter = nullptr;
|
||||
}
|
||||
|
||||
static void deactivateCurrentContext() { wglMakeCurrent (nullptr, nullptr); }
|
||||
bool makeActive() const noexcept { return isActive() || wglMakeCurrent (dc, renderContext) != FALSE; }
|
||||
|
|
@ -170,6 +168,7 @@ private:
|
|||
|
||||
std::unique_ptr<DummyComponent> dummyComponent;
|
||||
std::unique_ptr<ComponentPeer> nativeWindow;
|
||||
std::unique_ptr<ScopedThreadDPIAwarenessSetter> threadAwarenessSetter;
|
||||
HGLRC renderContext;
|
||||
HDC dc;
|
||||
OpenGLContext* context = {};
|
||||
|
|
@ -219,7 +218,13 @@ private:
|
|||
void createNativeWindow (Component& component)
|
||||
{
|
||||
auto* topComp = component.getTopLevelComponent();
|
||||
nativeWindow.reset (createNonRepaintingEmbeddedWindowsPeer (*dummyComponent, topComp->getWindowHandle()));
|
||||
|
||||
{
|
||||
auto* parentHWND = topComp->getWindowHandle();
|
||||
|
||||
ScopedThreadDPIAwarenessSetter setter { parentHWND };
|
||||
nativeWindow.reset (createNonRepaintingEmbeddedWindowsPeer (*dummyComponent, parentHWND));
|
||||
}
|
||||
|
||||
if (auto* peer = topComp->getPeer())
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue