Alexandre Julliard : winex11: Retrieve the cursor info with GetIconInfo to create a color cursor.
Alexandre Julliard
julliard at winehq.org
Fri May 21 12:15:16 CDT 2010
Module: wine
Branch: master
Commit: 6264bc20bc8d5d812be9a46dee3b765efe8b02a9
URL: http://source.winehq.org/git/wine.git/?a=commit;h=6264bc20bc8d5d812be9a46dee3b765efe8b02a9
Author: Alexandre Julliard <julliard at winehq.org>
Date: Thu May 20 14:54:41 2010 +0200
winex11: Retrieve the cursor info with GetIconInfo to create a color cursor.
---
dlls/winex11.drv/mouse.c | 235 ++++++++++++++++------------------------------
1 files changed, 82 insertions(+), 153 deletions(-)
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c
index 9581945..54bc06b 100644
--- a/dlls/winex11.drv/mouse.c
+++ b/dlls/winex11.drv/mouse.c
@@ -514,165 +514,73 @@ static BOOL check_alpha_zero(CURSORICONINFO *ptr, unsigned char *xor_bits)
#ifdef SONAME_LIBXCURSOR
/***********************************************************************
- * create_cursor_image
- *
- * Create an XcursorImage from a CURSORICONINFO
- */
-static XcursorImage *create_cursor_image( CURSORICONINFO *ptr )
-{
- static const unsigned char convert_5to8[] =
- {
- 0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
- 0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
- 0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
- 0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
- };
- static const unsigned char convert_6to8[] =
- {
- 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
- 0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
- 0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
- 0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
- 0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
- 0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
- 0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
- 0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
- };
- int x;
- int y;
- int and_size;
- unsigned char *and_bits, *and_ptr, *xor_bits, *xor_ptr;
- int and_width_bytes, xor_width_bytes;
- XcursorPixel *pixel_ptr;
- XcursorImage *image;
- unsigned char tmp;
- BOOL alpha_zero;
-
- and_width_bytes = 2 * ((ptr->nWidth+15) / 16);
- xor_width_bytes = ptr->nWidthBytes;
-
- and_size = ptr->nHeight * and_width_bytes;
- and_ptr = and_bits = (unsigned char *)(ptr + 1);
-
- xor_ptr = xor_bits = and_ptr + and_size;
-
- image = pXcursorImageCreate( ptr->nWidth, ptr->nHeight );
- if (!image) return NULL;
-
- pixel_ptr = image->pixels;
-
- alpha_zero = check_alpha_zero(ptr, xor_bits);
-
- /* On windows, to calculate the color for a pixel, first an AND is done
- * with the background and the "and" bitmap, then an XOR with the "xor"
- * bitmap. This means that when the data in the "and" bitmap is 0, the
- * pixel will get the color as specified in the "xor" bitmap.
- * However, if the data in the "and" bitmap is 1, the result will be the
- * background XOR'ed with the value in the "xor" bitmap. In case the "xor"
- * data is completely black (0x000000) the pixel will become transparent,
- * in case it's white (0xffffff) the pixel will become the inverse of the
- * background color.
- *
- * Since we can't support inverting colors, we map the grayscale value of
- * the "xor" data to the alpha channel, and xor the color with either
- * black or white.
- */
- for (y = 0; y < ptr->nHeight; ++y)
- {
- and_ptr = and_bits + (y * and_width_bytes);
- xor_ptr = xor_bits + (y * xor_width_bytes);
-
- for (x = 0; x < ptr->nWidth; ++x)
- {
- /* Xcursor pixel data is in ARGB format, with A in the high byte */
- switch (ptr->bBitsPerPixel)
- {
- case 32:
- /* BGRA, 8 bits each */
- *pixel_ptr = *xor_ptr++;
- *pixel_ptr |= *xor_ptr++ << 8;
- *pixel_ptr |= *xor_ptr++ << 16;
- *pixel_ptr |= *xor_ptr++ << 24;
- break;
-
- case 24:
- /* BGR, 8 bits each */
- *pixel_ptr = *xor_ptr++;
- *pixel_ptr |= *xor_ptr++ << 8;
- *pixel_ptr |= *xor_ptr++ << 16;
- break;
-
- case 16:
- /* BGR, 5 red, 6 green, 5 blue */
- /* [gggbbbbb][rrrrrggg] -> [xxxxxxxx][rrrrrrrr][gggggggg][bbbbbbbb] */
- *pixel_ptr = convert_5to8[*xor_ptr & 0x1f];
- tmp = (*xor_ptr++ & 0xe0) >> 5;
- tmp |= (*xor_ptr & 0x07) << 3;
- *pixel_ptr |= convert_6to8[tmp] << 16;
- *pixel_ptr |= convert_5to8[*xor_ptr++ >> 3] << 24;
- break;
-
- case 1:
- if (*xor_ptr & (1 << (7 - (x & 7)))) *pixel_ptr = 0xffffff;
- else *pixel_ptr = 0;
- if ((x & 7) == 7) ++xor_ptr;
- break;
-
- default:
- FIXME("Currently no support for cursors with %d bits per pixel\n", ptr->bBitsPerPixel);
- return 0;
- }
-
- if (alpha_zero)
- {
- /* Alpha channel */
- if (~*and_ptr & (1 << (7 - (x & 7)))) *pixel_ptr |= 0xff << 24;
- else if (*pixel_ptr)
- {
- int alpha = (*pixel_ptr & 0xff) * 0.30f
- + ((*pixel_ptr & 0xff00) >> 8) * 0.55f
- + ((*pixel_ptr & 0xff0000) >> 16) * 0.15f;
- *pixel_ptr ^= ((x + y) % 2) ? 0xffffff : 0x000000;
- *pixel_ptr |= alpha << 24;
- }
- if ((x & 7) == 7) ++and_ptr;
- }
- ++pixel_ptr;
- }
- }
-
- return image;
-}
-
-
-/***********************************************************************
* create_xcursor_cursor
*
* Use Xcursor to create an X cursor from a Windows one.
*/
-static Cursor create_xcursor_cursor( Display *display, CURSORICONINFO *ptr )
+static Cursor create_xcursor_cursor( HDC hdc, ICONINFO *icon, int width, int height )
{
+ int x, y, i, has_alpha;
+ BITMAPINFO *info;
Cursor cursor;
XcursorImage *image;
+ XcursorPixel *ptr;
- image = create_cursor_image( ptr );
- if (!image) return 0;
+ if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) return 0;
- /* Make sure hotspot is valid */
- image->xhot = ptr->ptHotSpot.x;
- image->yhot = ptr->ptHotSpot.y;
- if (image->xhot >= image->width ||
- image->yhot >= image->height)
+ wine_tsx11_lock();
+ image = pXcursorImageCreate( width, height );
+ wine_tsx11_unlock();
+ if (!image)
{
- image->xhot = image->width / 2;
- image->yhot = image->height / 2;
+ HeapFree( GetProcessHeap(), 0, info );
+ return 0;
}
+ image->xhot = icon->xHotspot;
+ image->yhot = icon->yHotspot;
image->delay = 0;
- cursor = pXcursorImageLoadCursor( display, image );
- pXcursorImageDestroy( image );
+ info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ info->bmiHeader.biWidth = width;
+ info->bmiHeader.biHeight = -height;
+ info->bmiHeader.biPlanes = 1;
+ info->bmiHeader.biBitCount = 32;
+ info->bmiHeader.biCompression = BI_RGB;
+ info->bmiHeader.biSizeImage = width * height * 4;
+ info->bmiHeader.biXPelsPerMeter = 0;
+ info->bmiHeader.biYPelsPerMeter = 0;
+ info->bmiHeader.biClrUsed = 0;
+ info->bmiHeader.biClrImportant = 0;
+ GetDIBits( hdc, icon->hbmColor, 0, height, image->pixels, info, DIB_RGB_COLORS );
+
+ for (i = 0, ptr = image->pixels; i < width * height; i++, ptr++)
+ if ((has_alpha = (*ptr & 0xff000000) != 0)) break;
+
+ if (!has_alpha)
+ {
+ unsigned char *mask_bits;
+ unsigned int width_bytes = (width + 31) / 32 * 4;
+
+ /* generate alpha channel from the mask */
+ info->bmiHeader.biBitCount = 1;
+ info->bmiHeader.biSizeImage = width_bytes * height;
+ if ((mask_bits = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage )))
+ {
+ GetDIBits( hdc, icon->hbmMask, 0, height, mask_bits, info, DIB_RGB_COLORS );
+ for (y = 0, ptr = image->pixels; y < height; y++)
+ for (x = 0; x < width; x++, ptr++)
+ if (!((mask_bits[y * width_bytes + x / 8] << (x % 8)) & 0x80))
+ *ptr |= 0xff000000;
+ HeapFree( GetProcessHeap(), 0, mask_bits );
+ }
+ }
+ HeapFree( GetProcessHeap(), 0, info );
+ wine_tsx11_lock();
+ cursor = pXcursorImageLoadCursor( gdi_display, image );
+ pXcursorImageDestroy( image );
+ wine_tsx11_unlock();
return cursor;
}
@@ -994,23 +902,44 @@ static Cursor create_xlib_cursor( Display *display, CURSORICONINFO *ptr )
*/
static Cursor create_cursor( HANDLE handle, CURSORICONINFO *ptr )
{
- Cursor cursor;
+ Cursor cursor = 0;
+ HDC hdc;
+ ICONINFO info;
+ BITMAP bm;
if (!handle) return get_empty_cursor();
+ if (!(hdc = CreateCompatibleDC( 0 ))) return 0;
+ if (!GetIconInfo( handle, &info ))
+ {
+ DeleteDC( hdc );
+ return 0;
+ }
+
+ GetObjectW( info.hbmMask, sizeof(bm), &bm );
+ if (!info.hbmColor) bm.bmHeight /= 2;
+
+ /* make sure hotspot is valid */
+ if (info.xHotspot >= bm.bmWidth || info.yHotspot >= bm.bmHeight)
+ {
+ info.xHotspot = bm.bmWidth / 2;
+ info.yHotspot = bm.bmHeight / 2;
+ }
+
#ifdef SONAME_LIBXCURSOR
- if (pXcursorImageLoadCursor)
+ if (pXcursorImageLoadCursor && info.hbmColor)
+ cursor = create_xcursor_cursor( hdc, &info, bm.bmWidth, bm.bmHeight );
+#endif
+
+ if (!cursor)
{
wine_tsx11_lock();
- cursor = create_xcursor_cursor( gdi_display, ptr );
+ cursor = create_xlib_cursor( gdi_display, ptr );
wine_tsx11_unlock();
- if (cursor) return cursor;
}
-#endif
-
- wine_tsx11_lock();
- cursor = create_xlib_cursor( gdi_display, ptr );
- wine_tsx11_unlock();
+ if (info.hbmColor) DeleteObject( info.hbmColor );
+ DeleteObject( info.hbmMask );
+ DeleteDC( hdc );
return cursor;
}
More information about the wine-cvs
mailing list