Add color cursor support

Duane Clark dclark at leewardfpga.com
Sat Dec 15 14:20:26 CST 2001


Here is a bit of a hack to add support for cursors that are more than 1 
bpp deep. Currently it only adds support for 24 bit color cursors, but 
most of the structure is there for other depths. I will see whether 
Alexandre accepts this before attempting the rest of it :-)

The main ugly hack that is performed here is in determining whether a 
pixel is a foreground or background pixel. This is done by adding the 
red, green and blue values for each pixel, and testing whether they 
exceed an arbitrary threshold. This should probably be a reasonably safe 
method, since presumably any cursor will have a high level of contrast 
between foreground and background colors.

ChangeLog:

	* windows/cursoricon.c
                Change annoying ERR to a WARN
	* dlls/x11drv/mouse.c
                Add color cursor support

Duane



-------------- next part --------------
Index: windows/cursoricon.c
===================================================================
RCS file: /home/wine/wine/windows/cursoricon.c,v
retrieving revision 1.37
diff -u -r1.37 cursoricon.c
--- windows/cursoricon.c	2001/11/20 18:55:40	1.37
+++ windows/cursoricon.c	2001/12/15 18:20:07
@@ -1303,7 +1303,7 @@
 
     if ( hActiveCursor == handle )
     {
-        ERR_(cursor)("Destroying active cursor!\n" );
+        WARN_(cursor)("Destroying active cursor!\n" );
         SetCursor( 0 );
     }
 
Index: dlls/x11drv/mouse.c
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/mouse.c,v
retrieving revision 1.1
diff -u -r1.1 mouse.c
--- dlls/x11drv/mouse.c	2001/10/18 21:38:59	1.1
+++ dlls/x11drv/mouse.c	2001/12/15 18:20:08
@@ -145,13 +145,11 @@
     {
         XImage *image;
         GC gc;
-
-        if (ptr->bPlanes * ptr->bBitsPerPixel != 1)
-        {
-            WARN("Cursor has more than 1 bpp!\n" );
-            return 0;
-        }
-
+        Pixmap  pixmapTmp;
+        
+        TRACE("Bitmap %dx%d planes=%d bpp=%d bytesperline=%d\n",
+            ptr->nWidth, ptr->nHeight, ptr->bPlanes, ptr->bBitsPerPixel,
+            ptr->nWidthBytes);
         /* Create a pixmap and transfer all the bits to it */
 
         /* NOTE: Following hack works, but only because XFree depth
@@ -159,19 +157,134 @@
          *       as the Windows cursor data). Perhaps use a more generic
          *       algorithm here.
          */
+        /* This pixmap will be written with two bitmaps. The first is
+         *  the mask and the second is the image.
+         */
         if (!(pixmapAll = XCreatePixmap( display, root_window,
-                                         ptr->nWidth, ptr->nHeight * 2, 1 ))) return 0;
-        if (!(image = XCreateImage( display, visual,
-                                    1, ZPixmap, 0, (char *)(ptr + 1), ptr->nWidth,
-                                    ptr->nHeight * 2, 16, ptr->nWidthBytes))) return 0;
+                  ptr->nWidth, ptr->nHeight * 2, 1 ))) 
+            return 0;
+        if (!(pixmapTmp = XCreatePixmap( display, root_window,
+                ptr->nWidth, ptr->nHeight, 1 ))) 
+            return 0;
+        if (ptr->bPlanes * ptr->bBitsPerPixel == 1)
+        {
+            /* A plain old white on black cursor. */
+            fg.red = fg.green = fg.blue = 0xffff;
+            bg.red = bg.green = bg.blue = 0x0000;
+            if (!(image = XCreateImage( display, visual,
+                  1, ZPixmap, 0, (char *)(ptr + 1), ptr->nWidth,
+                  ptr->nHeight * 2, 16, ptr->nWidthBytes))) 
+            {
+                if (pixmapAll) XFreePixmap( display, pixmapAll );
+                return 0;
+            }
+        }
+        else
+        {
+            int     rbits, gbits, bbits, red, green, blue;
+            int     rfg, gfg, bfg, rbg, gbg, bbg;
+            int     rscale, gscale, bscale;
+            GC      gcTmp;
+            int     x, y, bitIndex, byteIndex;
+            unsigned char *theMask, *theImage, theChar;
+            int     threshold, fgBits, bgBits;
+            
+            switch (ptr->bBitsPerPixel)
+            {
+            case 24:
+                rbits = 8;
+                gbits = 8;
+                bbits = 8;
+                threshold = 0x40;
+                break;
+            default:
+                FIXME("Currently no support for cursors with %d bits per pixel\n",
+                  ptr->bBitsPerPixel);
+                if (pixmapAll) XFreePixmap( display, pixmapAll );
+                return 0;
+            }
+            /* the mask should still be 1 bit per pixel. */
+            theMask = (char *)(ptr + 1);
+            if (!(image = XCreateImage( display, visual,
+                  1, ZPixmap, 0, theMask, ptr->nWidth,
+                  ptr->nHeight, 16, ptr->nWidthBytes/ptr->bBitsPerPixel))) 
+            {
+                if (pixmapAll) XFreePixmap( display, pixmapAll );
+                if (pixmapTmp) XFreePixmap( display, pixmapTmp );
+                return 0;
+            }
+            gcTmp = XCreateGC( display, pixmapTmp, 0, NULL );
+            XSetFunction( display, gcTmp, GXclear );
+            XFillRectangle( display, pixmapTmp, gcTmp, 0, 0, ptr->nWidth, ptr->nHeight );
+            XSetFunction( display, gcTmp, GXset );
+            
+            /* This is made moderately complicated to support various
+             * different numbers of bits per color.
+             */
+            theImage = &theMask[ptr->nWidth/8 * ptr->nHeight];
+            rfg = gfg = bfg = rbg = gbg = bbg = 0;
+            bitIndex = 0;
+            byteIndex = 0;
+            fgBits = 0;
+            for (y=0; y<ptr->nHeight; y++)
+            {
+                for (x=0; x<ptr->nWidth; x++)
+                {
+                    theChar = theImage[byteIndex++];
+                    red = green = blue = 0;
+                    blue = theChar;
+                    theChar = theImage[byteIndex++];
+                    green = theChar;
+                    theChar = theImage[byteIndex++];
+                    red = theChar;
+                    if (red+green+blue > threshold)
+                    {
+                        rfg += red;
+                        gfg += green;
+                        bfg += blue;
+                        fgBits++;
+                        XDrawPoint( display, pixmapTmp, gcTmp, x, y );
+                    }
+                    else
+                    {
+                        rbg += red;
+                        gbg += green;
+                        bbg += blue;
+                    }
+                }
+            }
+            rscale = 1 << (16 - rbits);
+            gscale = 1 << (16 - gbits);
+            bscale = 1 << (16 - bbits);
+            fg.red   = rfg * rscale / fgBits;
+            fg.green = gfg * gscale / fgBits;
+            fg.blue  = bfg * bscale / fgBits;
+            bgBits = ptr->nWidth * ptr->nHeight - fgBits;
+            bg.red   = rbg * rscale / bgBits;
+            bg.green = gbg * gscale / bgBits;
+            bg.blue  = bbg * bscale / bgBits;
+            XFreeGC( display, gcTmp );
+        }
+            
         gc = XCreateGC( display, pixmapAll, 0, NULL );
         XSetGraphicsExposures( display, gc, False );
         image->byte_order = MSBFirst;
         image->bitmap_bit_order = MSBFirst;
         image->bitmap_unit = 16;
         _XInitImageFuncPtrs(image);
