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