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