33#ifdef __WINDOWS__
44
55#include < Tempest/Event>
6+ #include < Tempest/Pixmap>
67#include < Tempest/Except>
78#include < Tempest/TextCodec>
89#include < Tempest/Window>
@@ -328,7 +329,13 @@ void WindowsApi::implSetCursorPosition(SystemApi::Window *w, int x, int y) {
328329 }
329330 }
330331
332+ static HCURSOR customCursor = nullptr ;
333+
331334static void SetCursor (CursorShape show) {
335+ if (show==CursorShape::Custom && customCursor!=nullptr ) {
336+ SetCursor (customCursor);
337+ return ;
338+ }
332339 LPSTR idc = IDC_ARROW ;
333340 switch (show) {
334341 case Tempest::CursorShape::Arrow:
@@ -355,6 +362,9 @@ static void SetCursor(CursorShape show) {
355362 case Tempest::CursorShape::SizeAll:
356363 idc = IDC_SIZEALL ;
357364 break ;
365+ case Tempest::CursorShape::Custom:
366+ idc = IDC_ARROW ;
367+ break ;
358368 }
359369 HCURSOR hcur = idc==nullptr ? nullptr : LoadCursorA (nullptr , idc);
360370 SetCursor (hcur);
@@ -364,6 +374,60 @@ void WindowsApi::implShowCursor(SystemApi::Window*, CursorShape show) {
364374 SetCursor (show);
365375 }
366376
377+ void WindowsApi::implSetCustomCursor (const Pixmap& image, int hotX, int hotY) {
378+ if (customCursor!=nullptr ) {
379+ DestroyCursor (customCursor);
380+ customCursor = nullptr ;
381+ }
382+ if (image.isEmpty () || image.format ()!=TextureFormat::RGBA8 )
383+ return ;
384+
385+ const int w = int (image.w ());
386+ const int h = int (image.h ());
387+
388+ BITMAPV5HEADER bi = {};
389+ bi.bV5Size = sizeof (bi);
390+ bi.bV5Width = w;
391+ bi.bV5Height = -h; // top-down rows, as in Pixmap
392+ bi.bV5Planes = 1 ;
393+ bi.bV5BitCount = 32 ;
394+ bi.bV5Compression = BI_BITFIELDS ;
395+ bi.bV5RedMask = 0x00FF0000 ;
396+ bi.bV5GreenMask = 0x0000FF00 ;
397+ bi.bV5BlueMask = 0x000000FF ;
398+ bi.bV5AlphaMask = 0xFF000000 ;
399+
400+ void * bits = nullptr ;
401+ HDC dc = GetDC (nullptr );
402+ HBITMAP color = CreateDIBSection (dc, reinterpret_cast <BITMAPINFO *>(&bi), DIB_RGB_COLORS , &bits, nullptr , 0 );
403+ ReleaseDC (nullptr , dc);
404+ if (color==nullptr )
405+ return ;
406+
407+ auto src = reinterpret_cast <const uint8_t *>(image.data ());
408+ auto dst = reinterpret_cast <uint8_t *>(bits);
409+ for (size_t i=0 ; i<size_t (w*h); ++i) {
410+ dst[i*4 +0 ] = src[i*4 +2 ];
411+ dst[i*4 +1 ] = src[i*4 +1 ];
412+ dst[i*4 +2 ] = src[i*4 +0 ];
413+ dst[i*4 +3 ] = src[i*4 +3 ];
414+ }
415+
416+ // A 32-bit color bitmap with alpha takes precedence over the mask, which only needs to exist.
417+ HBITMAP mask = CreateBitmap (w, h, 1 , 1 , nullptr );
418+
419+ ICONINFO info = {};
420+ info.fIcon = FALSE ;
421+ info.xHotspot = DWORD (hotX);
422+ info.yHotspot = DWORD (hotY);
423+ info.hbmMask = mask;
424+ info.hbmColor = color;
425+ customCursor = CreateIconIndirect (&info);
426+
427+ DeleteObject (color);
428+ DeleteObject (mask);
429+ }
430+
367431long long WindowsApi::windowProc (void *_hWnd, uint32_t msg, const unsigned long long wParam, const long long lParam) {
368432 HWND hWnd = HWND (_hWnd);
369433
0 commit comments