[2/6] X11DRV: Support loading of multicolor and animated cursors

H. Verbeet hverbeet at gmail.com
Tue Apr 18 16:50:00 CDT 2006


This patch adds support for loading multicolor and animated cursors to
x11drv, if Xcursor is present.

Changelog:
  - Support loading of multicolor and animated cursors.
-------------- next part --------------
diff --git a/configure.ac b/configure.ac
index c61e554..7ada95e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -319,6 +319,7 @@ then
     AC_CHECK_HEADERS([X11/Xlib.h \
                       X11/XKBlib.h \
                       X11/Xutil.h \
+                      X11/Xcursor/Xcursor.h \
                       X11/extensions/shape.h \
                       X11/extensions/XInput.h \
                       X11/extensions/XShm.h \
@@ -341,6 +342,17 @@ then
               $X_LIBS -lXext -lX11 $X_EXTRA_LIBS)
         fi
 
+        dnl *** Check for X cursor extension
+        if test "$ac_cv_header_X11_Xcursor_Xcursor_h" = "yes"
+        then
+            AC_CHECK_LIB(Xcursor, XcursorImagesLoadCursor,
+            [AC_DEFINE(HAVE_LIBXCURSOR, 1,
+                [Define if you have the X cursor extension])
+                X_PRE_LIBS="$X_PRE_LIBS -lXcursor"
+            ],,
+            $X_LIBS -lXext -lX11 $X_EXTRA_LIBS)
+        fi
+
         dnl *** Check for X Shm extension
         if test "$ac_cv_header_X11_extensions_XShm_h" = "yes"
         then
diff --git a/dlls/x11drv/mouse.c b/dlls/x11drv/mouse.c
index e9ae7f8..8a9507c 100644
--- a/dlls/x11drv/mouse.c
+++ b/dlls/x11drv/mouse.c
@@ -2,6 +2,7 @@
  * X11 mouse driver
  *
  * Copyright 1998 Ulrich Weigand
+ * Copyright (C) 2006 Henri Verbeet
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -24,6 +25,9 @@
 #ifdef HAVE_LIBXXF86DGA2
 #include <X11/extensions/xf86dga.h>
 #endif
+#ifdef HAVE_LIBXCURSOR
+#include <X11/Xcursor/Xcursor.h>
+#endif
 #include <stdarg.h>
 
 #define NONAMELESSUNION
@@ -359,6 +363,115 @@ void X11DRV_send_mouse_input( HWND hwnd,
  *
  * Create an X cursor from a Windows one.
  */
+#ifdef HAVE_LIBXCURSOR
+static Cursor create_cursor(Display *display, CURSORANIINFO *ani_info)
+{
+    Cursor cursor;
+    XcursorImages *images = 0;
+    int image_count = 0;
+    CURSORICONINFO *ptr = (CURSORICONINFO *)(ani_info + 1);
+
+    if (!ani_info) /* Create an empty cursor */
+    {
+        XcursorImage *image = XcursorImageCreate(1, 1);
+        image->xhot = 0;
+        image->yhot = 0;
+        *(image->pixels) = 0;
+        cursor = XcursorImageLoadCursor(display, image);
+        XcursorImageDestroy(image);
+
+        return cursor;
+    }
+
+    image_count = ani_info->num_frames;
+    images = XcursorImagesCreate(image_count);
+
+    while(image_count--)
+    {
+        int mask_size = (ptr->nWidth >> 3) * ptr->nHeight;  /* Mask data is 1 bit per pixel */
+        int img_size = (ptr->nWidth * ptr->bBitsPerPixel * ptr->nHeight) >> 3;
+        unsigned char *mask_ptr = (unsigned char *)(ptr + 1);
+        unsigned char *img_ptr = mask_ptr + mask_size;
+        XcursorImage *image = XcursorImageCreate(ptr->nWidth, ptr->nHeight);
+        XcursorPixel *pixel_ptr = 0;
+        XcursorPixel *pixel_end = 0;
+        int pixel_idx = 0;
+        POINT hotspot;
+
+        /* Make sure hotspot is valid */
+        hotspot.x = ptr->ptHotSpot.x;
+        hotspot.y = ptr->ptHotSpot.y;
+        if (hotspot.x < 0 || hotspot.x >= ptr->nWidth ||
+            hotspot.y < 0 || hotspot.y >= ptr->nHeight)
+        {
+            hotspot.x = ptr->nWidth / 2;
+            hotspot.y = ptr->nHeight / 2;
+        }
+
+        image->xhot = hotspot.x;
+        image->yhot = hotspot.y;
+        image->delay = ani_info->delay;
+
+        pixel_ptr = image->pixels;
+        pixel_end = pixel_ptr + (image->width * image->height);
+
+        /* On windows, to calculate the color for a pixel, first an AND is done with the mask,
+         * then an XOR with the color data. What it comes down to is that when the mask bit
+         * is 0, the pixel will get the color specified in the color data. When the mask bit
+         * is 1, the result is the background XOR'ed with the color data. In case the
+         * color data is completely black (0x000000) the pixel will become transparent, in case
+         * the color is white (0xffffff) the pixel will become the inverse of the background color.
+         *
+         * Since we can't support inverting colors, we map the mask to the alpha channel,
+         * making the pixel opaque if the mask bit isn't set, and transparent when it is. */
+        while(pixel_ptr < pixel_end)
+        {
+            /* Xcursor pixel data is in ARGB format, with A in the high byte */
+            switch (ptr->bBitsPerPixel)
+            {
+                case 24:
+                    /* BGR, 8 bits each */
+                    *pixel_ptr = *img_ptr++;
+                    *pixel_ptr |= *img_ptr++ << 8;
+                    *pixel_ptr |= *img_ptr++ << 16;
+                    break;
+
+                case 16:
+                    /* BGR, 5 red, 6 green, 5 blue */
+                    *pixel_ptr = (*img_ptr & 0xf8) | ((*img_ptr & 0x07) << 13);
+                    ++img_ptr;
+                    *pixel_ptr |= ((*img_ptr & 0xe0) << 5) | ((*img_ptr & 0x1f) << 19);
+                    break;
+
+                case 1:
+                    if (img_ptr[pixel_idx >> 3] & (0x80 >> (pixel_idx & 7))) *pixel_ptr = 0xffffff;
+                    else *pixel_ptr = 0;
+                    break;
+
+                default:
+                    FIXME("Currently no support for cursors with %d bits per pixel\n", ptr->bBitsPerPixel);
+                    XcursorImagesDestroy (images);
+                    return 0;
+            }
+            /* Alpha channel */
+            if (~mask_ptr[pixel_idx >> 3] & (0x80 >> (pixel_idx & 7))) *pixel_ptr |= 0xff << 24;
+
+            ++pixel_ptr;
+            ++pixel_idx;
+        }
+
+        images->images[images->nimage] = image;
+        ++images->nimage;
+
+        /* advance to the next image */
+        ptr = (CURSORICONINFO *)(((char *)ptr) + (sizeof(CURSORICONINFO) + img_size+ mask_size));
+    }
+
+    cursor = XcursorImagesLoadCursor(display, images);
+    XcursorImagesDestroy(images);
+    return cursor;
+}
+#else
 static Cursor create_cursor( Display *display, CURSORANIINFO *ani_info )
 {
     Pixmap pixmapBits, pixmapMask, pixmapMaskInv, pixmapAll;
@@ -643,6 +756,7 @@ static Cursor create_cursor( Display *di
     }
     return cursor;
 }
+#endif /* HAVE_LIBXCURSOR */
 
 
 /***********************************************************************





More information about the wine-patches mailing list