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