library.c revision 9d0ccd10
17914d74bSmrg/*
27914d74bSmrg * Copyright © 2002 Keith Packard
37914d74bSmrg *
47914d74bSmrg * Permission to use, copy, modify, distribute, and sell this software and its
57914d74bSmrg * documentation for any purpose is hereby granted without fee, provided that
67914d74bSmrg * the above copyright notice appear in all copies and that both that
77914d74bSmrg * copyright notice and this permission notice appear in supporting
87914d74bSmrg * documentation, and that the name of Keith Packard not be used in
97914d74bSmrg * advertising or publicity pertaining to distribution of the software without
107914d74bSmrg * specific, written prior permission.  Keith Packard makes no
117914d74bSmrg * representations about the suitability of this software for any purpose.  It
127914d74bSmrg * is provided "as is" without express or implied warranty.
137914d74bSmrg *
147914d74bSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
157914d74bSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
167914d74bSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
177914d74bSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
187914d74bSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
197914d74bSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
207914d74bSmrg * PERFORMANCE OF THIS SOFTWARE.
217914d74bSmrg */
227914d74bSmrg
237914d74bSmrg#include "xcursorint.h"
247914d74bSmrg#include <stdlib.h>
257914d74bSmrg#include <string.h>
267914d74bSmrg
277914d74bSmrg#ifndef ICONDIR
287914d74bSmrg#define ICONDIR "/usr/X11R6/lib/X11/icons"
297914d74bSmrg#endif
307914d74bSmrg
317914d74bSmrg#ifndef XCURSORPATH
327914d74bSmrg#define XCURSORPATH "~/.icons:/usr/share/icons:/usr/share/pixmaps:"ICONDIR
337914d74bSmrg#endif
347914d74bSmrg
357914d74bSmrgconst char *
367914d74bSmrgXcursorLibraryPath (void)
377914d74bSmrg{
387914d74bSmrg    static const char	*path;
397914d74bSmrg
407914d74bSmrg    if (!path)
417914d74bSmrg    {
427914d74bSmrg	path = getenv ("XCURSOR_PATH");
437914d74bSmrg	if (!path)
447914d74bSmrg	    path = XCURSORPATH;
457914d74bSmrg    }
467914d74bSmrg    return path;
477914d74bSmrg}
487914d74bSmrg
497914d74bSmrgstatic  void
507914d74bSmrg_XcursorAddPathElt (char *path, const char *elt, int len)
517914d74bSmrg{
529d0ccd10Smrg    size_t    pathlen = strlen (path);
53e6d5e4e0Smrg
547914d74bSmrg    /* append / if the path doesn't currently have one */
557914d74bSmrg    if (path[0] == '\0' || path[pathlen - 1] != '/')
567914d74bSmrg    {
577914d74bSmrg	strcat (path, "/");
587914d74bSmrg	pathlen++;
597914d74bSmrg    }
607914d74bSmrg    if (len == -1)
617914d74bSmrg	len = strlen (elt);
627914d74bSmrg    /* strip leading slashes */
637914d74bSmrg    while (len && elt[0] == '/')
647914d74bSmrg    {
657914d74bSmrg	elt++;
667914d74bSmrg	len--;
677914d74bSmrg    }
687914d74bSmrg    strncpy (path + pathlen, elt, len);
697914d74bSmrg    path[pathlen + len] = '\0';
707914d74bSmrg}
717914d74bSmrg
727914d74bSmrgstatic char *
737914d74bSmrg_XcursorBuildThemeDir (const char *dir, const char *theme)
747914d74bSmrg{
757914d74bSmrg    const char	    *colon;
767914d74bSmrg    const char	    *tcolon;
777914d74bSmrg    char	    *full;
787914d74bSmrg    char	    *home;
797914d74bSmrg    int		    dirlen;
807914d74bSmrg    int		    homelen;
817914d74bSmrg    int		    themelen;
827914d74bSmrg    int		    len;
837914d74bSmrg
847914d74bSmrg    if (!dir || !theme)
857914d74bSmrg        return NULL;
86e6d5e4e0Smrg
877914d74bSmrg    colon = strchr (dir, ':');
887914d74bSmrg    if (!colon)
897914d74bSmrg	colon = dir + strlen (dir);
90e6d5e4e0Smrg
917914d74bSmrg    dirlen = colon - dir;
927914d74bSmrg
937914d74bSmrg    tcolon = strchr (theme, ':');
947914d74bSmrg    if (!tcolon)
957914d74bSmrg	tcolon = theme + strlen (theme);
967914d74bSmrg
977914d74bSmrg    themelen = tcolon - theme;
98e6d5e4e0Smrg
997914d74bSmrg    home = NULL;
1007914d74bSmrg    homelen = 0;
1017914d74bSmrg    if (*dir == '~')
1027914d74bSmrg    {
1037914d74bSmrg	home = getenv ("HOME");
1047914d74bSmrg	if (!home)
1057914d74bSmrg	    return NULL;
1067914d74bSmrg	homelen = strlen (home);
1077914d74bSmrg	dir++;
1087914d74bSmrg	dirlen--;
1097914d74bSmrg    }
1107914d74bSmrg
1117914d74bSmrg    /*
1127914d74bSmrg     * add space for any needed directory separators, one per component,
1137914d74bSmrg     * and one for the trailing null
1147914d74bSmrg     */
1157914d74bSmrg    len = 1 + homelen + 1 + dirlen + 1 + themelen + 1;
116e6d5e4e0Smrg
1177914d74bSmrg    full = malloc (len);
1187914d74bSmrg    if (!full)
1197914d74bSmrg	return NULL;
1207914d74bSmrg    full[0] = '\0';
1217914d74bSmrg
1227914d74bSmrg    if (home)
1237914d74bSmrg	_XcursorAddPathElt (full, home, -1);
1247914d74bSmrg    _XcursorAddPathElt (full, dir, dirlen);
1257914d74bSmrg    _XcursorAddPathElt (full, theme, themelen);
1267914d74bSmrg    return full;
1277914d74bSmrg}
1287914d74bSmrg
1297914d74bSmrgstatic char *
1307914d74bSmrg_XcursorBuildFullname (const char *dir, const char *subdir, const char *file)
1317914d74bSmrg{
1327914d74bSmrg    char    *full;
1337914d74bSmrg
1347914d74bSmrg    if (!dir || !subdir || !file)
1357914d74bSmrg        return NULL;
1367914d74bSmrg
1377914d74bSmrg    full = malloc (strlen (dir) + 1 + strlen (subdir) + 1 + strlen (file) + 1);
1387914d74bSmrg    if (!full)
1397914d74bSmrg	return NULL;
1407914d74bSmrg    full[0] = '\0';
1417914d74bSmrg    _XcursorAddPathElt (full, dir, -1);
1427914d74bSmrg    _XcursorAddPathElt (full, subdir, -1);
1437914d74bSmrg    _XcursorAddPathElt (full, file, -1);
1447914d74bSmrg    return full;
1457914d74bSmrg}
1467914d74bSmrg
1477914d74bSmrgstatic const char *
1487914d74bSmrg_XcursorNextPath (const char *path)
1497914d74bSmrg{
1507914d74bSmrg    char    *colon = strchr (path, ':');
1517914d74bSmrg
1527914d74bSmrg    if (!colon)
1537914d74bSmrg	return NULL;
1547914d74bSmrg    return colon + 1;
1557914d74bSmrg}
1567914d74bSmrg
1577914d74bSmrg#define XcursorWhite(c)	((c) == ' ' || (c) == '\t' || (c) == '\n')
1587914d74bSmrg#define XcursorSep(c) ((c) == ';' || (c) == ',')
1597914d74bSmrg
1607914d74bSmrgstatic char *
1617914d74bSmrg_XcursorThemeInherits (const char *full)
1627914d74bSmrg{
1637914d74bSmrg    char    line[8192];
1647914d74bSmrg    char    *result = NULL;
1657914d74bSmrg    FILE    *f;
1667914d74bSmrg
1677914d74bSmrg    if (!full)
1687914d74bSmrg        return NULL;
1697914d74bSmrg
1707914d74bSmrg    f = fopen (full, "r");
1717914d74bSmrg    if (f)
1727914d74bSmrg    {
1737914d74bSmrg	while (fgets (line, sizeof (line), f))
1747914d74bSmrg	{
1757914d74bSmrg	    if (!strncmp (line, "Inherits", 8))
1767914d74bSmrg	    {
1777914d74bSmrg		char    *l = line + 8;
1787914d74bSmrg		char    *r;
1797914d74bSmrg		while (*l == ' ') l++;
1807914d74bSmrg		if (*l != '=') continue;
1817914d74bSmrg		l++;
1827914d74bSmrg		while (*l == ' ') l++;
1839d0ccd10Smrg		result = malloc (strlen (l) + 1);
1847914d74bSmrg		if (result)
1857914d74bSmrg		{
1867914d74bSmrg		    r = result;
187e6d5e4e0Smrg		    while (*l)
1887914d74bSmrg		    {
1897914d74bSmrg			while (XcursorSep(*l) || XcursorWhite (*l)) l++;
1907914d74bSmrg			if (!*l)
1917914d74bSmrg			    break;
1927914d74bSmrg			if (r != result)
1937914d74bSmrg			    *r++ = ':';
194e6d5e4e0Smrg			while (*l && !XcursorWhite(*l) &&
1957914d74bSmrg			       !XcursorSep(*l))
1967914d74bSmrg			    *r++ = *l++;
1977914d74bSmrg		    }
1987914d74bSmrg		    *r++ = '\0';
1997914d74bSmrg		}
2007914d74bSmrg		break;
2017914d74bSmrg	    }
2027914d74bSmrg	}
2037914d74bSmrg	fclose (f);
2047914d74bSmrg    }
2057914d74bSmrg    return result;
2067914d74bSmrg}
2077914d74bSmrg
2087914d74bSmrg#define XCURSOR_SCAN_CORE   ((FILE *) 1)
2097914d74bSmrg
2107914d74bSmrgstatic FILE *
2117914d74bSmrgXcursorScanTheme (const char *theme, const char *name)
2127914d74bSmrg{
2137914d74bSmrg    FILE	*f = NULL;
2147914d74bSmrg    char	*full;
2157914d74bSmrg    char	*dir;
2167914d74bSmrg    const char  *path;
2177914d74bSmrg    char	*inherits = NULL;
2187914d74bSmrg    const char	*i;
2197914d74bSmrg
2207914d74bSmrg    if (!theme || !name)
2217914d74bSmrg        return NULL;
2227914d74bSmrg
2237914d74bSmrg    /*
2247914d74bSmrg     * XCURSOR_CORE_THEME is a magic name; cursors from the core set
2257914d74bSmrg     * are never found in any directory.  Instead, a magic value is
2267914d74bSmrg     * returned which truncates any search so that overlying functions
2277914d74bSmrg     * can switch to equivalent core cursors
2287914d74bSmrg     */
2297914d74bSmrg    if (!strcmp (theme, XCURSOR_CORE_THEME) && XcursorLibraryShape (name) >= 0)
2307914d74bSmrg	return XCURSOR_SCAN_CORE;
2317914d74bSmrg    /*
2327914d74bSmrg     * Scan this theme
2337914d74bSmrg     */
2347914d74bSmrg    for (path = XcursorLibraryPath ();
235e169010aSmrg	 path && f == NULL;
2367914d74bSmrg	 path = _XcursorNextPath (path))
2377914d74bSmrg    {
2387914d74bSmrg	dir = _XcursorBuildThemeDir (path, theme);
2397914d74bSmrg	if (dir)
2407914d74bSmrg	{
2417914d74bSmrg	    full = _XcursorBuildFullname (dir, "cursors", name);
2427914d74bSmrg	    if (full)
2437914d74bSmrg	    {
2447914d74bSmrg		f = fopen (full, "r");
2457914d74bSmrg		free (full);
2467914d74bSmrg	    }
2477914d74bSmrg	    if (!f && !inherits)
2487914d74bSmrg	    {
2497914d74bSmrg		full = _XcursorBuildFullname (dir, "", "index.theme");
2507914d74bSmrg		if (full)
2517914d74bSmrg		{
2527914d74bSmrg		    inherits = _XcursorThemeInherits (full);
2537914d74bSmrg		    free (full);
2547914d74bSmrg		}
2557914d74bSmrg	    }
2567914d74bSmrg	    free (dir);
2577914d74bSmrg	}
2587914d74bSmrg    }
2597914d74bSmrg    /*
2607914d74bSmrg     * Recurse to scan inherited themes
2617914d74bSmrg     */
262e169010aSmrg    for (i = inherits; i && f == NULL; i = _XcursorNextPath (i))
2637914d74bSmrg	f = XcursorScanTheme (i, name);
2647914d74bSmrg    if (inherits != NULL)
2657914d74bSmrg	free (inherits);
2667914d74bSmrg    return f;
2677914d74bSmrg}
2687914d74bSmrg
2697914d74bSmrgXcursorImage *
2707914d74bSmrgXcursorLibraryLoadImage (const char *file, const char *theme, int size)
2717914d74bSmrg{
2727914d74bSmrg    FILE	    *f = NULL;
2737914d74bSmrg    XcursorImage    *image = NULL;
2747914d74bSmrg
2757914d74bSmrg    if (!file)
2767914d74bSmrg        return NULL;
2777914d74bSmrg
2787914d74bSmrg    if (theme)
2797914d74bSmrg	f = XcursorScanTheme (theme, file);
2807914d74bSmrg    if (!f)
2817914d74bSmrg	f = XcursorScanTheme ("default", file);
2827914d74bSmrg    if (f == XCURSOR_SCAN_CORE)
2837914d74bSmrg	return NULL;
2847914d74bSmrg    if (f)
2857914d74bSmrg    {
2867914d74bSmrg	image = XcursorFileLoadImage (f, size);
2877914d74bSmrg	fclose (f);
2887914d74bSmrg    }
2897914d74bSmrg    return image;
2907914d74bSmrg}
2917914d74bSmrg
2927914d74bSmrgXcursorImages *
2937914d74bSmrgXcursorLibraryLoadImages (const char *file, const char *theme, int size)
2947914d74bSmrg{
2957914d74bSmrg    FILE	    *f = NULL;
2967914d74bSmrg    XcursorImages   *images = NULL;
2977914d74bSmrg
2987914d74bSmrg    if (!file)
2997914d74bSmrg        return NULL;
3007914d74bSmrg
3017914d74bSmrg    if (theme)
3027914d74bSmrg	f = XcursorScanTheme (theme, file);
3037914d74bSmrg    if (!f)
3047914d74bSmrg	f = XcursorScanTheme ("default", file);
3057914d74bSmrg    if (f == XCURSOR_SCAN_CORE)
3067914d74bSmrg	return NULL;
3077914d74bSmrg    if (f)
3087914d74bSmrg    {
3097914d74bSmrg	images = XcursorFileLoadImages (f, size);
3107914d74bSmrg	if (images)
3117914d74bSmrg	    XcursorImagesSetName (images, file);
3127914d74bSmrg	fclose (f);
3137914d74bSmrg    }
3147914d74bSmrg    return images;
3157914d74bSmrg}
3167914d74bSmrg
3177914d74bSmrgCursor
3187914d74bSmrgXcursorLibraryLoadCursor (Display *dpy, const char *file)
3197914d74bSmrg{
3207914d74bSmrg    int		    size = XcursorGetDefaultSize (dpy);
3217914d74bSmrg    char	    *theme = XcursorGetTheme (dpy);
3227914d74bSmrg    XcursorImages   *images = XcursorLibraryLoadImages (file, theme, size);
3237914d74bSmrg    Cursor	    cursor;
3247914d74bSmrg
3257914d74bSmrg    if (!file)
3267914d74bSmrg        return 0;
327e6d5e4e0Smrg
3287914d74bSmrg    if (!images)
3297914d74bSmrg    {
3307914d74bSmrg	int id = XcursorLibraryShape (file);
3317914d74bSmrg
3327914d74bSmrg	if (id >= 0)
3337914d74bSmrg	    return _XcursorCreateFontCursor (dpy, id);
3347914d74bSmrg	else
3357914d74bSmrg	    return 0;
3367914d74bSmrg    }
3377914d74bSmrg    cursor = XcursorImagesLoadCursor (dpy, images);
3387914d74bSmrg    XcursorImagesDestroy (images);
3397914d74bSmrg#if defined HAVE_XFIXES && XFIXES_MAJOR >= 2
3407914d74bSmrg    XFixesSetCursorName (dpy, cursor, file);
3417914d74bSmrg#endif
3427914d74bSmrg    return cursor;
3437914d74bSmrg}
3447914d74bSmrg
3457914d74bSmrgXcursorCursors *
3467914d74bSmrgXcursorLibraryLoadCursors (Display *dpy, const char *file)
3477914d74bSmrg{
3487914d74bSmrg    int		    size = XcursorGetDefaultSize (dpy);
3497914d74bSmrg    char	    *theme = XcursorGetTheme (dpy);
3507914d74bSmrg    XcursorImages   *images = XcursorLibraryLoadImages (file, theme, size);
3517914d74bSmrg    XcursorCursors  *cursors;
352e6d5e4e0Smrg
3537914d74bSmrg    if (!file)
3547914d74bSmrg        return NULL;
355e6d5e4e0Smrg
3567914d74bSmrg    if (!images)
3577914d74bSmrg    {
3587914d74bSmrg	int id = XcursorLibraryShape (file);
3597914d74bSmrg
3607914d74bSmrg	if (id >= 0)
3617914d74bSmrg	{
3627914d74bSmrg	    cursors = XcursorCursorsCreate (dpy, 1);
3637914d74bSmrg	    if (cursors)
3647914d74bSmrg	    {
3657914d74bSmrg		cursors->cursors[0] = _XcursorCreateFontCursor (dpy, id);
3667914d74bSmrg		if (cursors->cursors[0] == None)
3677914d74bSmrg		{
3687914d74bSmrg		    XcursorCursorsDestroy (cursors);
3697914d74bSmrg		    cursors = NULL;
3707914d74bSmrg		}
3717914d74bSmrg		else
3727914d74bSmrg		    cursors->ncursor = 1;
3737914d74bSmrg	    }
3747914d74bSmrg	}
3757914d74bSmrg	else
3767914d74bSmrg	    cursors = NULL;
3777914d74bSmrg    }
3787914d74bSmrg    else
3797914d74bSmrg    {
3807914d74bSmrg	cursors = XcursorImagesLoadCursors (dpy, images);
3817914d74bSmrg	XcursorImagesDestroy (images);
3827914d74bSmrg    }
3837914d74bSmrg    return cursors;
3847914d74bSmrg}
3857914d74bSmrg
3867914d74bSmrgstatic const char _XcursorStandardNames[] =
3877914d74bSmrg	"X_cursor\0"
3887914d74bSmrg	"arrow\0"
3897914d74bSmrg	"based_arrow_down\0"
3907914d74bSmrg	"based_arrow_up\0"
3917914d74bSmrg	"boat\0"
3927914d74bSmrg	"bogosity\0"
3937914d74bSmrg	"bottom_left_corner\0"
3947914d74bSmrg	"bottom_right_corner\0"
3957914d74bSmrg	"bottom_side\0"
3967914d74bSmrg	"bottom_tee\0"
3977914d74bSmrg	"box_spiral\0"
3987914d74bSmrg	"center_ptr\0"
3997914d74bSmrg	"circle\0"
4007914d74bSmrg	"clock\0"
4017914d74bSmrg	"coffee_mug\0"
4027914d74bSmrg	"cross\0"
4037914d74bSmrg	"cross_reverse\0"
4047914d74bSmrg	"crosshair\0"
4057914d74bSmrg	"diamond_cross\0"
4067914d74bSmrg	"dot\0"
4077914d74bSmrg	"dotbox\0"
4087914d74bSmrg	"double_arrow\0"
4097914d74bSmrg	"draft_large\0"
4107914d74bSmrg	"draft_small\0"
4117914d74bSmrg	"draped_box\0"
4127914d74bSmrg	"exchange\0"
4137914d74bSmrg	"fleur\0"
4147914d74bSmrg	"gobbler\0"
4157914d74bSmrg	"gumby\0"
4167914d74bSmrg	"hand1\0"
4177914d74bSmrg	"hand2\0"
4187914d74bSmrg	"heart\0"
4197914d74bSmrg	"icon\0"
4207914d74bSmrg	"iron_cross\0"
4217914d74bSmrg	"left_ptr\0"
4227914d74bSmrg	"left_side\0"
4237914d74bSmrg	"left_tee\0"
4247914d74bSmrg	"leftbutton\0"
4257914d74bSmrg	"ll_angle\0"
4267914d74bSmrg	"lr_angle\0"
4277914d74bSmrg	"man\0"
4287914d74bSmrg	"middlebutton\0"
4297914d74bSmrg	"mouse\0"
4307914d74bSmrg	"pencil\0"
4317914d74bSmrg	"pirate\0"
4327914d74bSmrg	"plus\0"
4337914d74bSmrg	"question_arrow\0"
4347914d74bSmrg	"right_ptr\0"
4357914d74bSmrg	"right_side\0"
4367914d74bSmrg	"right_tee\0"
4377914d74bSmrg	"rightbutton\0"
4387914d74bSmrg	"rtl_logo\0"
4397914d74bSmrg	"sailboat\0"
4407914d74bSmrg	"sb_down_arrow\0"
4417914d74bSmrg	"sb_h_double_arrow\0"
4427914d74bSmrg	"sb_left_arrow\0"
4437914d74bSmrg	"sb_right_arrow\0"
4447914d74bSmrg	"sb_up_arrow\0"
4457914d74bSmrg	"sb_v_double_arrow\0"
4467914d74bSmrg	"shuttle\0"
4477914d74bSmrg	"sizing\0"
4487914d74bSmrg	"spider\0"
4497914d74bSmrg	"spraycan\0"
4507914d74bSmrg	"star\0"
4517914d74bSmrg	"target\0"
4527914d74bSmrg	"tcross\0"
4537914d74bSmrg	"top_left_arrow\0"
4547914d74bSmrg	"top_left_corner\0"
4557914d74bSmrg	"top_right_corner\0"
4567914d74bSmrg	"top_side\0"
4577914d74bSmrg	"top_tee\0"
4587914d74bSmrg	"trek\0"
4597914d74bSmrg	"ul_angle\0"
4607914d74bSmrg	"umbrella\0"
4617914d74bSmrg	"ur_angle\0"
4627914d74bSmrg	"watch\0"
4637914d74bSmrg	"xterm";
4647914d74bSmrg
4657914d74bSmrgstatic const unsigned short _XcursorStandardNameOffsets[] = {
4667914d74bSmrg	0, 9, 15, 32, 47, 52, 61, 80, 100, 112, 123, 134, 145, 152, 158,
4677914d74bSmrg	169, 175, 189, 199, 213, 217, 224, 237, 249, 261, 272, 281, 287,
4687914d74bSmrg	295, 301, 307, 313, 319, 324, 335, 344, 354, 363, 374, 383, 392,
4697914d74bSmrg	396, 409, 415, 422, 429, 434, 449, 459, 470, 480, 492, 501, 510,
4707914d74bSmrg	524, 542, 556, 571, 583, 601, 609, 616, 623, 632, 637, 644, 651,
4717914d74bSmrg	666, 682, 699, 708, 716, 721, 730, 739, 748, 754
4727914d74bSmrg};
4737914d74bSmrg
4747914d74bSmrg#define NUM_STANDARD_NAMES  (sizeof _XcursorStandardNameOffsets / sizeof _XcursorStandardNameOffsets[0])
4757914d74bSmrg
4767914d74bSmrg#define STANDARD_NAME(id) \
4777914d74bSmrg    _XcursorStandardNames + _XcursorStandardNameOffsets[id]
4787914d74bSmrg
4797914d74bSmrgXcursorImage *
4807914d74bSmrgXcursorShapeLoadImage (unsigned int shape, const char *theme, int size)
4817914d74bSmrg{
4827914d74bSmrg    unsigned int    id = shape >> 1;
4837914d74bSmrg
4847914d74bSmrg    if (id < NUM_STANDARD_NAMES)
4857914d74bSmrg	return XcursorLibraryLoadImage (STANDARD_NAME (id), theme, size);
4867914d74bSmrg    else
4877914d74bSmrg	return NULL;
4887914d74bSmrg}
4897914d74bSmrg
4907914d74bSmrgXcursorImages *
4917914d74bSmrgXcursorShapeLoadImages (unsigned int shape, const char *theme, int size)
4927914d74bSmrg{
4937914d74bSmrg    unsigned int    id = shape >> 1;
4947914d74bSmrg
4957914d74bSmrg    if (id < NUM_STANDARD_NAMES)
4967914d74bSmrg	return XcursorLibraryLoadImages (STANDARD_NAME (id), theme, size);
4977914d74bSmrg    else
4987914d74bSmrg	return NULL;
4997914d74bSmrg}
5007914d74bSmrg
5017914d74bSmrgCursor
5027914d74bSmrgXcursorShapeLoadCursor (Display *dpy, unsigned int shape)
5037914d74bSmrg{
5047914d74bSmrg    unsigned int    id = shape >> 1;
5057914d74bSmrg
5067914d74bSmrg    if (id < NUM_STANDARD_NAMES)
5077914d74bSmrg	return XcursorLibraryLoadCursor (dpy, STANDARD_NAME (id));
5087914d74bSmrg    else
5097914d74bSmrg	return 0;
5107914d74bSmrg}
5117914d74bSmrg
5127914d74bSmrgXcursorCursors *
5137914d74bSmrgXcursorShapeLoadCursors (Display *dpy, unsigned int shape)
5147914d74bSmrg{
5157914d74bSmrg    unsigned int    id = shape >> 1;
5167914d74bSmrg
5177914d74bSmrg    if (id < NUM_STANDARD_NAMES)
5187914d74bSmrg	return XcursorLibraryLoadCursors (dpy, STANDARD_NAME (id));
5197914d74bSmrg    else
5207914d74bSmrg	return NULL;
5217914d74bSmrg}
5227914d74bSmrg
5237914d74bSmrgint
5247914d74bSmrgXcursorLibraryShape (const char *library)
5257914d74bSmrg{
5267914d74bSmrg    int	low, high;
5277914d74bSmrg    int	mid;
5287914d74bSmrg    int	c;
5297914d74bSmrg
5307914d74bSmrg    low = 0;
5317914d74bSmrg    high = NUM_STANDARD_NAMES - 1;
5327914d74bSmrg    while (low < high - 1)
5337914d74bSmrg    {
5347914d74bSmrg	mid = (low + high) >> 1;
5357914d74bSmrg	c = strcmp (library, STANDARD_NAME (mid));
5367914d74bSmrg	if (c == 0)
5377914d74bSmrg	    return (mid << 1);
5387914d74bSmrg	if (c > 0)
5397914d74bSmrg	    low = mid;
5407914d74bSmrg	else
5417914d74bSmrg	    high = mid;
5427914d74bSmrg    }
5437914d74bSmrg    while (low <= high)
5447914d74bSmrg    {
5457914d74bSmrg	if (!strcmp (library, STANDARD_NAME (low)))
5467914d74bSmrg	    return (low << 1);
5477914d74bSmrg	low++;
5487914d74bSmrg    }
5497914d74bSmrg    return -1;
5507914d74bSmrg}
551