Skip to content

Commit

Permalink
Refactoring reverse arrow cursor loading, improve CopyImage() quali…
Browse files Browse the repository at this point in the history
  • Loading branch information
zufuliu committed Apr 19, 2024
1 parent 8950869 commit 8671ed5
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 39 deletions.
55 changes: 49 additions & 6 deletions scintilla/win32/PlatWin.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -2889,11 +2889,22 @@ void FlipBitmap(HBITMAP bitmap, int width, int height) noexcept {

}

HCURSOR LoadReverseArrowCursor(UINT dpi, int cursorBaseSize) noexcept {
HCURSOR reverseArrowCursor {};

HCURSOR LoadReverseArrowCursor(HCURSOR cursor, UINT dpi) noexcept {
bool created = false;
HCURSOR cursor = ::LoadCursor({}, IDC_ARROW);
// https://learn.microsoft.com/en-us/answers/questions/815036/windows-cursor-size
constexpr DWORD defaultCursorBaseSize = 32;
DWORD cursorBaseSize = 0;
HKEY hKey {};
LSTATUS status = ::RegOpenKeyExW(HKEY_CURRENT_USER, L"Control Panel\\Cursors", 0, KEY_READ, &hKey);
if (status == ERROR_SUCCESS) {
DWORD baseSize = 0;
DWORD type = REG_DWORD;
DWORD size = sizeof(DWORD);
status = ::RegQueryValueExW(hKey, L"CursorBaseSize", nullptr, &type, reinterpret_cast<LPBYTE>(&baseSize), &size);
if (status == ERROR_SUCCESS && type == REG_DWORD) {
cursorBaseSize = baseSize;
}
}

if (dpi != g_uSystemDPI || cursorBaseSize > defaultCursorBaseSize) {
int width;
Expand All @@ -2905,14 +2916,45 @@ HCURSOR LoadReverseArrowCursor(UINT dpi, int cursorBaseSize) noexcept {
width = SystemMetricsForDpi(SM_CXCURSOR, dpi);
height = SystemMetricsForDpi(SM_CYCURSOR, dpi);
}
if (hKey) {
// workaround CopyImage() for system cursor
// https://learn.microsoft.com/en-us/answers/questions/1315176/how-to-copy-system-cursors-properly
WCHAR cursorPath[MAX_PATH]{};
DWORD size = sizeof(cursorPath);
DWORD type = REG_SZ;
status = ::RegQueryValueExW(hKey, L"Arrow", nullptr, &type, reinterpret_cast<LPBYTE>(cursorPath), &size);
if (status == ERROR_SUCCESS && (type == REG_SZ || type == REG_EXPAND_SZ)) {
LPCWSTR path = cursorPath;
WCHAR expansion[MAX_PATH];
if (type == REG_EXPAND_SZ) {
size = ::ExpandEnvironmentStringsW(cursorPath, expansion, MAX_PATH);
if (size > 0 && size <= MAX_PATH) {
path = expansion;
}
}
HCURSOR load = static_cast<HCURSOR>(::LoadImage({}, path, IMAGE_CURSOR, width, height, LR_LOADFROMFILE));
if (load) {
created = true;
cursor = load;
}
}
}
HCURSOR copy = static_cast<HCURSOR>(::CopyImage(cursor, IMAGE_CURSOR, width, height, LR_COPYFROMRESOURCE | LR_COPYRETURNORG));
if (copy) {
created = copy != cursor;
if (copy && copy != cursor) {
if (created) {
::DestroyCursor(cursor);
}
created = true;
cursor = copy;
}
}

if (hKey) {
::RegCloseKey(hKey);
}

ICONINFO info;
HCURSOR reverseArrowCursor {};
if (::GetIconInfo(cursor, &info)) {
BITMAP bmp{};
if (::GetObject(info.hbmMask, sizeof(bmp), &bmp)) {
Expand Down Expand Up @@ -2958,6 +3000,7 @@ void Window::SetCursor(Cursor curs) noexcept {
case Cursor::reverseArrow:
case Cursor::arrow:
case Cursor::invalid: // Should not occur, but just in case.
default:
::SetCursor(::LoadCursor({}, IDC_ARROW));
break;
}
Expand Down
3 changes: 1 addition & 2 deletions scintilla/win32/PlatWin.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,7 @@ inline UINT DpiForWindow(WindowID wid) noexcept {
return GetWindowDPI(HwndFromWindowID(wid));
}

constexpr int defaultCursorBaseSize = 32;
HCURSOR LoadReverseArrowCursor(UINT dpi, int cursorBaseSize) noexcept;
HCURSOR LoadReverseArrowCursor(HCURSOR cursor, UINT dpi) noexcept;

class MouseWheelDelta {
int wheelDelta = 0;
Expand Down
47 changes: 16 additions & 31 deletions scintilla/win32/ScintillaWin.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -357,8 +357,7 @@ class GlobalMemory;

class ReverseArrowCursor {
HCURSOR cursor {};
UINT dpi = USER_DEFAULT_SCREEN_DPI;
UINT cursorBaseSize = defaultCursorBaseSize;
bool valid = false;

public:
ReverseArrowCursor() noexcept = default;
Expand All @@ -373,18 +372,22 @@ class ReverseArrowCursor {
}
}

HCURSOR Load(UINT dpi_, UINT cursorBaseSize_) noexcept {
void Invalidate() noexcept {
valid = false;
}

HCURSOR Load(UINT dpi) noexcept {
if (cursor) {
if (dpi == dpi_ && cursorBaseSize == cursorBaseSize_) {
if (valid) {
return cursor;
}
::DestroyCursor(cursor);
}

dpi = dpi_;
cursorBaseSize = cursorBaseSize_;
cursor = LoadReverseArrowCursor(dpi_, cursorBaseSize_);
return cursor ? cursor : ::LoadCursor({}, IDC_ARROW);
valid = true;
HCURSOR arrow = ::LoadCursor({}, IDC_ARROW);
cursor = LoadReverseArrowCursor(arrow, dpi);
return cursor ? cursor : arrow;
}
};

Expand Down Expand Up @@ -421,7 +424,6 @@ class ScintillaWin final :
MouseWheelDelta horizontalWheelDelta;

UINT dpi = USER_DEFAULT_SCREEN_DPI;
UINT cursorBaseSize = defaultCursorBaseSize;
ReverseArrowCursor reverseArrowCursor;

PRectangle rectangleClient;
Expand Down Expand Up @@ -849,7 +851,7 @@ void ScintillaWin::DisplayCursor(Window::Cursor c) noexcept {
c = static_cast<Window::Cursor>(cursorMode);
}
if (c == Window::Cursor::reverseArrow) {
::SetCursor(reverseArrowCursor.Load(dpi, cursorBaseSize));
::SetCursor(reverseArrowCursor.Load(dpi));
} else {
wMain.SetCursor(c);
}
Expand Down Expand Up @@ -2333,6 +2335,7 @@ sptr_t ScintillaWin::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) {

case WM_DPICHANGED:
dpi = HIWORD(wParam);
reverseArrowCursor.Invalidate();
vs.fontsValid = false;
InvalidateStyleRedraw();
break;
Expand All @@ -2341,6 +2344,7 @@ sptr_t ScintillaWin::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) {
const UINT dpiNow = GetWindowDPI(MainHWND());
if (dpi != dpiNow) {
dpi = dpiNow;
reverseArrowCursor.Invalidate();
vs.fontsValid = false;
InvalidateStyleRedraw();
}
Expand Down Expand Up @@ -3465,34 +3469,15 @@ LRESULT ScintillaWin::ImeOnDocumentFeed(LPARAM lParam) const {
}

void ScintillaWin::GetMouseParameters() noexcept {
// mouse pointer size and colour may changed
reverseArrowCursor.Invalidate();
::SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &typingWithoutCursor, 0);
// This retrieves the number of lines per scroll as configured in the Mouse Properties sheet in Control Panel
::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &linesPerScroll, 0);
if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &charsPerScroll, 0)) {
// no horizontal scrolling configuration on Windows XP
charsPerScroll = (linesPerScroll == WHEEL_PAGESCROLL) ? 3 : linesPerScroll;
}

// https://learn.microsoft.com/en-us/answers/questions/815036/windows-cursor-size
#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
DWORD type = REG_DWORD;
DWORD size = sizeof(DWORD);
[[maybe_unused]] const LSTATUS status = RegGetValue(HKEY_CURRENT_USER, L"Control Panel\\Cursors", L"CursorBaseSize", RRF_RT_REG_DWORD, &type, &cursorBaseSize, &size);

#else
HKEY hKey;
LSTATUS status = RegOpenKeyEx(HKEY_CURRENT_USER, L"Control Panel\\Cursors", 0, KEY_READ, &hKey);
if (status == ERROR_SUCCESS) {
DWORD baseSize = 0;
DWORD type = REG_DWORD;
DWORD size = sizeof(DWORD);
status = RegQueryValueEx(hKey, L"CursorBaseSize", nullptr, &type, (LPBYTE)(&baseSize), &size);
if (status == ERROR_SUCCESS && type == REG_DWORD) {
cursorBaseSize = baseSize;
}
RegCloseKey(hKey);
}
#endif
}

void ScintillaWin::CopyToGlobal(GlobalMemory &gmUnicode, const SelectionText &selectedText, CopyEncoding encoding) const {
Expand Down

0 comments on commit 8671ed5

Please sign in to comment.