Here is another attempt at color cursor support, still only for 24 bit color cursors. If anyone knows of an app with color cursors at another depth, let me know and I will try to add support for it. This patch should print out a fixme with the depth of the requested cursor for unsupported depths. ChangeLog: * windows/cursoricon.c Destroying cursor is not neccesarily an error * 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.38 diff -u -r1.38 cursoricon.c --- windows/cursoricon.c 2001/12/17 21:40:57 1.38 +++ windows/cursoricon.c 2001/12/23 00:22:59 @@ -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/23 00:23:00 @@ -145,13 +145,10 @@ { XImage *image; GC gc; - - if (ptr->bPlanes * ptr->bBitsPerPixel != 1) - { - WARN("Cursor has more than 1 bpp!\n" ); - return 0; - } - + + 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 +156,143 @@ * 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; + 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; + 1, ZPixmap, 0, (char *)(ptr + 1), ptr->nWidth, + ptr->nHeight * 2, 16, ptr->nWidthBytes/ptr->bBitsPerPixel))) + { + XFreePixmap( display, pixmapAll ); + return 0; + } 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, - 0, 0, 0, 0, ptr->nWidth, ptr->nHeight * 2 ); + 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; + XPutImage( display, pixmapAll, gc, image, + 0, 0, 0, 0, ptr->nWidth, ptr->nHeight * 2 ); + } + else + { + int rbits, gbits, bbits, red, green, blue; + int rfg, gfg, bfg, rbg, gbg, bbg; + int rscale, gscale, bscale; + int x, y, xmax, ymax, bitIndex, byteIndex, xorIndex; + unsigned char *theMask, *theImage, theChar; + int threshold, fgBits, bgBits, bitShifted; + BYTE pXorBits[128]; /* Up to 32x32 icons */ + + 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); + XFreePixmap( display, pixmapAll ); + XFreeGC( display, gc ); + image->data = NULL; + XDestroyImage( image ); + return 0; + } + /* The location of the mask. */ + theMask = (char *)(ptr + 1); + /* The mask should still be 1 bit per pixel. The color image + * should immediately follow the mask. + */ + theImage = &theMask[ptr->nWidth/8 * ptr->nHeight]; + rfg = gfg = bfg = rbg = gbg = bbg = 0; + bitIndex = 0; + byteIndex = 0; + xorIndex = 0; + fgBits = 0; + bitShifted = 0x01; + xmax = (ptr->nWidth > 32) ? 32 : ptr->nWidth; + if (ptr->nWidth > 32) { + ERR("Got a %dx%d cursor. Cannot handle larger than 32x32.\n", + ptr->nWidth, ptr->nHeight); + } + ymax = (ptr->nHeight > 32) ? 32 : ptr->nHeight; + + memset(pXorBits, 0, 128); + for (y=0; y<ymax; y++) + { + for (x=0; x<xmax; 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++; + pXorBits[xorIndex] |= bitShifted; + } + else + { + rbg += red; + gbg += green; + bbg += blue; + } + if (x%8 == 7) + { + bitShifted = 0x01; + xorIndex++; + } + else + bitShifted = bitShifted << 1; + } + } + 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 = xmax * ymax - fgBits; + bg.red = rbg * rscale / bgBits; + bg.green = gbg * gscale / bgBits; + bg.blue = bbg * bscale / bgBits; + pixmapBits = XCreateBitmapFromData( display, root_window, pXorBits, xmax, ymax ); + if (!pixmapBits) + { + XFreePixmap( display, pixmapAll ); + XFreeGC( display, gc ); + image->data = NULL; + XDestroyImage( image ); + return 0; + } + + /* Put the mask. */ + XPutImage( display, pixmapAll, gc, image, + 0, 0, 0, 0, ptr->nWidth, ptr->nHeight ); + XSetFunction( display, gc, GXcopy ); + /* Put the image */ + XCopyArea( display, pixmapBits, pixmapAll, gc, + 0, 0, xmax, ymax, 0, ptr->nHeight ); + XFreePixmap( display, pixmapBits ); + } image->data = NULL; XDestroyImage( image ); @@ -230,8 +351,6 @@ 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 ); }