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