aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMarkus Nißl <unknown>2023-06-22 22:31:07 +1000
committerMarkus Nißl <unknown>2023-06-22 22:31:07 +1000
commit0ffbc41582dd7fe85093a7ea3f21459890eab03d (patch)
tree0f235206dee37a7a063d3ae3c70c5cddb2b916c3
parent5ad83ff87df54c085be87cde61215b3ee32a2e1a (diff)
downloadscintilla-mirror-0ffbc41582dd7fe85093a7ea3f21459890eab03d.tar.gz
Bug [#2382]. Fix reverse arrow cursor when scaled.
-rw-r--r--doc/ScintillaHistory.html4
-rw-r--r--win32/PlatWin.cxx128
-rw-r--r--win32/PlatWin.h2
-rw-r--r--win32/ScintillaWin.cxx16
4 files changed, 104 insertions, 46 deletions
diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html
index f60eb3933..503df317e 100644
--- a/doc/ScintillaHistory.html
+++ b/doc/ScintillaHistory.html
@@ -594,6 +594,10 @@
<a href="https://sourceforge.net/p/scintilla/feature-requests/1486/">Feature #1486</a>.
</li>
<li>
+ On Win32 fix reverse arrow cursor when scaled.
+ <a href="https://sourceforge.net/p/scintilla/bugs/2382/">Bug #2382</a>.
+ </li>
+ <li>
On Win32 hide cursor when typing if that system preference has been chosen.
<a href="https://sourceforge.net/p/scintilla/bugs/2333/">Bug #2333</a>.
</li>
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;
}
diff --git a/win32/PlatWin.h b/win32/PlatWin.h
index 8ce798cf1..f010923f2 100644
--- a/win32/PlatWin.h
+++ b/win32/PlatWin.h
@@ -46,7 +46,7 @@ void SetWindowPointer(HWND hWnd, void *ptr) noexcept;
HMONITOR MonitorFromWindowHandleScaling(HWND hWnd) noexcept;
UINT DpiForWindow(WindowID wid) noexcept;
-int GetDeviceScaleFactorWhenGdiScalingActive(HWND hWnd) noexcept;
+float GetDeviceScaleFactorWhenGdiScalingActive(HWND hWnd) noexcept;
int SystemMetricsForDpi(int nIndex, UINT dpi) noexcept;
diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx
index 95bb79825..964b3ee3c 100644
--- a/win32/ScintillaWin.cxx
+++ b/win32/ScintillaWin.cxx
@@ -364,7 +364,10 @@ class ScintillaWin :
static ATOM scintillaClassAtom;
static ATOM callClassAtom;
- int deviceScaleFactor = 1;
+ float deviceScaleFactor = 1.f;
+ int GetFirstIntegralMultipleDeviceScaleFactor() const noexcept {
+ return static_cast<int>(std::ceil(deviceScaleFactor));
+ }
#if defined(USE_D2D)
ID2D1RenderTarget *pRenderTarget;
@@ -723,14 +726,15 @@ void ScintillaWin::EnsureRenderTarget(HDC hdc) {
}
} else {
- drtp.dpiX = 96.f * deviceScaleFactor;
- drtp.dpiY = 96.f * deviceScaleFactor;
+ const int integralDeviceScaleFactor = GetFirstIntegralMultipleDeviceScaleFactor();
+ drtp.dpiX = 96.f * integralDeviceScaleFactor;
+ drtp.dpiY = 96.f * integralDeviceScaleFactor;
drtp.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN,
D2D1_ALPHA_MODE_UNKNOWN);
D2D1_HWND_RENDER_TARGET_PROPERTIES dhrtp {};
dhrtp.hwnd = hw;
- dhrtp.pixelSize = ::GetSizeUFromRect(rc, deviceScaleFactor);
+ dhrtp.pixelSize = ::GetSizeUFromRect(rc, integralDeviceScaleFactor);
dhrtp.presentOptions = (technology == Technology::DirectWriteRetain) ?
D2D1_PRESENT_OPTIONS_RETAIN_CONTENTS : D2D1_PRESENT_OPTIONS_NONE;
@@ -775,7 +779,7 @@ void ScintillaWin::DisplayCursor(Window::Cursor c) {
c = static_cast<Window::Cursor>(cursorMode);
}
if (c == Window::Cursor::reverseArrow) {
- ::SetCursor(reverseArrowCursor.Load(dpi));
+ ::SetCursor(reverseArrowCursor.Load(static_cast<UINT>(dpi * deviceScaleFactor)));
} else {
wMain.SetCursor(c);
}
@@ -3649,7 +3653,7 @@ LRESULT PASCAL ScintillaWin::CTWndProc(
surfaceWindow->Init(ps.hdc, hWnd);
} else {
#if defined(USE_D2D)
- const int scaleFactor = sciThis->deviceScaleFactor;
+ const int scaleFactor = sciThis->GetFirstIntegralMultipleDeviceScaleFactor();
// Create a Direct2D render target.
D2D1_HWND_RENDER_TARGET_PROPERTIES dhrtp {};