aboutsummaryrefslogtreecommitdiffhomepage
path: root/win32/PlatWin.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'win32/PlatWin.cxx')
-rw-r--r--win32/PlatWin.cxx128
1 files changed, 89 insertions, 39 deletions
diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx
index 65e27b63a..40302102b 100644
--- a/win32/PlatWin.cxx
+++ b/win32/PlatWin.cxx
@@ -167,6 +167,9 @@ GetWindowDpiAwarenessContextSig fnGetWindowDpiAwarenessContext = nullptr;
using GetScaleFactorForMonitorSig = HRESULT(WINAPI *)(HMONITOR, DEVICE_SCALE_FACTOR *);
GetScaleFactorForMonitorSig fnGetScaleFactorForMonitor = nullptr;
+using GetThreadDpiAwarenessContextSig = DPI_AWARENESS_CONTEXT(WINAPI *)();
+GetThreadDpiAwarenessContextSig fnGetThreadDpiAwarenessContext = nullptr;
+
using SetThreadDpiAwarenessContextSig = DPI_AWARENESS_CONTEXT(WINAPI *)(DPI_AWARENESS_CONTEXT);
SetThreadDpiAwarenessContextSig fnSetThreadDpiAwarenessContext = nullptr;
@@ -175,6 +178,7 @@ void LoadDpiForWindow() noexcept {
fnGetDpiForWindow = DLLFunction<GetDpiForWindowSig>(user32, "GetDpiForWindow");
fnGetSystemMetricsForDpi = DLLFunction<GetSystemMetricsForDpiSig>(user32, "GetSystemMetricsForDpi");
fnAdjustWindowRectExForDpi = DLLFunction<AdjustWindowRectExForDpiSig>(user32, "AdjustWindowRectExForDpi");
+ fnGetThreadDpiAwarenessContext = DLLFunction<GetThreadDpiAwarenessContextSig>(user32, "GetThreadDpiAwarenessContext");
fnSetThreadDpiAwarenessContext = DLLFunction<SetThreadDpiAwarenessContextSig>(user32, "SetThreadDpiAwarenessContext");
using GetDpiForSystemSig = UINT(WINAPI *)(void);
@@ -393,7 +397,7 @@ HMONITOR MonitorFromWindowHandleScaling(HWND hWnd) noexcept {
return monitor;
}
-int GetDeviceScaleFactorWhenGdiScalingActive(HWND hWnd) noexcept {
+float GetDeviceScaleFactorWhenGdiScalingActive(HWND hWnd) noexcept {
if (fnAreDpiAwarenessContextsEqual) {
PLATFORM_ASSERT(fnGetWindowDpiAwarenessContext && fnGetScaleFactorForMonitor);
if (fnAreDpiAwarenessContextsEqual(DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED, fnGetWindowDpiAwarenessContext(hWnd))) {
@@ -401,10 +405,10 @@ int GetDeviceScaleFactorWhenGdiScalingActive(HWND hWnd) noexcept {
const HMONITOR hMonitor = MonitorFromWindowHandleScaling(hRootWnd);
DEVICE_SCALE_FACTOR deviceScaleFactor;
if (S_OK == fnGetScaleFactorForMonitor(hMonitor, &deviceScaleFactor))
- return (static_cast<int>(deviceScaleFactor) + 99) / 100; // increase to first integral multiple of 1
+ return deviceScaleFactor / 100.f;
}
}
- return 1;
+ return 1.f;
}
std::shared_ptr<Font> Font::Allocate(const FontParameters &fp) {
@@ -2778,56 +2782,102 @@ void Window::InvalidateRectangle(PRectangle rc) {
::InvalidateRect(HwndFromWindowID(wid), &rcw, FALSE);
}
-namespace {
-
-void FlipBitmap(HBITMAP bitmap, int width, int height) noexcept {
- HDC hdc = ::CreateCompatibleDC({});
- if (hdc) {
- HBITMAP prevBmp = SelectBitmap(hdc, bitmap);
- ::StretchBlt(hdc, width - 1, 0, -width, height, hdc, 0, 0, width, height, SRCCOPY);
- SelectBitmap(hdc, prevBmp);
- ::DeleteDC(hdc);
- }
-}
-
-}
-
HCURSOR LoadReverseArrowCursor(UINT dpi) noexcept {
- HCURSOR reverseArrowCursor {};
+ class CursorHelper {
+ public:
+ ICONINFO info{};
+ BITMAP bmp{};
+ bool HasBitmap() const noexcept {
+ return bmp.bmWidth > 0;
+ }
- bool created = false;
- HCURSOR cursor = ::LoadCursor({}, IDC_ARROW);
+ CursorHelper(const HCURSOR cursor) noexcept {
+ Init(cursor);
+ }
+ ~CursorHelper() {
+ CleanUp();
+ }
- if (dpi != uSystemDPI) {
- const int width = SystemMetricsForDpi(SM_CXCURSOR, dpi);
- const int height = SystemMetricsForDpi(SM_CYCURSOR, dpi);
- HCURSOR copy = static_cast<HCURSOR>(::CopyImage(cursor, IMAGE_CURSOR, width, height, LR_COPYFROMRESOURCE | LR_COPYRETURNORG));
- if (copy) {
- created = copy != cursor;
- cursor = copy;
+ CursorHelper &operator=(const HCURSOR cursor) noexcept {
+ CleanUp();
+ Init(cursor);
+ return *this;
+ }
+
+ bool MatchesSize(const int width, const int height) noexcept {
+ return bmp.bmWidth == width && bmp.bmHeight == height;
}
- }
- ICONINFO info;
- if (::GetIconInfo(cursor, &info)) {
- BITMAP bmp {};
- if (::GetObject(info.hbmMask, sizeof(bmp), &bmp)) {
- FlipBitmap(info.hbmMask, bmp.bmWidth, bmp.bmHeight);
+ HCURSOR CreateFlippedCursor() noexcept {
+ if (info.hbmMask)
+ FlipBitmap(info.hbmMask, bmp.bmWidth, bmp.bmHeight);
if (info.hbmColor)
FlipBitmap(info.hbmColor, bmp.bmWidth, bmp.bmHeight);
info.xHotspot = bmp.bmWidth - 1 - info.xHotspot;
- reverseArrowCursor = ::CreateIconIndirect(&info);
+ return ::CreateIconIndirect(&info);
+ }
+
+ private:
+ void Init(const HCURSOR &cursor) noexcept {
+ if (::GetIconInfo(cursor, &info)) {
+ ::GetObject(info.hbmMask, sizeof(bmp), &bmp);
+ PLATFORM_ASSERT(HasBitmap());
+ }
+ }
+
+ void CleanUp() noexcept {
+ if (info.hbmMask)
+ ::DeleteObject(info.hbmMask);
+ if (info.hbmColor)
+ ::DeleteObject(info.hbmColor);
+ info = {};
+ bmp = {};
+ }
+
+ static void FlipBitmap(const HBITMAP bitmap, const int width, const int height) noexcept {
+ HDC hdc = ::CreateCompatibleDC({});
+ if (hdc) {
+ HBITMAP prevBmp = SelectBitmap(hdc, bitmap);
+ ::StretchBlt(hdc, width - 1, 0, -width, height, hdc, 0, 0, width, height, SRCCOPY);
+ SelectBitmap(hdc, prevBmp);
+ ::DeleteDC(hdc);
+ }
+ }
+ };
+
+ HCURSOR reverseArrowCursor {};
+
+ const int width = SystemMetricsForDpi(SM_CXCURSOR, dpi);
+ const int height = SystemMetricsForDpi(SM_CYCURSOR, dpi);
+
+ DPI_AWARENESS_CONTEXT oldContext = nullptr;
+ if (fnAreDpiAwarenessContextsEqual && fnAreDpiAwarenessContextsEqual(fnGetThreadDpiAwarenessContext(), DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED)) {
+ oldContext = fnSetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
+ PLATFORM_ASSERT(oldContext != nullptr);
+ }
+
+ const HCURSOR cursor = static_cast<HCURSOR>(::LoadImage({}, IDC_ARROW, IMAGE_CURSOR, width, height, LR_SHARED));
+ if (cursor) {
+ CursorHelper cursorHelper(cursor);
+
+ if (cursorHelper.HasBitmap() && !cursorHelper.MatchesSize(width, height)) {
+ const HCURSOR copy = static_cast<HCURSOR>(::CopyImage(cursor, IMAGE_CURSOR, width, height, LR_COPYFROMRESOURCE | LR_COPYRETURNORG));
+ if (copy) {
+ cursorHelper = copy;
+ ::DestroyCursor(copy);
+ }
}
- ::DeleteObject(info.hbmMask);
- if (info.hbmColor)
- ::DeleteObject(info.hbmColor);
+ if (cursorHelper.HasBitmap()) {
+ reverseArrowCursor = cursorHelper.CreateFlippedCursor();
+ }
}
- if (created) {
- ::DestroyCursor(cursor);
+ if (oldContext) {
+ fnSetThreadDpiAwarenessContext(oldContext);
}
+
return reverseArrowCursor;
}