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
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 );