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, ¢erColor) >= 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