-        XPutImage( display, pixmapAll, gc, image,
+        if (ptr->bPlanes * ptr->bBitsPerPixel == 1)
+        {
+            XPutImage( display, pixmapAll, gc, image,
                    0, 0, 0, 0, ptr->nWidth, ptr->nHeight * 2 );
+        }
+        else
+        {
+            XPutImage( display, pixmapAll, gc, image,
+                   0, 0, 0, 0, ptr->nWidth, ptr->nHeight );
+            XSetFunction( display, gc, GXcopy );
+            XCopyArea( display, pixmapTmp, pixmapAll, gc,
+                       0, 0, ptr->nWidth, ptr->nHeight, 0, ptr->nHeight );
+        }
         image->data = NULL;
         XDestroyImage( image );
 
@@ -230,14 +343,13 @@
             XCopyArea( display, pixmapMaskInv, pixmapBits, gc,
                        0, 0, ptr->nWidth, ptr->nHeight, 1, 1 );
             XSetFunction( display, gc, GXcopy );
-            fg.red = fg.green = fg.blue = 0xffff;
-            bg.red = bg.green = bg.blue = 0x0000;
             cursor = XCreatePixmapCursor( display, pixmapBits, pixmapMask,
                                 &fg, &bg, ptr->ptHotSpot.x, ptr->ptHotSpot.y );
         }
 
         /* Now free everything */
 
+        if (pixmapTmp) XFreePixmap( display, pixmapTmp );
         if (pixmapAll) XFreePixmap( display, pixmapAll );
         if (pixmapBits) XFreePixmap( display, pixmapBits );
         if (pixmapMask) XFreePixmap( display, pixmapMask );


More information about the wine-patches mailing list