library.c revision cdce750a
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
32cdce750aSmrg#define XCURSORPATH "~/.local/share/icons:~/.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))
263cdce750aSmrg    {
264cdce750aSmrg        if (strcmp(i, theme) != 0)
265cdce750aSmrg            f = XcursorScanTheme (i, name);
266cdce750aSmrg        else
267cdce750aSmrg            printf("Not calling XcursorScanTheme because of circular dependency: %s. %s", i, name);
268cdce750aSmrg    }
2697914d74bSmrg    if (inherits != NULL)
2707914d74bSmrg	free (inherits);
2717914d74bSmrg    return f;
2727914d74bSmrg}
2737914d74bSmrg
2747914d74bSmrgXcursorImage *
2757914d74bSmrgXcursorLibraryLoadImage (const char *file, const char *theme, int size)
2767914d74bSmrg{
2777914d74bSmrg    FILE	    *f = NULL;
2787914d74bSmrg    XcursorImage    *image = NULL;
2797914d74bSmrg
2807914d74bSmrg    if (!file)
2817914d74bSmrg        return NULL;
2827914d74bSmrg
2837914d74bSmrg    if (theme)
2847914d74bSmrg	f = XcursorScanTheme (theme, file);
2857914d74bSmrg    if (!f)
2867914d74bSmrg	f = XcursorScanTheme ("default", file);
2877914d74bSmrg    if (f == XCURSOR_SCAN_CORE)
2887914d74bSmrg	return NULL;
2897914d74bSmrg    if (f)
2907914d74bSmrg    {
2917914d74bSmrg	image = XcursorFileLoadImage (f, size);
2927914d74bSmrg	fclose (f);
2937914d74bSmrg    }
2947914d74bSmrg    return image;
2957914d74bSmrg}
2967914d74bSmrg
2977914d74bSmrgXcursorImages *
2987914d74bSmrgXcursorLibraryLoadImages (const char *file, const char *theme, int size)
2997914d74bSmrg{
3007914d74bSmrg    FILE	    *f = NULL;
3017914d74bSmrg    XcursorImages   *images = NULL;
3027914d74bSmrg
3037914d74bSmrg    if (!file)
3047914d74bSmrg        return NULL;
3057914d74bSmrg
3067914d74bSmrg    if (theme)
3077914d74bSmrg	f = XcursorScanTheme (theme, file);
3087914d74bSmrg    if (!f)
3097914d74bSmrg	f = XcursorScanTheme ("default", file);
3107914d74bSmrg    if (f == XCURSOR_SCAN_CORE)
3117914d74bSmrg	return NULL;
3127914d74bSmrg    if (f)
3137914d74bSmrg    {
3147914d74bSmrg	images = XcursorFileLoadImages (f, size);
3157914d74bSmrg	if (images)
3167914d74bSmrg	    XcursorImagesSetName (images, file);
3177914d74bSmrg	fclose (f);
3187914d74bSmrg    }
3197914d74bSmrg    return images;
3207914d74bSmrg}
3217914d74bSmrg
3227914d74bSmrgCursor
3237914d74bSmrgXcursorLibraryLoadCursor (Display *dpy, const char *file)
3247914d74bSmrg{
3257914d74bSmrg    int		    size = XcursorGetDefaultSize (dpy);
3267914d74bSmrg    char	    *theme = XcursorGetTheme (dpy);
3277914d74bSmrg    XcursorImages   *images = XcursorLibraryLoadImages (file, theme, size);
3287914d74bSmrg    Cursor	    cursor;
3297914d74bSmrg
3307914d74bSmrg    if (!file)
3317914d74bSmrg        return 0;
332e6d5e4e0Smrg
3337914d74bSmrg    if (!images)
3347914d74bSmrg    {
3357914d74bSmrg	int id = XcursorLibraryShape (file);
3367914d74bSmrg
3377914d74bSmrg	if (id >= 0)
3387914d74bSmrg	    return _XcursorCreateFontCursor (dpy, id);
3397914d74bSmrg	else
3407914d74bSmrg	    return 0;
3417914d74bSmrg    }
3427914d74bSmrg    cursor = XcursorImagesLoadCursor (dpy, images);
3437914d74bSmrg    XcursorImagesDestroy (images);
3447914d74bSmrg#if defined HAVE_XFIXES && XFIXES_MAJOR >= 2
3457914d74bSmrg    XFixesSetCursorName (dpy, cursor, file);
3467914d74bSmrg#endif
3477914d74bSmrg    return cursor;
3487914d74bSmrg}
3497914d74bSmrg
3507914d74bSmrgXcursorCursors *
3517914d74bSmrgXcursorLibraryLoadCursors (Display *dpy, const char *file)
3527914d74bSmrg{
3537914d74bSmrg    int		    size = XcursorGetDefaultSize (dpy);
3547914d74bSmrg    char	    *theme = XcursorGetTheme (dpy);
3557914d74bSmrg    XcursorImages   *images = XcursorLibraryLoadImages (file, theme, size);
3567914d74bSmrg    XcursorCursors  *cursors;
357e6d5e4e0Smrg
3587914d74bSmrg    if (!file)
3597914d74bSmrg        return NULL;
360e6d5e4e0Smrg
3617914d74bSmrg    if (!images)
3627914d74bSmrg    {
3637914d74bSmrg	int id = XcursorLibraryShape (file);
3647914d74bSmrg
3657914d74bSmrg	if (id >= 0)
3667914d74bSmrg	{
3677914d74bSmrg	    cursors = XcursorCursorsCreate (dpy, 1);
3687914d74bSmrg	    if (cursors)
3697914d74bSmrg	    {
3707914d74bSmrg		cursors->cursors[0] = _XcursorCreateFontCursor (dpy, id);
3717914d74bSmrg		if (cursors->cursors[0] == None)
3727914d74bSmrg		{
3737914d74bSmrg		    XcursorCursorsDestroy (cursors);
3747914d74bSmrg		    cursors = NULL;
3757914d74bSmrg		}
3767914d74bSmrg		else
3777914d74bSmrg		    cursors->ncursor = 1;
3787914d74bSmrg	    }
3797914d74bSmrg	}
3807914d74bSmrg	else
3817914d74bSmrg	    cursors = NULL;
3827914d74bSmrg    }
3837914d74bSmrg    else
3847914d74bSmrg    {
3857914d74bSmrg	cursors = XcursorImagesLoadCursors (dpy, images);
3867914d74bSmrg	XcursorImagesDestroy (images);
3877914d74bSmrg    }
3887914d74bSmrg    return cursors;
3897914d74bSmrg}
3907914d74bSmrg
3917914d74bSmrgstatic const char _XcursorStandardNames[] =
3927914d74bSmrg	"X_cursor\0"
3937914d74bSmrg	"arrow\0"
3947914d74bSmrg	"based_arrow_down\0"
3957914d74bSmrg	"based_arrow_up\0"
3967914d74bSmrg	"boat\0"
3977914d74bSmrg	"bogosity\0"
3987914d74bSmrg	"bottom_left_corner\0"
3997914d74bSmrg	"bottom_right_corner\0"
4007914d74bSmrg	"bottom_side\0"
4017914d74bSmrg	"bottom_tee\0"
4027914d74bSmrg	"box_spiral\0"
4037914d74bSmrg	"center_ptr\0"
4047914d74bSmrg	"circle\0"
4057914d74bSmrg	"clock\0"
4067914d74bSmrg	"coffee_mug\0"
4077914d74bSmrg	"cross\0"
4087914d74bSmrg	"cross_reverse\0"
4097914d74bSmrg	"crosshair\0"
4107914d74bSmrg	"diamond_cross\0"
4117914d74bSmrg	"dot\0"
4127914d74bSmrg	"dotbox\0"
4137914d74bSmrg	"double_arrow\0"
4147914d74bSmrg	"draft_large\0"
4157914d74bSmrg	"draft_small\0"
4167914d74bSmrg	"draped_box\0"
4177914d74bSmrg	"exchange\0"
4187914d74bSmrg	"fleur\0"
4197914d74bSmrg	"gobbler\0"
4207914d74bSmrg	"gumby\0"
4217914d74bSmrg	"hand1\0"
4227914d74bSmrg	"hand2\0"
4237914d74bSmrg	"heart\0"
4247914d74bSmrg	"icon\0"
4257914d74bSmrg	"iron_cross\0"
4267914d74bSmrg	"left_ptr\0"
4277914d74bSmrg	"left_side\0"
4287914d74bSmrg	"left_tee\0"
4297914d74bSmrg	"leftbutton\0"
4307914d74bSmrg	"ll_angle\0"
4317914d74bSmrg	"lr_angle\0"
4327914d74bSmrg	"man\0"
4337914d74bSmrg	"middlebutton\0"
4347914d74bSmrg	"mouse\0"
4357914d74bSmrg	"pencil\0"
4367914d74bSmrg	"pirate\0"
4377914d74bSmrg	"plus\0"
4387914d74bSmrg	"question_arrow\0"
4397914d74bSmrg	"right_ptr\0"
4407914d74bSmrg	"right_side\0"
4417914d74bSmrg	"right_tee\0"
4427914d74bSmrg	"rightbutton\0"
4437914d74bSmrg	"rtl_logo\0"
4447914d74bSmrg	"sailboat\0"
4457914d74bSmrg	"sb_down_arrow\0"
4467914d74bSmrg	"sb_h_double_arrow\0"
4477914d74bSmrg	"sb_left_arrow\0"
4487914d74bSmrg	"sb_right_arrow\0"
4497914d74bSmrg	"sb_up_arrow\0"
4507914d74bSmrg	"sb_v_double_arrow\0"
4517914d74bSmrg	"shuttle\0"
4527914d74bSmrg	"sizing\0"
4537914d74bSmrg	"spider\0"
4547914d74bSmrg	"spraycan\0"
4557914d74bSmrg	"star\0"
4567914d74bSmrg	"target\0"
4577914d74bSmrg	"tcross\0"
4587914d74bSmrg	"top_left_arrow\0"
4597914d74bSmrg	"top_left_corner\0"
4607914d74bSmrg	"top_right_corner\0"
4617914d74bSmrg	"top_side\0"
4627914d74bSmrg	"top_tee\0"
4637914d74bSmrg	"trek\0"
4647914d74bSmrg	"ul_angle\0"
4657914d74bSmrg	"umbrella\0"
4667914d74bSmrg	"ur_angle\0"
4677914d74bSmrg	"watch\0"
4687914d74bSmrg	"xterm";
4697914d74bSmrg
4707914d74bSmrgstatic const unsigned short _XcursorStandardNameOffsets[] = {
4717914d74bSmrg	0, 9, 15, 32, 47, 52, 61, 80, 100, 112, 123, 134, 145, 152, 158,
4727914d74bSmrg	169, 175, 189, 199, 213, 217, 224, 237, 249, 261, 272, 281, 287,
4737914d74bSmrg	295, 301, 307, 313, 319, 324, 335, 344, 354, 363, 374, 383, 392,
4747914d74bSmrg	396, 409, 415, 422, 429, 434, 449, 459, 470, 480, 492, 501, 510,
4757914d74bSmrg	524, 542, 556, 571, 583, 601, 609, 616, 623, 632, 637, 644, 651,
4767914d74bSmrg	666, 682, 699, 708, 716, 721, 730, 739, 748, 754
4777914d74bSmrg};
4787914d74bSmrg
4797914d74bSmrg#define NUM_STANDARD_NAMES  (sizeof _XcursorStandardNameOffsets / sizeof _XcursorStandardNameOffsets[0])
4807914d74bSmrg
4817914d74bSmrg#define STANDARD_NAME(id) \
4827914d74bSmrg    _XcursorStandardNames + _XcursorStandardNameOffsets[id]
4837914d74bSmrg
4847914d74bSmrgXcursorImage *
4857914d74bSmrgXcursorShapeLoadImage (unsigned int shape, const char *theme, int size)
4867914d74bSmrg{
4877914d74bSmrg    unsigned int    id = shape >> 1;
4887914d74bSmrg
4897914d74bSmrg    if (id < NUM_STANDARD_NAMES)
4907914d74bSmrg	return XcursorLibraryLoadImage (STANDARD_NAME (id), theme, size);
4917914d74bSmrg    else
4927914d74bSmrg	return NULL;
4937914d74bSmrg}
4947914d74bSmrg
4957914d74bSmrgXcursorImages *
4967914d74bSmrgXcursorShapeLoadImages (unsigned int shape, const char *theme, int size)
4977914d74bSmrg{
4987914d74bSmrg    unsigned int    id = shape >> 1;
4997914d74bSmrg
5007914d74bSmrg    if (id < NUM_STANDARD_NAMES)
5017914d74bSmrg	return XcursorLibraryLoadImages (STANDARD_NAME (id), theme, size);
5027914d74bSmrg    else
5037914d74bSmrg	return NULL;
5047914d74bSmrg}
5057914d74bSmrg
5067914d74bSmrgCursor
5077914d74bSmrgXcursorShapeLoadCursor (Display *dpy, unsigned int shape)
5087914d74bSmrg{
5097914d74bSmrg    unsigned int    id = shape >> 1;
5107914d74bSmrg
5117914d74bSmrg    if (id < NUM_STANDARD_NAMES)
5127914d74bSmrg	return XcursorLibraryLoadCursor (dpy, STANDARD_NAME (id));
5137914d74bSmrg    else
5147914d74bSmrg	return 0;
5157914d74bSmrg}
5167914d74bSmrg
5177914d74bSmrgXcursorCursors *
5187914d74bSmrgXcursorShapeLoadCursors (Display *dpy, unsigned int shape)
5197914d74bSmrg{
5207914d74bSmrg    unsigned int    id = shape >> 1;
5217914d74bSmrg
5227914d74bSmrg    if (id < NUM_STANDARD_NAMES)
5237914d74bSmrg	return XcursorLibraryLoadCursors (dpy, STANDARD_NAME (id));
5247914d74bSmrg    else
5257914d74bSmrg	return NULL;
5267914d74bSmrg}
5277914d74bSmrg
5287914d74bSmrgint
5297914d74bSmrgXcursorLibraryShape (const char *library)
5307914d74bSmrg{
5317914d74bSmrg    int	low, high;
5327914d74bSmrg    int	mid;
5337914d74bSmrg    int	c;
5347914d74bSmrg
5357914d74bSmrg    low = 0;
5367914d74bSmrg    high = NUM_STANDARD_NAMES - 1;
5377914d74bSmrg    while (low < high - 1)
5387914d74bSmrg    {
5397914d74bSmrg	mid = (low + high) >> 1;
5407914d74bSmrg	c = strcmp (library, STANDARD_NAME (mid));
5417914d74bSmrg	if (c == 0)
5427914d74bSmrg	    return (mid << 1);
5437914d74bSmrg	if (c > 0)
5447914d74bSmrg	    low = mid;
5457914d74bSmrg	else
5467914d74bSmrg	    high = mid;
5477914d74bSmrg    }
5487914d74bSmrg    while (low <= high)
5497914d74bSmrg    {
5507914d74bSmrg	if (!strcmp (library, STANDARD_NAME (low)))
5517914d74bSmrg	    return (low << 1);
5527914d74bSmrg	low++;
5537914d74bSmrg    }
5547914d74bSmrg    return -1;
5557914d74bSmrg}
556