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