Skip to content

Commit

Permalink
Fix creation of cursor mask (fix aseprite/aseprite#3989)
Browse files Browse the repository at this point in the history
  • Loading branch information
martincapello committed Aug 16, 2023
1 parent c182b50 commit 77bf6d9
Showing 1 changed file with 14 additions and 16 deletions.
30 changes: 14 additions & 16 deletions os/win/system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,20 @@ class WinCursorCache {

// Create an empty mask bitmap.
HBITMAP hmonobmp() {
if (!m_hmonobmp)
m_hmonobmp.reset(CreateBitmap(m_size.w, m_size.h, 1, 1, nullptr));
if (!m_hmonobmp) {
// We must fill the mask bitmap with ones to avoid issues when a cursor is fully
// transparent. Before this change we were returning a "no cursor" from makeCursor
// when the cursor was fully transparent to avoid showing a black bitmap as the
// cursor. But then the following issue was found:
// https://github.com/aseprite/aseprite/issues/3989 (which is about the mouse
// cursor leaving a trail of cursors after it was switched to a fully transparent
// cursor bitmap.
// By filling the mask with ones we fix both, the issue and the black cursor.
int maskSize = (((m_size.w + 15) >> 4) << 1) * m_size.h;
auto maskBits = std::make_unique<BYTE[]>(maskSize);
std::memset(maskBits.get(), 0xFF, maskSize);
m_hmonobmp.reset(CreateBitmap(m_size.w, m_size.h, 1, 1, maskBits.get()));
}
return m_hmonobmp.get();
}

Expand Down Expand Up @@ -195,16 +207,12 @@ CursorRef SystemWin::makeCursor(const os::Surface* surface,
return nullptr;

uint32_t* bits = g_cursor_cache.bits();
bool completelyTransparent = true;
for (int y=0; y<sz.h; ++y) {
const uint32_t* ptr = (const uint32_t*)surface->getData(0, (sz.h-1-y)/scale);
for (int x=0, u=0; x<sz.w; ++x, ++bits) {
uint32_t c = *ptr;
uint32_t a = ((c & format.alphaMask) >> format.alphaShift);

if (a)
completelyTransparent = false;

*bits = (a << 24) |
(((c & format.redMask ) >> format.redShift ) << 16) |
(((c & format.greenMask) >> format.greenShift) << 8) |
Expand All @@ -216,16 +224,6 @@ CursorRef SystemWin::makeCursor(const os::Surface* surface,
}
}

// It looks like if we set a cursor that is completely transparent
// (all pixels with alpha=0), Windows will create a black opaque
// rectangle cursor. Which is not what we are looking for. So in
// this specific case we put a "no cursor" which has the expected
// result.
if (completelyTransparent) {
// Return a valid Cursor instance but with a nullptr handle.
return make_ref<CursorWin>(nullptr);
}

ICONINFO ii;
ii.fIcon = FALSE;
ii.xHotspot = scale*focus.x + scale/2;
Expand Down

0 comments on commit 77bf6d9

Please sign in to comment.