cursor.c revision 4d939ec7
1/*
2 * Copyright © 2002 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Keith Packard not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission.  Keith Packard makes no
11 * representations about the suitability of this software for any purpose.  It
12 * is provided "as is" without express or implied warranty.
13 *
14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#include "xcursorint.h"
24#include <X11/Xlibint.h>
25#include <X11/Xutil.h>
26
27XcursorCursors *
28XcursorCursorsCreate (Display *dpy, int size)
29{
30    XcursorCursors  *cursors;
31
32    cursors = malloc (sizeof (XcursorCursors) +
33		      (size_t) size * sizeof (Cursor));
34    if (!cursors)
35	return NULL;
36    cursors->ref = 1;
37    cursors->dpy = dpy;
38    cursors->ncursor = 0;
39    cursors->cursors = (Cursor *) (cursors + 1);
40    return cursors;
41}
42
43void
44XcursorCursorsDestroy (XcursorCursors *cursors)
45{
46    int	    n;
47
48    if (!cursors)
49      return;
50
51    --cursors->ref;
52    if (cursors->ref > 0)
53	return;
54
55    for (n = 0; n < cursors->ncursor; n++)
56	XFreeCursor (cursors->dpy, cursors->cursors[n]);
57    free (cursors);
58}
59
60XcursorAnimate *
61XcursorAnimateCreate (XcursorCursors *cursors)
62{
63    XcursorAnimate  *animate;
64
65    animate = malloc (sizeof (XcursorAnimate));
66    if (!animate)
67	return NULL;
68    animate->cursors = cursors;
69    cursors->ref++;
70    animate->sequence = 0;
71    return animate;
72}
73
74void
75XcursorAnimateDestroy (XcursorAnimate *animate)
76{
77    if (!animate)
78      return;
79
80    XcursorCursorsDestroy (animate->cursors);
81    free (animate);
82}
83
84Cursor
85XcursorAnimateNext (XcursorAnimate *animate)
86{
87    Cursor  cursor = animate->cursors->cursors[animate->sequence++];
88
89    if (animate->sequence >= animate->cursors->ncursor)
90	animate->sequence = 0;
91    return cursor;
92}
93
94#if RENDER_MAJOR > 0 || RENDER_MINOR >= 5
95static int
96nativeByteOrder (void)
97{
98    int	x = 1;
99
100    return (*((char *) &x) == 1) ? LSBFirst : MSBFirst;
101}
102#endif
103
104static XcursorUInt
105_XcursorPixelBrightness (XcursorPixel p)
106{
107    XcursorPixel    alpha = p >> 24;
108    XcursorPixel    r, g, b;
109
110    if (!alpha)
111	return 0;
112    r = ((p >> 8) & 0xff00) / alpha;
113    if (r > 0xff) r = 0xff;
114    g = ((p >> 0) & 0xff00) / alpha;
115    if (g > 0xff) g = 0xff;
116    b = ((p << 8) & 0xff00) / alpha;
117    if (b > 0xff) b = 0xff;
118    return (r * 153 + g * 301 + b * 58) >> 9;
119}
120
121static unsigned short
122_XcursorDivideAlpha (XcursorUInt value, XcursorUInt alpha)
123{
124    if (!alpha)
125	return 0;
126    value = value * 255 / alpha;
127    if (value > 255)
128	value = 255;
129    return (unsigned short) (value | (value << 8));
130}
131
132static void
133_XcursorPixelToColor (XcursorPixel p, XColor *color)
134{
135    XcursorPixel    alpha = p >> 24;
136
137    color->pixel = 0;
138    color->red =   _XcursorDivideAlpha ((p >> 16) & 0xff, alpha);
139    color->green = _XcursorDivideAlpha ((p >>  8) & 0xff, alpha);
140    color->blue =  _XcursorDivideAlpha ((p >>  0) & 0xff, alpha);
141    color->flags = DoRed|DoGreen|DoBlue;
142}
143
144#undef DEBUG_IMAGE
145#ifdef DEBUG_IMAGE
146static void
147_XcursorDumpImage (XImage *image)
148{
149    FILE    *f = fopen ("/tmp/images", "a");
150    int	    x, y;
151    if (!f)
152	return;
153    fprintf (f, "%d x %x\n", image->width, image->height);
154    for (y = 0; y < image->height; y++)
155    {
156	for (x = 0; x < image->width; x++)
157	    fprintf (f, "%c", XGetPixel (image, x, y) ? '*' : ' ');
158	fprintf (f, "\n");
159    }
160    fflush (f);
161    fclose (f);
162}
163
164static void
165_XcursorDumpColor (XColor *color, char *name)
166{
167    FILE    *f = fopen ("/tmp/images", "a");
168    fprintf (f, "%s: %x %x %x\n", name,
169	     color->red, color->green, color->blue);
170    fflush (f);
171    fclose (f);
172}
173#endif
174
175static int
176_XcursorCompareRed (const void *a, const void *b)
177{
178    const XcursorPixel    *ap = a, *bp = b;
179
180    return (int) (((*ap >> 16) & 0xff) - ((*bp >> 16) & 0xff));
181}
182
183static int
184_XcursorCompareGreen (const void *a, const void *b)
185{
186    const XcursorPixel    *ap = a, *bp = b;
187
188    return (int) (((*ap >> 8) & 0xff) - ((*bp >> 8) & 0xff));
189}
190
191static int
192_XcursorCompareBlue (const void *a, const void *b)
193{
194    const XcursorPixel    *ap = a, *bp = b;
195
196    return (int) (((*ap >> 0) & 0xff) - ((*bp >> 0) & 0xff));
197}
198
199#define ScaledPixels(c,n) ((c)/(XcursorPixel)(n))
200
201static XcursorPixel
202_XcursorAverageColor (XcursorPixel *pixels, int npixels)
203{
204    XcursorPixel    p;
205    XcursorPixel    red, green, blue;
206    int		    n = npixels;
207
208    if (n < 1)
209	return 0;
210
211    blue = green = red = 0;
212    while (n--)
213    {
214	p = *pixels++;
215	red += (p >> 16) & 0xff;
216	green += (p >> 8) & 0xff;
217	blue += (p >> 0) & 0xff;
218    }
219    return (0xffU << 24)
220	    | (ScaledPixels(red, npixels) << 16)
221	    | (ScaledPixels(green, npixels) << 8)
222	    |  ScaledPixels(blue, npixels);
223}
224
225typedef struct XcursorCoreCursor {
226    XImage  *src_image;
227    XImage  *msk_image;
228    XColor  on_color;
229    XColor  off_color;
230} XcursorCoreCursor;
231
232static Bool
233_XcursorHeckbertMedianCut (const XcursorImage *image, XcursorCoreCursor *core)
234{
235    XImage	    *src_image = core->src_image, *msk_image = core->msk_image;
236    unsigned int    npixels = image->width * image->height;
237    int		    ncolors;
238    int		    n;
239    XcursorPixel    *po, *pn, *pc;
240    XcursorPixel    p;
241    XcursorPixel    red, green, blue, alpha;
242    XcursorPixel    max_red, min_red, max_green, min_green, max_blue, min_blue;
243    XcursorPixel    *temp, *pixels, *colors;
244    int		    split;
245    XcursorPixel    leftColor, centerColor, rightColor;
246    int		    (*compare) (const void *, const void *);
247    int		    x, y;
248
249    /*
250     * Temp space for converted image and converted colors
251     */
252    temp = malloc (npixels * sizeof (XcursorPixel) * 2);
253    if (!temp)
254	return False;
255
256    pixels = temp;
257    colors = pixels + npixels;
258
259    /*
260     * Convert to 2-value alpha and build
261     * array of opaque color values and an
262     */
263    po = image->pixels;
264    pn = pixels;
265    pc = colors;
266    max_blue = max_green = max_red = 0;
267    min_blue = min_green = min_red = 255;
268    n = (int) npixels;
269    while (n--)
270    {
271	p = *po++;
272	alpha = (p >> 24) & 0xff;
273	red = (p >> 16) & 0xff;
274	green = (p >> 8) & 0xff;
275	blue = (p >> 0) & 0xff;
276	if (alpha >= 0x80)
277	{
278	    red = red * 255 / alpha;
279	    green = green * 255 / alpha;
280	    blue = blue * 255 / alpha;
281	    if (red < min_red) min_red = red;
282	    if (red > max_red) max_red = red;
283	    if (green < min_green) min_green = green;
284	    if (green > max_green) max_green = green;
285	    if (blue < min_blue) min_blue = blue;
286	    if (blue > max_blue) max_blue = blue;
287	    p = ((0xffU << 24) | (red << 16) |
288		 (green << 8) | (blue << 0));
289	    *pc++ = p;
290	}
291	else
292	    p = 0;
293	*pn++ = p;
294    }
295    ncolors = (int) (pc - colors);
296
297    /*
298     * Compute longest dimension and sort
299     */
300    if ((max_green - min_green) >= (max_red - min_red) &&
301	(max_green - min_green) >= (max_blue - min_blue))
302	compare = _XcursorCompareGreen;
303    else if ((max_red - min_red) >= (max_blue - min_blue))
304	compare = _XcursorCompareRed;
305    else
306	compare = _XcursorCompareBlue;
307    qsort (colors, (size_t) ncolors, sizeof (XcursorPixel), compare);
308    /*
309     * Compute average colors on both sides of the cut
310     */
311    split = ncolors >> 1;
312    leftColor  = _XcursorAverageColor (colors, split);
313    centerColor = colors[split];
314    rightColor = _XcursorAverageColor (colors + split, ncolors - split);
315    /*
316     * Select best color for each pixel
317     */
318    pn = pixels;
319    for (y = 0; (unsigned) y < image->height; y++)
320	for (x = 0; (unsigned) x < image->width; x++)
321	{
322	    p = *pn++;
323	    if (p & 0xff000000)
324	    {
325		XPutPixel (msk_image, x, y, 1);
326		if ((*compare) (&p, &centerColor) >= 0)
327		    XPutPixel (src_image, x, y, 0);
328		else
329		    XPutPixel (src_image, x, y, 1);
330	    }
331	    else
332	    {
333		XPutPixel (msk_image, x, y, 0);
334		XPutPixel (src_image, x, y, 0);
335	    }
336	}
337    free (temp);
338    _XcursorPixelToColor (rightColor, &core->off_color);
339    _XcursorPixelToColor (leftColor, &core->on_color);
340    return True;
341}
342
343#if 0
344#define DITHER_DIM  4
345static XcursorPixel orderedDither[4][4] = {
346    {  1,  9,  3, 11 },
347    { 13,  5, 15,  7 },
348    {  4, 12,  2, 10 },
349    { 16,  8, 14,  6 }
350};
351#else
352#define DITHER_DIM 2
353static XcursorPixel orderedDither[2][2] = {
354    {  1,  3,  },
355    {  4,  2,  },
356};
357#endif
358
359#define DITHER_SIZE  ((sizeof orderedDither / sizeof orderedDither[0][0]) + 1)
360
361static Bool
362_XcursorBayerOrderedDither (const XcursorImage *image, XcursorCoreCursor *core)
363{
364    int		    x, y;
365    XcursorPixel    *pixel, p;
366    XcursorPixel    a, i, d;
367
368    pixel = image->pixels;
369    for (y = 0; (unsigned) y < image->height; y++)
370	for (x = 0; (unsigned) x < image->width; x++)
371	{
372	    p = *pixel++;
373	    a = (XcursorPixel) (((p >> 24) * DITHER_SIZE + 127) / 255);
374	    i = (XcursorPixel) ((_XcursorPixelBrightness (p) * DITHER_SIZE + 127) / 255);
375	    d = orderedDither[y&(DITHER_DIM-1)][x&(DITHER_DIM-1)];
376	    if (a > d)
377	    {
378		XPutPixel (core->msk_image, x, y, 1);
379		if (i > d)
380		    XPutPixel (core->src_image, x, y, 0);   /* white */
381		else
382		    XPutPixel (core->src_image, x, y, 1);   /* black */
383	    }
384	    else
385	    {
386		XPutPixel (core->msk_image, x, y, 0);
387		XPutPixel (core->src_image, x, y, 0);
388	    }
389	}
390    core->on_color.red = 0;
391    core->on_color.green = 0;
392    core->on_color.blue = 0;
393    core->off_color.red = 0xffff;
394    core->off_color.green = 0xffff;
395    core->off_color.blue = 0xffff;
396    return True;
397}
398
399static Bool
400_XcursorFloydSteinberg (const XcursorImage *image, XcursorCoreCursor *core)
401{
402    int		    *aPicture, *iPicture, *aP, *iP;
403    XcursorPixel    *pixel, p;
404    int		    aR, iR, aA, iA;
405    unsigned int    npixels = image->width * image->height;
406    int		    n;
407    int		    right = 1;
408    int		    belowLeft = (int) (image->width - 1);
409    int		    below = (int) image->width;
410    int		    belowRight = (int) (image->width + 1);
411    int		    iError, aError;
412    int		    iErrorRight, aErrorRight;
413    int		    iErrorBelowLeft, aErrorBelowLeft;
414    int		    iErrorBelow, aErrorBelow;
415    int		    iErrorBelowRight, aErrorBelowRight;
416    int		    x, y;
417    int		    max_inten, min_inten, mean_inten;
418
419    iPicture = malloc (npixels * sizeof (int) * 2);
420    if (!iPicture)
421	return False;
422    aPicture = iPicture + npixels;
423
424    /*
425     * Compute raw gray and alpha arrays
426     */
427    pixel = image->pixels;
428    iP = iPicture;
429    aP = aPicture;
430    n = (int) npixels;
431    max_inten = 0;
432    min_inten = 0xff;
433    while (n-- > 0)
434    {
435	p = *pixel++;
436	*aP++ = (int) (p >> 24);
437	iR = (int) _XcursorPixelBrightness (p);
438	if (iR > max_inten) max_inten = iR;
439	if (iR < min_inten) min_inten = iR;
440	*iP++ = iR;
441    }
442    /*
443     * Draw the image while diffusing the error
444     */
445    iP = iPicture;
446    aP = aPicture;
447    mean_inten = (max_inten + min_inten + 1) >> 1;
448    for (y = 0; (unsigned) y < image->height; y++)
449	for (x = 0; (unsigned) x < image->width; x++)
450	{
451	    aR = *aP;
452	    iR = *iP;
453	    if (aR >= 0x80)
454	    {
455		XPutPixel (core->msk_image, x, y, 1);
456		aA = 0xff;
457	    }
458	    else
459	    {
460		XPutPixel (core->msk_image, x, y, 0);
461		aA = 0x00;
462	    }
463	    if (iR >= mean_inten)
464	    {
465		XPutPixel (core->src_image, x, y, 0);
466		iA = max_inten;
467	    }
468	    else
469	    {
470		XPutPixel (core->src_image, x, y, 1);
471		iA = min_inten;
472	    }
473	    iError = iR - iA;
474	    aError = aR - aA;
475	    iErrorRight = (iError * 7) >> 4;
476	    iErrorBelowLeft = (iError * 3) >> 4;
477	    iErrorBelow = (iError * 5) >> 4;
478	    iErrorBelowRight = (iError - iErrorRight -
479				iErrorBelowLeft - iErrorBelow);
480	    aErrorRight = (aError * 7) >> 4;
481	    aErrorBelowLeft = (aError * 3) >> 4;
482	    aErrorBelow = (aError * 5) >> 4;
483	    aErrorBelowRight = (aError - aErrorRight -
484				aErrorBelowLeft - aErrorBelow);
485	    if (x < ((int)image->width - 1))
486	    {
487		iP[right] += iErrorRight;
488		aP[right] += aErrorRight;
489	    }
490	    if (y < ((int)image->height - 1))
491	    {
492		if (x)
493		{
494		    iP[belowLeft] += iErrorBelowLeft;
495		    aP[belowLeft] += aErrorBelowLeft;
496		}
497		iP[below] += iErrorBelow;
498		aP[below] += aErrorBelow;
499		if (x < ((int)image->width - 1))
500		{
501		    iP[belowRight] += iErrorBelowRight;
502		    aP[belowRight] += aErrorBelowRight;
503		}
504	    }
505	    aP++;
506	    iP++;
507	}
508    free (iPicture);
509    core->on_color.red =
510    core->on_color.green =
511    core->on_color.blue = (unsigned short) (min_inten | min_inten << 8);
512    core->off_color.red =
513    core->off_color.green =
514    core->off_color.blue = (unsigned short) (max_inten | max_inten << 8);
515    return True;
516}
517
518static Bool
519_XcursorThreshold (const XcursorImage *image, XcursorCoreCursor *core)
520{
521    XcursorPixel    *pixel, p;
522    int		    x, y;
523
524    /*
525     * Draw the image, picking black for dark pixels and white for light
526     */
527    pixel = image->pixels;
528    for (y = 0; (unsigned) y < image->height; y++)
529	for (x = 0; (unsigned) x < image->width; x++)
530	{
531	    p = *pixel++;
532	    if ((p >> 24) >= 0x80)
533	    {
534		XPutPixel (core->msk_image, x, y, 1);
535		if (_XcursorPixelBrightness (p) > 0x80)
536		    XPutPixel (core->src_image, x, y, 0);
537		else
538		    XPutPixel (core->src_image, x, y, 1);
539	    }
540	    else
541	    {
542		XPutPixel (core->msk_image, x, y, 0);
543		XPutPixel (core->src_image, x, y, 0);
544	    }
545	}
546    core->on_color.red =
547    core->on_color.green =
548    core->on_color.blue = 0;
549    core->off_color.red =
550    core->off_color.green =
551    core->off_color.blue = 0xffff;
552    return True;
553}
554
555Cursor
556XcursorImageLoadCursor (Display *dpy, const XcursorImage *image)
557{
558    Cursor  cursor;
559
560#if RENDER_MAJOR > 0 || RENDER_MINOR >= 5
561    if (XcursorSupportsARGB (dpy))
562    {
563	XImage		    ximage;
564	int		    screen = DefaultScreen (dpy);
565	Pixmap		    pixmap;
566	Picture		    picture;
567	GC		    gc;
568	XRenderPictFormat   *format;
569
570	ximage.width = (int) image->width;
571	ximage.height = (int) image->height;
572	ximage.xoffset = 0;
573	ximage.format = ZPixmap;
574	ximage.data = (char *) image->pixels;
575	ximage.byte_order = nativeByteOrder ();
576	ximage.bitmap_unit = 32;
577	ximage.bitmap_bit_order = ximage.byte_order;
578	ximage.bitmap_pad = 32;
579	ximage.depth = 32;
580	ximage.bits_per_pixel = 32;
581	ximage.bytes_per_line = (int) (image->width * 4);
582	ximage.red_mask = 0xff0000;
583	ximage.green_mask = 0x00ff00;
584	ximage.blue_mask = 0x0000ff;
585	ximage.obdata = NULL;
586	if (!XInitImage (&ximage))
587	    return None;
588	pixmap = XCreatePixmap (dpy, RootWindow (dpy, screen),
589				image->width, image->height, 32);
590	gc = XCreateGC (dpy, pixmap, 0, NULL);
591	XPutImage (dpy, pixmap, gc, &ximage,
592		   0, 0, 0, 0, image->width, image->height);
593	XFreeGC (dpy, gc);
594	format = XRenderFindStandardFormat (dpy, PictStandardARGB32);
595	picture = XRenderCreatePicture (dpy, pixmap, format, 0, NULL);
596	XFreePixmap (dpy, pixmap);
597	cursor = XRenderCreateCursor (dpy, picture,
598				      image->xhot, image->yhot);
599	XRenderFreePicture (dpy, picture);
600    }
601    else
602#endif
603    {
604	XcursorDisplayInfo  *info = _XcursorGetDisplayInfo (dpy);
605	int		    screen = DefaultScreen (dpy);
606	XcursorCoreCursor   core;
607	Pixmap		    src_pixmap, msk_pixmap;
608	GC		    gc;
609	XGCValues	    gcv;
610
611	if (!info)
612	    return 0;
613
614	core.src_image = XCreateImage (dpy, NULL, 1, ZPixmap,
615				       0, NULL, image->width, image->height,
616				       32, 0);
617	core.src_image->data = Xmalloc (image->height *
618					(unsigned) core.src_image->bytes_per_line);
619	core.msk_image = XCreateImage (dpy, NULL, 1, ZPixmap,
620				       0, NULL, image->width, image->height,
621				       32, 0);
622	core.msk_image->data = Xmalloc (image->height *
623					(unsigned) core.msk_image->bytes_per_line);
624
625	switch (info->dither) {
626	case XcursorDitherThreshold:
627	    if (!_XcursorThreshold (image, &core))
628		return 0;
629	    break;
630	case XcursorDitherMedian:
631	    if (!_XcursorHeckbertMedianCut (image, &core))
632		return 0;
633	    break;
634	case XcursorDitherOrdered:
635	    if (!_XcursorBayerOrderedDither (image, &core))
636		return 0;
637	    break;
638	case XcursorDitherDiffuse:
639	    if (!_XcursorFloydSteinberg (image, &core))
640		return 0;
641	    break;
642	default:
643	    return 0;
644	}
645
646	/*
647	 * Create the cursor
648	 */
649	src_pixmap = XCreatePixmap (dpy, RootWindow (dpy, screen),
650				    image->width, image->height, 1);
651	msk_pixmap = XCreatePixmap (dpy, RootWindow (dpy, screen),
652				    image->width, image->height, 1);
653	gcv.foreground = 1;
654	gcv.background = 0;
655	gc = XCreateGC (dpy, src_pixmap,
656			GCForeground|GCBackground,
657			&gcv);
658	XPutImage (dpy, src_pixmap, gc, core.src_image,
659		   0, 0, 0, 0, image->width, image->height);
660
661	XPutImage (dpy, msk_pixmap, gc, core.msk_image,
662		   0, 0, 0, 0, image->width, image->height);
663	XFreeGC (dpy, gc);
664
665#ifdef DEBUG_IMAGE
666	_XcursorDumpColor (&core.on_color, "on_color");
667	_XcursorDumpColor (&core.off_color, "off_color");
668	_XcursorDumpImage (core.src_image);
669	_XcursorDumpImage (core.msk_image);
670#endif
671	XDestroyImage (core.src_image);
672	XDestroyImage (core.msk_image);
673
674	cursor = XCreatePixmapCursor (dpy, src_pixmap, msk_pixmap,
675				      &core.on_color, &core.off_color,
676				      image->xhot, image->yhot);
677	XFreePixmap (dpy, src_pixmap);
678	XFreePixmap (dpy, msk_pixmap);
679    }
680    return cursor;
681}
682
683XcursorCursors *
684XcursorImagesLoadCursors (Display *dpy, const XcursorImages *images)
685{
686    XcursorCursors  *cursors = XcursorCursorsCreate (dpy, images->nimage);
687    int		    n;
688
689    if (!cursors)
690	return NULL;
691    for (n = 0; n < images->nimage; n++)
692    {
693	cursors->cursors[n] = XcursorImageLoadCursor (dpy, images->images[n]);
694	if (!cursors->cursors[n])
695	{
696	    XcursorCursorsDestroy (cursors);
697	    return NULL;
698	}
699	cursors->ncursor++;
700    }
701    return cursors;
702}
703
704Cursor
705XcursorImagesLoadCursor (Display *dpy, const XcursorImages *images)
706{
707    Cursor  cursor;
708    if (images->nimage == 1 || !XcursorSupportsAnim (dpy))
709	cursor = XcursorImageLoadCursor (dpy, images->images[0]);
710    else
711    {
712	XcursorCursors	*cursors = XcursorImagesLoadCursors (dpy, images);
713	XAnimCursor	*anim;
714	int		n;
715
716	if (!cursors)
717	    return 0;
718	anim = malloc ((size_t) cursors->ncursor * sizeof (XAnimCursor));
719	if (!anim)
720	{
721	    XcursorCursorsDestroy (cursors);
722	    return 0;
723	}
724	for (n = 0; n < cursors->ncursor; n++)
725	{
726	    anim[n].cursor = cursors->cursors[n];
727	    anim[n].delay = images->images[n]->delay;
728	}
729	cursor = XRenderCreateAnimCursor (dpy, cursors->ncursor, anim);
730	XcursorCursorsDestroy(cursors);
731	free (anim);
732    }
733#if defined HAVE_XFIXES && XFIXES_MAJOR >= 2
734    if (images->name)
735	XFixesSetCursorName (dpy, cursor, images->name);
736#endif
737    return cursor;
738}
739
740
741Cursor
742XcursorFilenameLoadCursor (Display *dpy, const char *file)
743{
744    int		    size = XcursorGetDefaultSize (dpy);
745    XcursorImages   *images = XcursorFilenameLoadImages (file, size);
746    Cursor	    cursor;
747
748    if (!images)
749	return None;
750    cursor = XcursorImagesLoadCursor (dpy, images);
751    XcursorImagesDestroy (images);
752    return cursor;
753}
754
755XcursorCursors *
756XcursorFilenameLoadCursors (Display *dpy, const char *file)
757{
758    int		    size = XcursorGetDefaultSize (dpy);
759    XcursorImages   *images = XcursorFilenameLoadImages (file, size);
760    XcursorCursors  *cursors;
761
762    if (!images)
763	return NULL;
764    cursors = XcursorImagesLoadCursors (dpy, images);
765    XcursorImagesDestroy (images);
766    return cursors;
767}
768
769/*
770 * Stolen from XCreateGlyphCursor (which we cruelly override)
771 */
772
773Cursor
774_XcursorCreateGlyphCursor(Display	    *dpy,
775			  Font		    source_font,
776			  Font		    mask_font,
777			  unsigned int	    source_char,
778			  unsigned int	    mask_char,
779			  XColor _Xconst    *foreground,
780			  XColor _Xconst    *background)
781{
782    Cursor cid;
783    register xCreateGlyphCursorReq *req;
784
785    LockDisplay(dpy);
786    GetReq(CreateGlyphCursor, req);
787    cid = req->cid = (CARD32) XAllocID(dpy);
788    req->source = (CARD32) source_font;
789    req->mask = (CARD32) mask_font;
790    req->sourceChar = (CARD16) source_char;
791    req->maskChar = (CARD16) mask_char;
792    req->foreRed = foreground->red;
793    req->foreGreen = foreground->green;
794    req->foreBlue = foreground->blue;
795    req->backRed = background->red;
796    req->backGreen = background->green;
797    req->backBlue = background->blue;
798    UnlockDisplay(dpy);
799    SyncHandle();
800    return (cid);
801}
802
803/*
804 * Stolen from XCreateFontCursor (which we cruelly override)
805 */
806
807Cursor
808_XcursorCreateFontCursor (Display *dpy, unsigned int shape)
809{
810#define DATA(c) { 0UL, c, c, c, 0, 0 }
811    static XColor _Xconst foreground = DATA(0);  /* black */
812    static XColor _Xconst background = DATA(65535);  /* white */
813#undef DATA
814
815    /*
816     * the cursor font contains the shape glyph followed by the mask
817     * glyph; so character position 0 contains a shape, 1 the mask for 0,
818     * 2 a shape, etc.  <X11/cursorfont.h> contains hash define names
819     * for all of these.
820     */
821
822    if (dpy->cursor_font == None)
823    {
824	dpy->cursor_font = XLoadFont (dpy, CURSORFONT);
825	if (dpy->cursor_font == None)
826	    return None;
827    }
828
829    return _XcursorCreateGlyphCursor (dpy, dpy->cursor_font, dpy->cursor_font,
830				      shape, shape + 1, &foreground, &background);
831}
832
833