cursor.c revision 7914d74b
17914d74bSmrg/*
27914d74bSmrg * $Id: cursor.c,v 1.1.1.1 2008/07/30 02:45:52 mrg Exp $
37914d74bSmrg *
47914d74bSmrg * Copyright © 2002 Keith Packard
57914d74bSmrg *
67914d74bSmrg * Permission to use, copy, modify, distribute, and sell this software and its
77914d74bSmrg * documentation for any purpose is hereby granted without fee, provided that
87914d74bSmrg * the above copyright notice appear in all copies and that both that
97914d74bSmrg * copyright notice and this permission notice appear in supporting
107914d74bSmrg * documentation, and that the name of Keith Packard not be used in
117914d74bSmrg * advertising or publicity pertaining to distribution of the software without
127914d74bSmrg * specific, written prior permission.  Keith Packard makes no
137914d74bSmrg * representations about the suitability of this software for any purpose.  It
147914d74bSmrg * is provided "as is" without express or implied warranty.
157914d74bSmrg *
167914d74bSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
177914d74bSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
187914d74bSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
197914d74bSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
207914d74bSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
217914d74bSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
227914d74bSmrg * PERFORMANCE OF THIS SOFTWARE.
237914d74bSmrg */
247914d74bSmrg
257914d74bSmrg#include "xcursorint.h"
267914d74bSmrg#include <X11/Xlibint.h>
277914d74bSmrg#include <X11/Xutil.h>
287914d74bSmrg
297914d74bSmrgXcursorCursors *
307914d74bSmrgXcursorCursorsCreate (Display *dpy, int size)
317914d74bSmrg{
327914d74bSmrg    XcursorCursors  *cursors;
337914d74bSmrg
347914d74bSmrg    cursors = malloc (sizeof (XcursorCursors) +
357914d74bSmrg		      size * sizeof (Cursor));
367914d74bSmrg    if (!cursors)
377914d74bSmrg	return NULL;
387914d74bSmrg    cursors->ref = 1;
397914d74bSmrg    cursors->dpy = dpy;
407914d74bSmrg    cursors->ncursor = 0;
417914d74bSmrg    cursors->cursors = (Cursor *) (cursors + 1);
427914d74bSmrg    return cursors;
437914d74bSmrg}
447914d74bSmrg
457914d74bSmrgvoid
467914d74bSmrgXcursorCursorsDestroy (XcursorCursors *cursors)
477914d74bSmrg{
487914d74bSmrg    int	    n;
497914d74bSmrg
507914d74bSmrg    if (!cursors)
517914d74bSmrg      return;
527914d74bSmrg
537914d74bSmrg    --cursors->ref;
547914d74bSmrg    if (cursors->ref > 0)
557914d74bSmrg	return;
567914d74bSmrg
577914d74bSmrg    for (n = 0; n < cursors->ncursor; n++)
587914d74bSmrg	XFreeCursor (cursors->dpy, cursors->cursors[n]);
597914d74bSmrg    free (cursors);
607914d74bSmrg}
617914d74bSmrg
627914d74bSmrgXcursorAnimate *
637914d74bSmrgXcursorAnimateCreate (XcursorCursors *cursors)
647914d74bSmrg{
657914d74bSmrg    XcursorAnimate  *animate;
667914d74bSmrg
677914d74bSmrg    animate = malloc (sizeof (XcursorAnimate));
687914d74bSmrg    if (!animate)
697914d74bSmrg	return NULL;
707914d74bSmrg    animate->cursors = cursors;
717914d74bSmrg    cursors->ref++;
727914d74bSmrg    animate->sequence = 0;
737914d74bSmrg    return animate;
747914d74bSmrg}
757914d74bSmrg
767914d74bSmrgvoid
777914d74bSmrgXcursorAnimateDestroy (XcursorAnimate *animate)
787914d74bSmrg{
797914d74bSmrg    if (!animate)
807914d74bSmrg      return;
817914d74bSmrg
827914d74bSmrg    XcursorCursorsDestroy (animate->cursors);
837914d74bSmrg    free (animate);
847914d74bSmrg}
857914d74bSmrg
867914d74bSmrgCursor
877914d74bSmrgXcursorAnimateNext (XcursorAnimate *animate)
887914d74bSmrg{
897914d74bSmrg    Cursor  cursor = animate->cursors->cursors[animate->sequence++];
907914d74bSmrg
917914d74bSmrg    if (animate->sequence >= animate->cursors->ncursor)
927914d74bSmrg	animate->sequence = 0;
937914d74bSmrg    return cursor;
947914d74bSmrg}
957914d74bSmrg
967914d74bSmrgstatic int
977914d74bSmrgnativeByteOrder (void)
987914d74bSmrg{
997914d74bSmrg    int	x = 1;
1007914d74bSmrg
1017914d74bSmrg    return (*((char *) &x) == 1) ? LSBFirst : MSBFirst;
1027914d74bSmrg}
1037914d74bSmrg
1047914d74bSmrgstatic XcursorUInt
1057914d74bSmrg_XcursorPixelBrightness (XcursorPixel p)
1067914d74bSmrg{
1077914d74bSmrg    XcursorPixel    alpha = p >> 24;
1087914d74bSmrg    XcursorPixel    r, g, b;
1097914d74bSmrg
1107914d74bSmrg    if (!alpha)
1117914d74bSmrg	return 0;
1127914d74bSmrg    r = ((p >> 8) & 0xff00) / alpha;
1137914d74bSmrg    if (r > 0xff) r = 0xff;
1147914d74bSmrg    g = ((p >> 0) & 0xff00) / alpha;
1157914d74bSmrg    if (g > 0xff) g = 0xff;
1167914d74bSmrg    b = ((p << 8) & 0xff00) / alpha;
1177914d74bSmrg    if (b > 0xff) b = 0xff;
1187914d74bSmrg    return (r * 153 + g * 301 + b * 58) >> 9;
1197914d74bSmrg}
1207914d74bSmrg
1217914d74bSmrgstatic unsigned short
1227914d74bSmrg_XcursorDivideAlpha (XcursorUInt value, XcursorUInt alpha)
1237914d74bSmrg{
1247914d74bSmrg    if (!alpha)
1257914d74bSmrg	return 0;
1267914d74bSmrg    value = value * 255 / alpha;
1277914d74bSmrg    if (value > 255)
1287914d74bSmrg	value = 255;
1297914d74bSmrg    return value | (value << 8);
1307914d74bSmrg}
1317914d74bSmrg
1327914d74bSmrgstatic void
1337914d74bSmrg_XcursorPixelToColor (XcursorPixel p, XColor *color)
1347914d74bSmrg{
1357914d74bSmrg    XcursorPixel    alpha = p >> 24;
1367914d74bSmrg
1377914d74bSmrg    color->pixel = 0;
1387914d74bSmrg    color->red =   _XcursorDivideAlpha ((p >> 16) & 0xff, alpha);
1397914d74bSmrg    color->green = _XcursorDivideAlpha ((p >>  8) & 0xff, alpha);
1407914d74bSmrg    color->blue =  _XcursorDivideAlpha ((p >>  0) & 0xff, alpha);
1417914d74bSmrg    color->flags = DoRed|DoGreen|DoBlue;
1427914d74bSmrg}
1437914d74bSmrg
1447914d74bSmrg#undef DEBUG_IMAGE
1457914d74bSmrg#ifdef DEBUG_IMAGE
1467914d74bSmrgstatic void
1477914d74bSmrg_XcursorDumpImage (XImage *image)
1487914d74bSmrg{
1497914d74bSmrg    FILE    *f = fopen ("/tmp/images", "a");
1507914d74bSmrg    int	    x, y;
1517914d74bSmrg    if (!f)
1527914d74bSmrg	return;
1537914d74bSmrg    fprintf (f, "%d x %x\n", image->width, image->height);
1547914d74bSmrg    for (y = 0; y < image->height; y++)
1557914d74bSmrg    {
1567914d74bSmrg	for (x = 0; x < image->width; x++)
1577914d74bSmrg	    fprintf (f, "%c", XGetPixel (image, x, y) ? '*' : ' ');
1587914d74bSmrg	fprintf (f, "\n");
1597914d74bSmrg    }
1607914d74bSmrg    fflush (f);
1617914d74bSmrg    fclose (f);
1627914d74bSmrg}
1637914d74bSmrg
1647914d74bSmrgstatic void
1657914d74bSmrg_XcursorDumpColor (XColor *color, char *name)
1667914d74bSmrg{
1677914d74bSmrg    FILE    *f = fopen ("/tmp/images", "a");
1687914d74bSmrg    fprintf (f, "%s: %x %x %x\n", name,
1697914d74bSmrg	     color->red, color->green, color->blue);
1707914d74bSmrg    fflush (f);
1717914d74bSmrg    fclose (f);
1727914d74bSmrg}
1737914d74bSmrg#endif
1747914d74bSmrg
1757914d74bSmrgstatic int
1767914d74bSmrg_XcursorCompareRed (const void *a, const void *b)
1777914d74bSmrg{
1787914d74bSmrg    const XcursorPixel    *ap = a, *bp = b;
1797914d74bSmrg
1807914d74bSmrg    return (int) (((*ap >> 16) & 0xff) - ((*bp >> 16) & 0xff));
1817914d74bSmrg}
1827914d74bSmrg
1837914d74bSmrgstatic int
1847914d74bSmrg_XcursorCompareGreen (const void *a, const void *b)
1857914d74bSmrg{
1867914d74bSmrg    const XcursorPixel    *ap = a, *bp = b;
1877914d74bSmrg
1887914d74bSmrg    return (int) (((*ap >> 8) & 0xff) - ((*bp >> 8) & 0xff));
1897914d74bSmrg}
1907914d74bSmrg
1917914d74bSmrgstatic int
1927914d74bSmrg_XcursorCompareBlue (const void *a, const void *b)
1937914d74bSmrg{
1947914d74bSmrg    const XcursorPixel    *ap = a, *bp = b;
1957914d74bSmrg
1967914d74bSmrg    return (int) (((*ap >> 0) & 0xff) - ((*bp >> 0) & 0xff));
1977914d74bSmrg}
1987914d74bSmrg
1997914d74bSmrgstatic XcursorPixel
2007914d74bSmrg_XcursorAverageColor (XcursorPixel *pixels, int npixels)
2017914d74bSmrg{
2027914d74bSmrg    XcursorPixel    p;
2037914d74bSmrg    XcursorPixel    red, green, blue;
2047914d74bSmrg    int		    n = npixels;
2057914d74bSmrg
2067914d74bSmrg    blue = green = red = 0;
2077914d74bSmrg    while (n--)
2087914d74bSmrg    {
2097914d74bSmrg	p = *pixels++;
2107914d74bSmrg	red += (p >> 16) & 0xff;
2117914d74bSmrg	green += (p >> 8) & 0xff;
2127914d74bSmrg	blue += (p >> 0) & 0xff;
2137914d74bSmrg    }
2147914d74bSmrg    if (!n)
2157914d74bSmrg	return 0;
2167914d74bSmrg    return (0xff << 24) | ((red/npixels) << 16) | ((green/npixels) << 8) | (blue/npixels);
2177914d74bSmrg}
2187914d74bSmrg
2197914d74bSmrgtypedef struct XcursorCoreCursor {
2207914d74bSmrg    XImage  *src_image;
2217914d74bSmrg    XImage  *msk_image;
2227914d74bSmrg    XColor  on_color;
2237914d74bSmrg    XColor  off_color;
2247914d74bSmrg} XcursorCoreCursor;
2257914d74bSmrg
2267914d74bSmrgstatic Bool
2277914d74bSmrg_XcursorHeckbertMedianCut (const XcursorImage *image, XcursorCoreCursor *core)
2287914d74bSmrg{
2297914d74bSmrg    XImage	    *src_image = core->src_image, *msk_image = core->msk_image;
2307914d74bSmrg    int		    npixels = image->width * image->height;
2317914d74bSmrg    int		    ncolors;
2327914d74bSmrg    int		    n;
2337914d74bSmrg    XcursorPixel    *po, *pn, *pc;
2347914d74bSmrg    XcursorPixel    p;
2357914d74bSmrg    XcursorPixel    red, green, blue, alpha;
2367914d74bSmrg    XcursorPixel    max_red, min_red, max_green, min_green, max_blue, min_blue;
2377914d74bSmrg    XcursorPixel    *temp, *pixels, *colors;
2387914d74bSmrg    int		    split;
2397914d74bSmrg    XcursorPixel    leftColor, centerColor, rightColor;
2407914d74bSmrg    int		    (*compare) (const void *, const void *);
2417914d74bSmrg    int		    x, y;
2427914d74bSmrg
2437914d74bSmrg    /*
2447914d74bSmrg     * Temp space for converted image and converted colors
2457914d74bSmrg     */
2467914d74bSmrg    temp = malloc (npixels * sizeof (XcursorPixel) * 2);
2477914d74bSmrg    if (!temp)
2487914d74bSmrg	return False;
2497914d74bSmrg
2507914d74bSmrg    pixels = temp;
2517914d74bSmrg    colors = pixels + npixels;
2527914d74bSmrg
2537914d74bSmrg    /*
2547914d74bSmrg     * Convert to 2-value alpha and build
2557914d74bSmrg     * array of opaque color values and an
2567914d74bSmrg     */
2577914d74bSmrg    po = image->pixels;
2587914d74bSmrg    pn = pixels;
2597914d74bSmrg    pc = colors;
2607914d74bSmrg    max_blue = max_green = max_red = 0;
2617914d74bSmrg    min_blue = min_green = min_red = 255;
2627914d74bSmrg    n = npixels;
2637914d74bSmrg    while (n--)
2647914d74bSmrg    {
2657914d74bSmrg	p = *po++;
2667914d74bSmrg	alpha = (p >> 24) & 0xff;
2677914d74bSmrg	red = (p >> 16) & 0xff;
2687914d74bSmrg	green = (p >> 8) & 0xff;
2697914d74bSmrg	blue = (p >> 0) & 0xff;
2707914d74bSmrg	if (alpha >= 0x80)
2717914d74bSmrg	{
2727914d74bSmrg	    red = red * 255 / alpha;
2737914d74bSmrg	    green = green * 255 / alpha;
2747914d74bSmrg	    blue = blue * 255 / alpha;
2757914d74bSmrg	    if (red < min_red) min_red = red;
2767914d74bSmrg	    if (red > max_red) max_red = red;
2777914d74bSmrg	    if (green < min_green) min_green = green;
2787914d74bSmrg	    if (green > max_green) max_green = green;
2797914d74bSmrg	    if (blue < min_blue) min_blue = blue;
2807914d74bSmrg	    if (blue > max_blue) max_blue = blue;
2817914d74bSmrg	    p = ((0xff << 24) | (red << 16) |
2827914d74bSmrg		 (green << 8) | (blue << 0));
2837914d74bSmrg	    *pc++ = p;
2847914d74bSmrg	}
2857914d74bSmrg	else
2867914d74bSmrg	    p = 0;
2877914d74bSmrg	*pn++ = p;
2887914d74bSmrg    }
2897914d74bSmrg    ncolors = pc - colors;
2907914d74bSmrg
2917914d74bSmrg    /*
2927914d74bSmrg     * Compute longest dimension and sort
2937914d74bSmrg     */
2947914d74bSmrg    if ((max_green - min_green) >= (max_red - min_red) &&
2957914d74bSmrg	(max_green - min_green) >= (max_blue - min_blue))
2967914d74bSmrg	compare = _XcursorCompareGreen;
2977914d74bSmrg    else if ((max_red - min_red) >= (max_blue - min_blue))
2987914d74bSmrg	compare = _XcursorCompareRed;
2997914d74bSmrg    else
3007914d74bSmrg	compare = _XcursorCompareBlue;
3017914d74bSmrg    qsort (colors, ncolors, sizeof (XcursorPixel), compare);
3027914d74bSmrg    /*
3037914d74bSmrg     * Compute average colors on both sides of the cut
3047914d74bSmrg     */
3057914d74bSmrg    split = ncolors >> 1;
3067914d74bSmrg    leftColor  = _XcursorAverageColor (colors, split);
3077914d74bSmrg    centerColor = colors[split];
3087914d74bSmrg    rightColor = _XcursorAverageColor (colors + split, ncolors - split);
3097914d74bSmrg    /*
3107914d74bSmrg     * Select best color for each pixel
3117914d74bSmrg     */
3127914d74bSmrg    pn = pixels;
3137914d74bSmrg    for (y = 0; y < image->height; y++)
3147914d74bSmrg	for (x = 0; x < image->width; x++)
3157914d74bSmrg	{
3167914d74bSmrg	    p = *pn++;
3177914d74bSmrg	    if (p & 0xff000000)
3187914d74bSmrg	    {
3197914d74bSmrg		XPutPixel (msk_image, x, y, 1);
3207914d74bSmrg		if ((*compare) (&p, &centerColor) >= 0)
3217914d74bSmrg		    XPutPixel (src_image, x, y, 0);
3227914d74bSmrg		else
3237914d74bSmrg		    XPutPixel (src_image, x, y, 1);
3247914d74bSmrg	    }
3257914d74bSmrg	    else
3267914d74bSmrg	    {
3277914d74bSmrg		XPutPixel (msk_image, x, y, 0);
3287914d74bSmrg		XPutPixel (src_image, x, y, 0);
3297914d74bSmrg	    }
3307914d74bSmrg	}
3317914d74bSmrg    free (temp);
3327914d74bSmrg    _XcursorPixelToColor (rightColor, &core->off_color);
3337914d74bSmrg    _XcursorPixelToColor (leftColor, &core->on_color);
3347914d74bSmrg    return True;
3357914d74bSmrg}
3367914d74bSmrg
3377914d74bSmrg#if 0
3387914d74bSmrg#define DITHER_DIM  4
3397914d74bSmrgstatic XcursorPixel orderedDither[4][4] = {
3407914d74bSmrg    {  1,  9,  3, 11 },
3417914d74bSmrg    { 13,  5, 15,  7 },
3427914d74bSmrg    {  4, 12,  2, 10 },
3437914d74bSmrg    { 16,  8, 14,  6 }
3447914d74bSmrg};
3457914d74bSmrg#else
3467914d74bSmrg#define DITHER_DIM 2
3477914d74bSmrgstatic XcursorPixel orderedDither[2][2] = {
3487914d74bSmrg    {  1,  3,  },
3497914d74bSmrg    {  4,  2,  },
3507914d74bSmrg};
3517914d74bSmrg#endif
3527914d74bSmrg
3537914d74bSmrg#define DITHER_SIZE  ((sizeof orderedDither / sizeof orderedDither[0][0]) + 1)
3547914d74bSmrg
3557914d74bSmrgstatic Bool
3567914d74bSmrg_XcursorBayerOrderedDither (const XcursorImage *image, XcursorCoreCursor *core)
3577914d74bSmrg{
3587914d74bSmrg    int		    x, y;
3597914d74bSmrg    XcursorPixel    *pixel, p;
3607914d74bSmrg    XcursorPixel    a, i, d;
3617914d74bSmrg
3627914d74bSmrg    pixel = image->pixels;
3637914d74bSmrg    for (y = 0; y < image->height; y++)
3647914d74bSmrg	for (x = 0; x < image->width; x++)
3657914d74bSmrg	{
3667914d74bSmrg	    p = *pixel++;
3677914d74bSmrg	    a = ((p >> 24) * DITHER_SIZE + 127) / 255;
3687914d74bSmrg	    i = (_XcursorPixelBrightness (p) * DITHER_SIZE + 127) / 255;
3697914d74bSmrg	    d = orderedDither[y&(DITHER_DIM-1)][x&(DITHER_DIM-1)];
3707914d74bSmrg	    if (a > d)
3717914d74bSmrg	    {
3727914d74bSmrg		XPutPixel (core->msk_image, x, y, 1);
3737914d74bSmrg		if (i > d)
3747914d74bSmrg		    XPutPixel (core->src_image, x, y, 0);   /* white */
3757914d74bSmrg		else
3767914d74bSmrg		    XPutPixel (core->src_image, x, y, 1);   /* black */
3777914d74bSmrg	    }
3787914d74bSmrg	    else
3797914d74bSmrg	    {
3807914d74bSmrg		XPutPixel (core->msk_image, x, y, 0);
3817914d74bSmrg		XPutPixel (core->src_image, x, y, 0);
3827914d74bSmrg	    }
3837914d74bSmrg	}
3847914d74bSmrg    core->on_color.red = 0;
3857914d74bSmrg    core->on_color.green = 0;
3867914d74bSmrg    core->on_color.blue = 0;
3877914d74bSmrg    core->off_color.red = 0xffff;
3887914d74bSmrg    core->off_color.green = 0xffff;
3897914d74bSmrg    core->off_color.blue = 0xffff;
3907914d74bSmrg    return True;
3917914d74bSmrg}
3927914d74bSmrg
3937914d74bSmrgstatic Bool
3947914d74bSmrg_XcursorFloydSteinberg (const XcursorImage *image, XcursorCoreCursor *core)
3957914d74bSmrg{
3967914d74bSmrg    int		    *aPicture, *iPicture, *aP, *iP;
3977914d74bSmrg    XcursorPixel    *pixel, p;
3987914d74bSmrg    int		    aR, iR, aA, iA;
3997914d74bSmrg    int		    npixels = image->width * image->height;
4007914d74bSmrg    int		    n;
4017914d74bSmrg    int		    right = 1;
4027914d74bSmrg    int		    belowLeft = image->width - 1;
4037914d74bSmrg    int		    below = image->width;
4047914d74bSmrg    int		    belowRight = image->width + 1;
4057914d74bSmrg    int		    iError, aError;
4067914d74bSmrg    int		    iErrorRight, aErrorRight;
4077914d74bSmrg    int		    iErrorBelowLeft, aErrorBelowLeft;
4087914d74bSmrg    int		    iErrorBelow, aErrorBelow;
4097914d74bSmrg    int		    iErrorBelowRight, aErrorBelowRight;
4107914d74bSmrg    int		    x, y;
4117914d74bSmrg    int		    max_inten, min_inten, mean_inten;
4127914d74bSmrg
4137914d74bSmrg    iPicture = malloc (npixels * sizeof (int) * 2);
4147914d74bSmrg    if (!iPicture)
4157914d74bSmrg	return False;
4167914d74bSmrg    aPicture = iPicture + npixels;
4177914d74bSmrg
4187914d74bSmrg    /*
4197914d74bSmrg     * Compute raw gray and alpha arrays
4207914d74bSmrg     */
4217914d74bSmrg    pixel = image->pixels;
4227914d74bSmrg    iP = iPicture;
4237914d74bSmrg    aP = aPicture;
4247914d74bSmrg    n = npixels;
4257914d74bSmrg    max_inten = 0;
4267914d74bSmrg    min_inten = 0xff;
4277914d74bSmrg    while (n--)
4287914d74bSmrg    {
4297914d74bSmrg	p = *pixel++;
4307914d74bSmrg	*aP++ = (int) (p >> 24);
4317914d74bSmrg	iR = (int) _XcursorPixelBrightness (p);
4327914d74bSmrg	if (iR > max_inten) max_inten = iR;
4337914d74bSmrg	if (iR < min_inten) min_inten = iR;
4347914d74bSmrg	*iP++ = iR;
4357914d74bSmrg    }
4367914d74bSmrg    /*
4377914d74bSmrg     * Draw the image while diffusing the error
4387914d74bSmrg     */
4397914d74bSmrg    iP = iPicture;
4407914d74bSmrg    aP = aPicture;
4417914d74bSmrg    mean_inten = (max_inten + min_inten + 1) >> 1;
4427914d74bSmrg    for (y = 0; y < image->height; y++)
4437914d74bSmrg	for (x = 0; x < image->width; x++)
4447914d74bSmrg	{
4457914d74bSmrg	    aR = *aP;
4467914d74bSmrg	    iR = *iP;
4477914d74bSmrg	    if (aR >= 0x80)
4487914d74bSmrg	    {
4497914d74bSmrg		XPutPixel (core->msk_image, x, y, 1);
4507914d74bSmrg		aA = 0xff;
4517914d74bSmrg	    }
4527914d74bSmrg	    else
4537914d74bSmrg	    {
4547914d74bSmrg		XPutPixel (core->msk_image, x, y, 0);
4557914d74bSmrg		aA = 0x00;
4567914d74bSmrg	    }
4577914d74bSmrg	    if (iR >= mean_inten)
4587914d74bSmrg	    {
4597914d74bSmrg		XPutPixel (core->src_image, x, y, 0);
4607914d74bSmrg		iA = max_inten;
4617914d74bSmrg	    }
4627914d74bSmrg	    else
4637914d74bSmrg	    {
4647914d74bSmrg		XPutPixel (core->src_image, x, y, 1);
4657914d74bSmrg		iA = min_inten;
4667914d74bSmrg	    }
4677914d74bSmrg	    iError = iR - iA;
4687914d74bSmrg	    aError = aR - aA;
4697914d74bSmrg	    iErrorRight = (iError * 7) >> 4;
4707914d74bSmrg	    iErrorBelowLeft = (iError * 3) >> 4;
4717914d74bSmrg	    iErrorBelow = (iError * 5) >> 4;
4727914d74bSmrg	    iErrorBelowRight = (iError - iErrorRight -
4737914d74bSmrg				iErrorBelowLeft - iErrorBelow);
4747914d74bSmrg	    aErrorRight = (aError * 7) >> 4;
4757914d74bSmrg	    aErrorBelowLeft = (aError * 3) >> 4;
4767914d74bSmrg	    aErrorBelow = (aError * 5) >> 4;
4777914d74bSmrg	    aErrorBelowRight = (aError - aErrorRight -
4787914d74bSmrg				aErrorBelowLeft - aErrorBelow);
4797914d74bSmrg	    if (x < image->width - 1)
4807914d74bSmrg	    {
4817914d74bSmrg		iP[right] += iErrorRight;
4827914d74bSmrg		aP[right] += aErrorRight;
4837914d74bSmrg	    }
4847914d74bSmrg	    if (y < image->height - 1)
4857914d74bSmrg	    {
4867914d74bSmrg		if (x)
4877914d74bSmrg		{
4887914d74bSmrg		    iP[belowLeft] += iErrorBelowLeft;
4897914d74bSmrg		    aP[belowLeft] += aErrorBelowLeft;
4907914d74bSmrg		}
4917914d74bSmrg		iP[below] += iErrorBelow;
4927914d74bSmrg		aP[below] += aErrorBelow;
4937914d74bSmrg		if (x < image->width - 1)
4947914d74bSmrg		{
4957914d74bSmrg		    iP[belowRight] += iErrorBelowRight;
4967914d74bSmrg		    aP[belowRight] += aErrorBelowRight;
4977914d74bSmrg		}
4987914d74bSmrg	    }
4997914d74bSmrg	    aP++;
5007914d74bSmrg	    iP++;
5017914d74bSmrg	}
5027914d74bSmrg    free (iPicture);
5037914d74bSmrg    core->on_color.red =
5047914d74bSmrg    core->on_color.green =
5057914d74bSmrg    core->on_color.blue = (min_inten | min_inten << 8);
5067914d74bSmrg    core->off_color.red =
5077914d74bSmrg    core->off_color.green =
5087914d74bSmrg    core->off_color.blue = (max_inten | max_inten << 8);
5097914d74bSmrg    return True;
5107914d74bSmrg}
5117914d74bSmrg
5127914d74bSmrgstatic Bool
5137914d74bSmrg_XcursorThreshold (const XcursorImage *image, XcursorCoreCursor *core)
5147914d74bSmrg{
5157914d74bSmrg    XcursorPixel    *pixel, p;
5167914d74bSmrg    int		    x, y;
5177914d74bSmrg
5187914d74bSmrg    /*
5197914d74bSmrg     * Draw the image, picking black for dark pixels and white for light
5207914d74bSmrg     */
5217914d74bSmrg    pixel = image->pixels;
5227914d74bSmrg    for (y = 0; y < image->height; y++)
5237914d74bSmrg	for (x = 0; x < image->width; x++)
5247914d74bSmrg	{
5257914d74bSmrg	    p = *pixel++;
5267914d74bSmrg	    if ((p >> 24) >= 0x80)
5277914d74bSmrg	    {
5287914d74bSmrg		XPutPixel (core->msk_image, x, y, 1);
5297914d74bSmrg		if (_XcursorPixelBrightness (p) > 0x80)
5307914d74bSmrg		    XPutPixel (core->src_image, x, y, 0);
5317914d74bSmrg		else
5327914d74bSmrg		    XPutPixel (core->src_image, x, y, 1);
5337914d74bSmrg	    }
5347914d74bSmrg	    else
5357914d74bSmrg	    {
5367914d74bSmrg		XPutPixel (core->msk_image, x, y, 0);
5377914d74bSmrg		XPutPixel (core->src_image, x, y, 0);
5387914d74bSmrg	    }
5397914d74bSmrg	}
5407914d74bSmrg    core->on_color.red =
5417914d74bSmrg    core->on_color.green =
5427914d74bSmrg    core->on_color.blue = 0;
5437914d74bSmrg    core->off_color.red =
5447914d74bSmrg    core->off_color.green =
5457914d74bSmrg    core->off_color.blue = 0xffff;
5467914d74bSmrg    return True;
5477914d74bSmrg}
5487914d74bSmrg
5497914d74bSmrgCursor
5507914d74bSmrgXcursorImageLoadCursor (Display *dpy, const XcursorImage *image)
5517914d74bSmrg{
5527914d74bSmrg    Cursor  cursor;
5537914d74bSmrg
5547914d74bSmrg#if RENDER_MAJOR > 0 || RENDER_MINOR >= 5
5557914d74bSmrg    if (XcursorSupportsARGB (dpy))
5567914d74bSmrg    {
5577914d74bSmrg	XImage		    ximage;
5587914d74bSmrg	int		    screen = DefaultScreen (dpy);
5597914d74bSmrg	Pixmap		    pixmap;
5607914d74bSmrg	Picture		    picture;
5617914d74bSmrg	GC		    gc;
5627914d74bSmrg	XRenderPictFormat   *format;
5637914d74bSmrg
5647914d74bSmrg	ximage.width = image->width;
5657914d74bSmrg	ximage.height = image->height;
5667914d74bSmrg	ximage.xoffset = 0;
5677914d74bSmrg	ximage.format = ZPixmap;
5687914d74bSmrg	ximage.data = (char *) image->pixels;
5697914d74bSmrg	ximage.byte_order = nativeByteOrder ();
5707914d74bSmrg	ximage.bitmap_unit = 32;
5717914d74bSmrg	ximage.bitmap_bit_order = ximage.byte_order;
5727914d74bSmrg	ximage.bitmap_pad = 32;
5737914d74bSmrg	ximage.depth = 32;
5747914d74bSmrg	ximage.bits_per_pixel = 32;
5757914d74bSmrg	ximage.bytes_per_line = image->width * 4;
5767914d74bSmrg	ximage.red_mask = 0xff0000;
5777914d74bSmrg	ximage.green_mask = 0x00ff00;
5787914d74bSmrg	ximage.blue_mask = 0x0000ff;
5797914d74bSmrg	ximage.obdata = NULL;
5807914d74bSmrg	if (!XInitImage (&ximage))
5817914d74bSmrg	    return None;
5827914d74bSmrg	pixmap = XCreatePixmap (dpy, RootWindow (dpy, screen),
5837914d74bSmrg				image->width, image->height, 32);
5847914d74bSmrg	gc = XCreateGC (dpy, pixmap, 0, NULL);
5857914d74bSmrg	XPutImage (dpy, pixmap, gc, &ximage,
5867914d74bSmrg		   0, 0, 0, 0, image->width, image->height);
5877914d74bSmrg	XFreeGC (dpy, gc);
5887914d74bSmrg	format = XRenderFindStandardFormat (dpy, PictStandardARGB32);
5897914d74bSmrg	picture = XRenderCreatePicture (dpy, pixmap, format, 0, NULL);
5907914d74bSmrg	XFreePixmap (dpy, pixmap);
5917914d74bSmrg	cursor = XRenderCreateCursor (dpy, picture,
5927914d74bSmrg				      image->xhot, image->yhot);
5937914d74bSmrg	XRenderFreePicture (dpy, picture);
5947914d74bSmrg    }
5957914d74bSmrg    else
5967914d74bSmrg#endif
5977914d74bSmrg    {
5987914d74bSmrg	XcursorDisplayInfo  *info = _XcursorGetDisplayInfo (dpy);
5997914d74bSmrg	int		    screen = DefaultScreen (dpy);
6007914d74bSmrg	XcursorCoreCursor   core;
6017914d74bSmrg	Pixmap		    src_pixmap, msk_pixmap;
6027914d74bSmrg	GC		    gc;
6037914d74bSmrg	XGCValues	    gcv;
6047914d74bSmrg
6057914d74bSmrg	core.src_image = XCreateImage (dpy, NULL, 1, ZPixmap,
6067914d74bSmrg				       0, NULL, image->width, image->height,
6077914d74bSmrg				       32, 0);
6087914d74bSmrg	core.src_image->data = Xmalloc (image->height *
6097914d74bSmrg					core.src_image->bytes_per_line);
6107914d74bSmrg	core.msk_image = XCreateImage (dpy, NULL, 1, ZPixmap,
6117914d74bSmrg				       0, NULL, image->width, image->height,
6127914d74bSmrg				       32, 0);
6137914d74bSmrg	core.msk_image->data = Xmalloc (image->height *
6147914d74bSmrg					core.msk_image->bytes_per_line);
6157914d74bSmrg
6167914d74bSmrg	switch (info->dither) {
6177914d74bSmrg	case XcursorDitherThreshold:
6187914d74bSmrg	    if (!_XcursorThreshold (image, &core))
6197914d74bSmrg		return 0;
6207914d74bSmrg	    break;
6217914d74bSmrg	case XcursorDitherMedian:
6227914d74bSmrg	    if (!_XcursorHeckbertMedianCut (image, &core))
6237914d74bSmrg		return 0;
6247914d74bSmrg	    break;
6257914d74bSmrg	case XcursorDitherOrdered:
6267914d74bSmrg	    if (!_XcursorBayerOrderedDither (image, &core))
6277914d74bSmrg		return 0;
6287914d74bSmrg	    break;
6297914d74bSmrg	case XcursorDitherDiffuse:
6307914d74bSmrg	    if (!_XcursorFloydSteinberg (image, &core))
6317914d74bSmrg		return 0;
6327914d74bSmrg	    break;
6337914d74bSmrg	default:
6347914d74bSmrg	    return 0;
6357914d74bSmrg	}
6367914d74bSmrg
6377914d74bSmrg	/*
6387914d74bSmrg	 * Create the cursor
6397914d74bSmrg	 */
6407914d74bSmrg	src_pixmap = XCreatePixmap (dpy, RootWindow (dpy, screen),
6417914d74bSmrg				    image->width, image->height, 1);
6427914d74bSmrg	msk_pixmap = XCreatePixmap (dpy, RootWindow (dpy, screen),
6437914d74bSmrg				    image->width, image->height, 1);
6447914d74bSmrg	gcv.foreground = 1;
6457914d74bSmrg	gcv.background = 0;
6467914d74bSmrg	gc = XCreateGC (dpy, src_pixmap,
6477914d74bSmrg			GCForeground|GCBackground,
6487914d74bSmrg			&gcv);
6497914d74bSmrg	XPutImage (dpy, src_pixmap, gc, core.src_image,
6507914d74bSmrg		   0, 0, 0, 0, image->width, image->height);
6517914d74bSmrg
6527914d74bSmrg	XPutImage (dpy, msk_pixmap, gc, core.msk_image,
6537914d74bSmrg		   0, 0, 0, 0, image->width, image->height);
6547914d74bSmrg	XFreeGC (dpy, gc);
6557914d74bSmrg
6567914d74bSmrg#ifdef DEBUG_IMAGE
6577914d74bSmrg	_XcursorDumpColor (&core.on_color, "on_color");
6587914d74bSmrg	_XcursorDumpColor (&core.off_color, "off_color");
6597914d74bSmrg	_XcursorDumpImage (core.src_image);
6607914d74bSmrg	_XcursorDumpImage (core.msk_image);
6617914d74bSmrg#endif
6627914d74bSmrg	XDestroyImage (core.src_image);
6637914d74bSmrg	XDestroyImage (core.msk_image);
6647914d74bSmrg
6657914d74bSmrg	cursor = XCreatePixmapCursor (dpy, src_pixmap, msk_pixmap,
6667914d74bSmrg				      &core.on_color, &core.off_color,
6677914d74bSmrg				      image->xhot, image->yhot);
6687914d74bSmrg	XFreePixmap (dpy, src_pixmap);
6697914d74bSmrg	XFreePixmap (dpy, msk_pixmap);
6707914d74bSmrg    }
6717914d74bSmrg    return cursor;
6727914d74bSmrg}
6737914d74bSmrg
6747914d74bSmrgXcursorCursors *
6757914d74bSmrgXcursorImagesLoadCursors (Display *dpy, const XcursorImages *images)
6767914d74bSmrg{
6777914d74bSmrg    XcursorCursors  *cursors = XcursorCursorsCreate (dpy, images->nimage);
6787914d74bSmrg    int		    n;
6797914d74bSmrg
6807914d74bSmrg    if (!cursors)
6817914d74bSmrg	return NULL;
6827914d74bSmrg    for (n = 0; n < images->nimage; n++)
6837914d74bSmrg    {
6847914d74bSmrg	cursors->cursors[n] = XcursorImageLoadCursor (dpy, images->images[n]);
6857914d74bSmrg	if (!cursors->cursors[n])
6867914d74bSmrg	{
6877914d74bSmrg	    XcursorCursorsDestroy (cursors);
6887914d74bSmrg	    return NULL;
6897914d74bSmrg	}
6907914d74bSmrg	cursors->ncursor++;
6917914d74bSmrg    }
6927914d74bSmrg    return cursors;
6937914d74bSmrg}
6947914d74bSmrg
6957914d74bSmrgCursor
6967914d74bSmrgXcursorImagesLoadCursor (Display *dpy, const XcursorImages *images)
6977914d74bSmrg{
6987914d74bSmrg    Cursor  cursor;
6997914d74bSmrg    if (images->nimage == 1 || !XcursorSupportsAnim (dpy))
7007914d74bSmrg	cursor = XcursorImageLoadCursor (dpy, images->images[0]);
7017914d74bSmrg    else
7027914d74bSmrg    {
7037914d74bSmrg	XcursorCursors	*cursors = XcursorImagesLoadCursors (dpy, images);
7047914d74bSmrg	XAnimCursor	*anim;
7057914d74bSmrg	int		n;
7067914d74bSmrg
7077914d74bSmrg	if (!cursors)
7087914d74bSmrg	    return 0;
7097914d74bSmrg	anim = malloc (cursors->ncursor * sizeof (XAnimCursor));
7107914d74bSmrg	if (!anim)
7117914d74bSmrg	{
7127914d74bSmrg	    XcursorCursorsDestroy (cursors);
7137914d74bSmrg	    return 0;
7147914d74bSmrg	}
7157914d74bSmrg	for (n = 0; n < cursors->ncursor; n++)
7167914d74bSmrg	{
7177914d74bSmrg	    anim[n].cursor = cursors->cursors[n];
7187914d74bSmrg	    anim[n].delay = images->images[n]->delay;
7197914d74bSmrg	}
7207914d74bSmrg	cursor = XRenderCreateAnimCursor (dpy, cursors->ncursor, anim);
7217914d74bSmrg	XcursorCursorsDestroy(cursors);
7227914d74bSmrg	free (anim);
7237914d74bSmrg    }
7247914d74bSmrg#if defined HAVE_XFIXES && XFIXES_MAJOR >= 2
7257914d74bSmrg    if (images->name)
7267914d74bSmrg	XFixesSetCursorName (dpy, cursor, images->name);
7277914d74bSmrg#endif
7287914d74bSmrg    return cursor;
7297914d74bSmrg}
7307914d74bSmrg
7317914d74bSmrg
7327914d74bSmrgCursor
7337914d74bSmrgXcursorFilenameLoadCursor (Display *dpy, const char *file)
7347914d74bSmrg{
7357914d74bSmrg    int		    size = XcursorGetDefaultSize (dpy);
7367914d74bSmrg    XcursorImages   *images = XcursorFilenameLoadImages (file, size);
7377914d74bSmrg    Cursor	    cursor;
7387914d74bSmrg
7397914d74bSmrg    if (!images)
7407914d74bSmrg	return None;
7417914d74bSmrg    cursor = XcursorImagesLoadCursor (dpy, images);
7427914d74bSmrg    XcursorImagesDestroy (images);
7437914d74bSmrg    return cursor;
7447914d74bSmrg}
7457914d74bSmrg
7467914d74bSmrgXcursorCursors *
7477914d74bSmrgXcursorFilenameLoadCursors (Display *dpy, const char *file)
7487914d74bSmrg{
7497914d74bSmrg    int		    size = XcursorGetDefaultSize (dpy);
7507914d74bSmrg    XcursorImages   *images = XcursorFilenameLoadImages (file, size);
7517914d74bSmrg    XcursorCursors  *cursors;
7527914d74bSmrg
7537914d74bSmrg    if (!images)
7547914d74bSmrg	return NULL;
7557914d74bSmrg    cursors = XcursorImagesLoadCursors (dpy, images);
7567914d74bSmrg    XcursorImagesDestroy (images);
7577914d74bSmrg    return cursors;
7587914d74bSmrg}
7597914d74bSmrg
7607914d74bSmrg/*
7617914d74bSmrg * Stolen from XCreateGlyphCursor (which we cruelly override)
7627914d74bSmrg */
7637914d74bSmrg
7647914d74bSmrgCursor
7657914d74bSmrg_XcursorCreateGlyphCursor(Display	    *dpy,
7667914d74bSmrg			  Font		    source_font,
7677914d74bSmrg			  Font		    mask_font,
7687914d74bSmrg			  unsigned int	    source_char,
7697914d74bSmrg			  unsigned int	    mask_char,
7707914d74bSmrg			  XColor _Xconst    *foreground,
7717914d74bSmrg			  XColor _Xconst    *background)
7727914d74bSmrg{
7737914d74bSmrg    Cursor cid;
7747914d74bSmrg    register xCreateGlyphCursorReq *req;
7757914d74bSmrg
7767914d74bSmrg    LockDisplay(dpy);
7777914d74bSmrg    GetReq(CreateGlyphCursor, req);
7787914d74bSmrg    cid = req->cid = XAllocID(dpy);
7797914d74bSmrg    req->source = source_font;
7807914d74bSmrg    req->mask = mask_font;
7817914d74bSmrg    req->sourceChar = source_char;
7827914d74bSmrg    req->maskChar = mask_char;
7837914d74bSmrg    req->foreRed = foreground->red;
7847914d74bSmrg    req->foreGreen = foreground->green;
7857914d74bSmrg    req->foreBlue = foreground->blue;
7867914d74bSmrg    req->backRed = background->red;
7877914d74bSmrg    req->backGreen = background->green;
7887914d74bSmrg    req->backBlue = background->blue;
7897914d74bSmrg    UnlockDisplay(dpy);
7907914d74bSmrg    SyncHandle();
7917914d74bSmrg    return (cid);
7927914d74bSmrg}
7937914d74bSmrg
7947914d74bSmrg/*
7957914d74bSmrg * Stolen from XCreateFontCursor (which we cruelly override)
7967914d74bSmrg */
7977914d74bSmrg
7987914d74bSmrgCursor
7997914d74bSmrg_XcursorCreateFontCursor (Display *dpy, unsigned int shape)
8007914d74bSmrg{
8017914d74bSmrg    static XColor _Xconst foreground = { 0,    0,     0,     0  };  /* black */
8027914d74bSmrg    static XColor _Xconst background = { 0, 65535, 65535, 65535 };  /* white */
8037914d74bSmrg
8047914d74bSmrg    /*
8057914d74bSmrg     * the cursor font contains the shape glyph followed by the mask
8067914d74bSmrg     * glyph; so character position 0 contains a shape, 1 the mask for 0,
8077914d74bSmrg     * 2 a shape, etc.  <X11/cursorfont.h> contains hash define names
8087914d74bSmrg     * for all of these.
8097914d74bSmrg     */
8107914d74bSmrg
8117914d74bSmrg    if (dpy->cursor_font == None)
8127914d74bSmrg    {
8137914d74bSmrg	dpy->cursor_font = XLoadFont (dpy, CURSORFONT);
8147914d74bSmrg	if (dpy->cursor_font == None)
8157914d74bSmrg	    return None;
8167914d74bSmrg    }
8177914d74bSmrg
8187914d74bSmrg    return _XcursorCreateGlyphCursor (dpy, dpy->cursor_font, dpy->cursor_font,
8197914d74bSmrg				      shape, shape + 1, &foreground, &background);
8207914d74bSmrg}
8217914d74bSmrg
822