468
474
#ifdef SONAME_LIBXCURSOR
470
476
/***********************************************************************
471
* create_xcursor_cursor
477
* create_xcursor_frame
473
* Use Xcursor to create an X cursor from a Windows one.
479
* Use Xcursor to create a frame of an X cursor from a Windows one.
475
static Cursor create_xcursor_cursor( HDC hdc, ICONINFO *icon, int width, int height )
481
static XcursorImage *create_xcursor_frame( HDC hdc, ICONINFO *iinfo, HANDLE icon,
482
HBITMAP hbmColor, unsigned char *color_bits, int color_size,
483
HBITMAP hbmMask, unsigned char *mask_bits, int mask_size,
484
int width, int height, int istep )
486
XcursorImage *image, *ret = NULL;
477
487
int x, y, i, has_alpha;
481
488
XcursorPixel *ptr;
483
if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) return 0;
485
490
wine_tsx11_lock();
486
491
image = pXcursorImageCreate( width, height );
487
492
wine_tsx11_unlock();
490
HeapFree( GetProcessHeap(), 0, info );
494
image->xhot = icon->xHotspot;
495
image->yhot = icon->yHotspot;
498
info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
499
info->bmiHeader.biWidth = width;
500
info->bmiHeader.biHeight = -height;
501
info->bmiHeader.biPlanes = 1;
502
info->bmiHeader.biBitCount = 32;
503
info->bmiHeader.biCompression = BI_RGB;
504
info->bmiHeader.biSizeImage = width * height * 4;
505
info->bmiHeader.biXPelsPerMeter = 0;
506
info->bmiHeader.biYPelsPerMeter = 0;
507
info->bmiHeader.biClrUsed = 0;
508
info->bmiHeader.biClrImportant = 0;
509
GetDIBits( hdc, icon->hbmColor, 0, height, image->pixels, info, DIB_RGB_COLORS );
495
ERR("X11 failed to produce a cursor frame!\n");
499
image->xhot = iinfo->xHotspot;
500
image->yhot = iinfo->yHotspot;
501
image->delay = 100; /* TODO: find a way to get the proper delay */
503
/* draw the cursor frame to a temporary buffer then copy it into the XcursorImage */
504
memset( color_bits, 0x00, color_size );
505
SelectObject( hdc, hbmColor );
506
if (!DrawIconEx( hdc, 0, 0, icon, width, height, istep, NULL, DI_NORMAL ))
508
TRACE("Could not draw frame %d (walk past end of frames).\n", istep);
511
memcpy( image->pixels, color_bits, color_size );
513
/* check if the cursor frame was drawn with an alpha channel */
511
514
for (i = 0, ptr = image->pixels; i < width * height; i++, ptr++)
512
515
if ((has_alpha = (*ptr & 0xff000000) != 0)) break;
517
/* if no alpha channel was drawn then generate it from the mask */
516
unsigned char *mask_bits;
517
520
unsigned int width_bytes = (width + 31) / 32 * 4;
519
/* generate alpha channel from the mask */
520
info->bmiHeader.biBitCount = 1;
521
info->bmiHeader.biSizeImage = width_bytes * height;
522
if ((mask_bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage )))
522
/* draw the cursor mask to a temporary buffer */
523
memset( mask_bits, 0xFF, mask_size );
524
SelectObject( hdc, hbmMask );
525
if (!DrawIconEx( hdc, 0, 0, icon, width, height, istep, NULL, DI_MASK ))
524
GetDIBits( hdc, icon->hbmMask, 0, height, mask_bits, info, DIB_RGB_COLORS );
525
for (y = 0, ptr = image->pixels; y < height; y++)
526
for (x = 0; x < width; x++, ptr++)
527
if (!((mask_bits[y * width_bytes + x / 8] << (x % 8)) & 0x80))
529
HeapFree( GetProcessHeap(), 0, mask_bits );
527
ERR("Failed to draw frame mask %d.\n", istep);
532
HeapFree( GetProcessHeap(), 0, info );
530
/* use the buffer to directly modify the XcursorImage alpha channel */
531
for (y = 0, ptr = image->pixels; y < height; y++)
532
for (x = 0; x < width; x++, ptr++)
533
if (!((mask_bits[y * width_bytes + x / 8] << (x % 8)) & 0x80))
539
if (ret == NULL) pXcursorImageDestroy( image );
543
/***********************************************************************
544
* create_xcursor_cursor
546
* Use Xcursor to create an X cursor from a Windows one.
548
static Cursor create_xcursor_cursor( HDC hdc, ICONINFO *iinfo, HANDLE icon, int width, int height )
550
unsigned char *color_bits, *mask_bits;
551
HBITMAP hbmColor = 0, hbmMask = 0;
552
XcursorImage **imgs, *image;
553
int color_size, mask_size;
554
BITMAPINFO *info = NULL;
555
XcursorImages *images;
559
if (!(imgs = HeapAlloc( GetProcessHeap(), 0, sizeof(XcursorImage*) ))) return 0;
561
/* Allocate all of the resources necessary to obtain a cursor frame */
562
if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto cleanup;
563
info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
564
info->bmiHeader.biWidth = width;
565
info->bmiHeader.biHeight = -height;
566
info->bmiHeader.biPlanes = 1;
567
info->bmiHeader.biCompression = BI_RGB;
568
info->bmiHeader.biXPelsPerMeter = 0;
569
info->bmiHeader.biYPelsPerMeter = 0;
570
info->bmiHeader.biClrUsed = 0;
571
info->bmiHeader.biClrImportant = 0;
572
info->bmiHeader.biBitCount = 32;
573
color_size = width * height * 4;
574
info->bmiHeader.biSizeImage = color_size;
575
hbmColor = CreateDIBSection( hdc, info, DIB_RGB_COLORS, (VOID **) &color_bits, NULL, 0);
578
ERR("Failed to create DIB section for cursor color data!\n");
581
info->bmiHeader.biBitCount = 1;
582
mask_size = ((width + 31) / 32 * 4) * height; /* width_bytes * height */
583
info->bmiHeader.biSizeImage = mask_size;
584
hbmMask = CreateDIBSection( hdc, info, DIB_RGB_COLORS, (VOID **) &mask_bits, NULL, 0);
587
ERR("Failed to create DIB section for cursor mask data!\n");
591
/* Create an XcursorImage for each frame of the cursor */
594
XcursorImage **imgstmp;
596
image = create_xcursor_frame( hdc, iinfo, icon,
597
hbmColor, color_bits, color_size,
598
hbmMask, mask_bits, mask_size,
599
width, height, nFrames );
600
if (!image) break; /* no more drawable frames */
602
imgs[nFrames++] = image;
603
if (!(imgstmp = HeapReAlloc( GetProcessHeap(), 0, imgs, (nFrames+1)*sizeof(XcursorImage*) ))) goto cleanup;
607
/* Build an X cursor out of all of the frames */
608
if (!(images = pXcursorImagesCreate( nFrames ))) goto cleanup;
609
for (images->nimage = 0; images->nimage < nFrames; images->nimage++)
610
images->images[images->nimage] = imgs[images->nimage];
534
611
wine_tsx11_lock();
535
cursor = pXcursorImageLoadCursor( gdi_display, image );
536
pXcursorImageDestroy( image );
612
cursor = pXcursorImagesLoadCursor( gdi_display, images );
537
613
wine_tsx11_unlock();
614
pXcursorImagesDestroy( images ); /* Note: this frees each individual frame (calls XcursorImageDestroy) */
615
HeapFree( GetProcessHeap(), 0, imgs );
621
/* Failed to produce a cursor, free previously allocated frames */
622
for (nFrames--; nFrames >= 0; nFrames--)
623
pXcursorImageDestroy( imgs[nFrames] );
624
HeapFree( GetProcessHeap(), 0, imgs );
626
/* Cleanup all of the resources used to obtain the frame data */
627
if (hbmColor) DeleteObject( hbmColor );
628
if (hbmMask) DeleteObject( hbmMask );
629
HeapFree( GetProcessHeap(), 0, info );