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