library.c revision 4d939ec7
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
354d939ec7Smrgtypedef struct XcursorInherit {
364d939ec7Smrg    char	*line;
374d939ec7Smrg    const char	*theme;
384d939ec7Smrg} XcursorInherit;
394d939ec7Smrg
407914d74bSmrgconst char *
417914d74bSmrgXcursorLibraryPath (void)
427914d74bSmrg{
437914d74bSmrg    static const char	*path;
447914d74bSmrg
457914d74bSmrg    if (!path)
467914d74bSmrg    {
477914d74bSmrg	path = getenv ("XCURSOR_PATH");
487914d74bSmrg	if (!path)
497914d74bSmrg	    path = XCURSORPATH;
507914d74bSmrg    }
517914d74bSmrg    return path;
527914d74bSmrg}
537914d74bSmrg
547914d74bSmrgstatic  void
557914d74bSmrg_XcursorAddPathElt (char *path, const char *elt, int len)
567914d74bSmrg{
579d0ccd10Smrg    size_t    pathlen = strlen (path);
58e6d5e4e0Smrg
597914d74bSmrg    /* append / if the path doesn't currently have one */
607914d74bSmrg    if (path[0] == '\0' || path[pathlen - 1] != '/')
617914d74bSmrg    {
627914d74bSmrg	strcat (path, "/");
637914d74bSmrg	pathlen++;
647914d74bSmrg    }
657914d74bSmrg    if (len == -1)
664d939ec7Smrg	len = (int) strlen (elt);
677914d74bSmrg    /* strip leading slashes */
687914d74bSmrg    while (len && elt[0] == '/')
697914d74bSmrg    {
707914d74bSmrg	elt++;
717914d74bSmrg	len--;
727914d74bSmrg    }
734d939ec7Smrg    strncpy (path + pathlen, elt, (size_t) len);
744d939ec7Smrg    path[pathlen + (size_t) len] = '\0';
757914d74bSmrg}
767914d74bSmrg
777914d74bSmrgstatic char *
787914d74bSmrg_XcursorBuildThemeDir (const char *dir, const char *theme)
797914d74bSmrg{
807914d74bSmrg    const char	    *colon;
817914d74bSmrg    const char	    *tcolon;
827914d74bSmrg    char	    *full;
837914d74bSmrg    char	    *home;
847914d74bSmrg    int		    dirlen;
857914d74bSmrg    int		    homelen;
867914d74bSmrg    int		    themelen;
877914d74bSmrg    int		    len;
887914d74bSmrg
897914d74bSmrg    if (!dir || !theme)
904d939ec7Smrg	return NULL;
91e6d5e4e0Smrg
927914d74bSmrg    colon = strchr (dir, ':');
937914d74bSmrg    if (!colon)
947914d74bSmrg	colon = dir + strlen (dir);
95e6d5e4e0Smrg
964d939ec7Smrg    dirlen = (int) (colon - dir);
977914d74bSmrg
987914d74bSmrg    tcolon = strchr (theme, ':');
997914d74bSmrg    if (!tcolon)
1007914d74bSmrg	tcolon = theme + strlen (theme);
1017914d74bSmrg
1024d939ec7Smrg    themelen = (int) (tcolon - theme);
103e6d5e4e0Smrg
1047914d74bSmrg    home = NULL;
1057914d74bSmrg    homelen = 0;
1067914d74bSmrg    if (*dir == '~')
1077914d74bSmrg    {
1087914d74bSmrg	home = getenv ("HOME");
1097914d74bSmrg	if (!home)
1107914d74bSmrg	    return NULL;
1114d939ec7Smrg	homelen = (int) strlen (home);
1127914d74bSmrg	dir++;
1137914d74bSmrg	dirlen--;
1147914d74bSmrg    }
1157914d74bSmrg
1167914d74bSmrg    /*
1177914d74bSmrg     * add space for any needed directory separators, one per component,
1187914d74bSmrg     * and one for the trailing null
1197914d74bSmrg     */
1207914d74bSmrg    len = 1 + homelen + 1 + dirlen + 1 + themelen + 1;
121e6d5e4e0Smrg
1224d939ec7Smrg    full = malloc ((size_t)len);
1237914d74bSmrg    if (!full)
1247914d74bSmrg	return NULL;
1257914d74bSmrg    full[0] = '\0';
1267914d74bSmrg
1277914d74bSmrg    if (home)
1287914d74bSmrg	_XcursorAddPathElt (full, home, -1);
1297914d74bSmrg    _XcursorAddPathElt (full, dir, dirlen);
1307914d74bSmrg    _XcursorAddPathElt (full, theme, themelen);
1317914d74bSmrg    return full;
1327914d74bSmrg}
1337914d74bSmrg
1347914d74bSmrgstatic char *
1357914d74bSmrg_XcursorBuildFullname (const char *dir, const char *subdir, const char *file)
1367914d74bSmrg{
1377914d74bSmrg    char    *full;
1387914d74bSmrg
1397914d74bSmrg    if (!dir || !subdir || !file)
1404d939ec7Smrg	return NULL;
1417914d74bSmrg
1427914d74bSmrg    full = malloc (strlen (dir) + 1 + strlen (subdir) + 1 + strlen (file) + 1);
1437914d74bSmrg    if (!full)
1447914d74bSmrg	return NULL;
1457914d74bSmrg    full[0] = '\0';
1467914d74bSmrg    _XcursorAddPathElt (full, dir, -1);
1477914d74bSmrg    _XcursorAddPathElt (full, subdir, -1);
1487914d74bSmrg    _XcursorAddPathElt (full, file, -1);
1497914d74bSmrg    return full;
1507914d74bSmrg}
1517914d74bSmrg
1527914d74bSmrgstatic const char *
1537914d74bSmrg_XcursorNextPath (const char *path)
1547914d74bSmrg{
1557914d74bSmrg    char    *colon = strchr (path, ':');
1567914d74bSmrg
1577914d74bSmrg    if (!colon)
1587914d74bSmrg	return NULL;
1597914d74bSmrg    return colon + 1;
1607914d74bSmrg}
1617914d74bSmrg
1627914d74bSmrg#define XcursorWhite(c)	((c) == ' ' || (c) == '\t' || (c) == '\n')
1637914d74bSmrg#define XcursorSep(c) ((c) == ';' || (c) == ',')
1647914d74bSmrg
1657914d74bSmrgstatic char *
1667914d74bSmrg_XcursorThemeInherits (const char *full)
1677914d74bSmrg{
1687914d74bSmrg    char    line[8192];
1697914d74bSmrg    char    *result = NULL;
1707914d74bSmrg    FILE    *f;
1717914d74bSmrg
1727914d74bSmrg    if (!full)
1734d939ec7Smrg	return NULL;
1747914d74bSmrg
1757914d74bSmrg    f = fopen (full, "r");
1767914d74bSmrg    if (f)
1777914d74bSmrg    {
1787914d74bSmrg	while (fgets (line, sizeof (line), f))
1797914d74bSmrg	{
1807914d74bSmrg	    if (!strncmp (line, "Inherits", 8))
1817914d74bSmrg	    {
1827914d74bSmrg		char    *l = line + 8;
1837914d74bSmrg		while (*l == ' ') l++;
1847914d74bSmrg		if (*l != '=') continue;
1857914d74bSmrg		l++;
1867914d74bSmrg		while (*l == ' ') l++;
1879d0ccd10Smrg		result = malloc (strlen (l) + 1);
1887914d74bSmrg		if (result)
1897914d74bSmrg		{
1904d939ec7Smrg		    char *r = result;
191e6d5e4e0Smrg		    while (*l)
1927914d74bSmrg		    {
1937914d74bSmrg			while (XcursorSep(*l) || XcursorWhite (*l)) l++;
1947914d74bSmrg			if (!*l)
1957914d74bSmrg			    break;
1967914d74bSmrg			if (r != result)
1977914d74bSmrg			    *r++ = ':';
198e6d5e4e0Smrg			while (*l && !XcursorWhite(*l) &&
1997914d74bSmrg			       !XcursorSep(*l))
2007914d74bSmrg			    *r++ = *l++;
2017914d74bSmrg		    }
2027914d74bSmrg		    *r++ = '\0';
2037914d74bSmrg		}
2047914d74bSmrg		break;
2057914d74bSmrg	    }
2067914d74bSmrg	}
2077914d74bSmrg	fclose (f);
2087914d74bSmrg    }
2097914d74bSmrg    return result;
2107914d74bSmrg}
2117914d74bSmrg
2127914d74bSmrg#define XCURSOR_SCAN_CORE   ((FILE *) 1)
2134d939ec7Smrg#define MAX_INHERITS_DEPTH  32
2147914d74bSmrg
2157914d74bSmrgstatic FILE *
2167914d74bSmrgXcursorScanTheme (const char *theme, const char *name)
2177914d74bSmrg{
2184d939ec7Smrg    FILE		*f = NULL;
2194d939ec7Smrg    char		*full;
2204d939ec7Smrg    char		*dir;
2214d939ec7Smrg    const char		*path;
2224d939ec7Smrg    XcursorInherit	 inherits[MAX_INHERITS_DEPTH + 1];
2234d939ec7Smrg    int			 d;
2247914d74bSmrg
2257914d74bSmrg    if (!theme || !name)
2264d939ec7Smrg	return NULL;
2277914d74bSmrg
2287914d74bSmrg    /*
2297914d74bSmrg     * XCURSOR_CORE_THEME is a magic name; cursors from the core set
2307914d74bSmrg     * are never found in any directory.  Instead, a magic value is
2317914d74bSmrg     * returned which truncates any search so that overlying functions
2327914d74bSmrg     * can switch to equivalent core cursors
2337914d74bSmrg     */
2347914d74bSmrg    if (!strcmp (theme, XCURSOR_CORE_THEME) && XcursorLibraryShape (name) >= 0)
2357914d74bSmrg	return XCURSOR_SCAN_CORE;
2364d939ec7Smrg
2374d939ec7Smrg    memset (inherits, 0, sizeof (inherits));
2384d939ec7Smrg
2394d939ec7Smrg    d = 0;
2404d939ec7Smrg    inherits[d].theme = theme;
2414d939ec7Smrg
2424d939ec7Smrg    while (f == NULL && d >= 0 && inherits[d].theme != NULL)
2437914d74bSmrg    {
2444d939ec7Smrg	/*
2454d939ec7Smrg	 * Scan this theme
2464d939ec7Smrg	 */
2474d939ec7Smrg	for (path = XcursorLibraryPath ();
2484d939ec7Smrg	     path && f == NULL;
2494d939ec7Smrg	     path = _XcursorNextPath (path))
2507914d74bSmrg	{
2514d939ec7Smrg	    dir = _XcursorBuildThemeDir (path, inherits[d].theme);
2524d939ec7Smrg	    if (dir)
2537914d74bSmrg	    {
2544d939ec7Smrg		full = _XcursorBuildFullname (dir, "cursors", name);
2557914d74bSmrg		if (full)
2567914d74bSmrg		{
2574d939ec7Smrg		    f = fopen (full, "r");
2587914d74bSmrg		    free (full);
2597914d74bSmrg		}
2604d939ec7Smrg		if (!f && inherits[d + 1].line == NULL)
2614d939ec7Smrg		{
2624d939ec7Smrg		    if (d + 1 >= MAX_INHERITS_DEPTH)
2634d939ec7Smrg		    {
2644d939ec7Smrg			free (dir);
2654d939ec7Smrg			goto finish;
2664d939ec7Smrg		    }
2674d939ec7Smrg		    full = _XcursorBuildFullname (dir, "", "index.theme");
2684d939ec7Smrg		    if (full)
2694d939ec7Smrg		    {
2704d939ec7Smrg			inherits[d + 1].line = _XcursorThemeInherits (full);
2714d939ec7Smrg			inherits[d + 1].theme = inherits[d + 1].line;
2724d939ec7Smrg			free (full);
2734d939ec7Smrg		    }
2744d939ec7Smrg		}
2754d939ec7Smrg		free (dir);
2767914d74bSmrg	    }
2777914d74bSmrg	}
2784d939ec7Smrg
2794d939ec7Smrg	d++;
2804d939ec7Smrg	while (d > 0 && inherits[d].theme == NULL)
2814d939ec7Smrg	{
2824d939ec7Smrg	    free (inherits[d].line);
2834d939ec7Smrg	    inherits[d].line = NULL;
2844d939ec7Smrg
2854d939ec7Smrg	    if (--d == 0)
2864d939ec7Smrg		inherits[d].theme = NULL;
2874d939ec7Smrg	    else
2884d939ec7Smrg		inherits[d].theme = _XcursorNextPath (inherits[d].theme);
2894d939ec7Smrg	}
2904d939ec7Smrg
2914d939ec7Smrg	/*
2924d939ec7Smrg	 * Detect and break self reference loop early on.
2934d939ec7Smrg	 */
2944d939ec7Smrg	if (inherits[d].theme != NULL && strcmp (inherits[d].theme, theme) == 0)
2954d939ec7Smrg	    break;
2967914d74bSmrg    }
2974d939ec7Smrg
2984d939ec7Smrgfinish:
2994d939ec7Smrg    for (d = 1; d <= MAX_INHERITS_DEPTH; d++)
3004d939ec7Smrg	free (inherits[d].line);
3014d939ec7Smrg
3027914d74bSmrg    return f;
3037914d74bSmrg}
3047914d74bSmrg
3057914d74bSmrgXcursorImage *
3067914d74bSmrgXcursorLibraryLoadImage (const char *file, const char *theme, int size)
3077914d74bSmrg{
3087914d74bSmrg    FILE	    *f = NULL;
3097914d74bSmrg    XcursorImage    *image = NULL;
3107914d74bSmrg
3117914d74bSmrg    if (!file)
3124d939ec7Smrg	return NULL;
3137914d74bSmrg
3147914d74bSmrg    if (theme)
3157914d74bSmrg	f = XcursorScanTheme (theme, file);
3167914d74bSmrg    if (!f)
3177914d74bSmrg	f = XcursorScanTheme ("default", file);
3184d939ec7Smrg    if (f != NULL && f != XCURSOR_SCAN_CORE)
3197914d74bSmrg    {
3207914d74bSmrg	image = XcursorFileLoadImage (f, size);
3217914d74bSmrg	fclose (f);
3227914d74bSmrg    }
3237914d74bSmrg    return image;
3247914d74bSmrg}
3257914d74bSmrg
3267914d74bSmrgXcursorImages *
3277914d74bSmrgXcursorLibraryLoadImages (const char *file, const char *theme, int size)
3287914d74bSmrg{
3297914d74bSmrg    FILE	    *f = NULL;
3307914d74bSmrg    XcursorImages   *images = NULL;
3317914d74bSmrg
3327914d74bSmrg    if (!file)
3334d939ec7Smrg	return NULL;
3347914d74bSmrg
3357914d74bSmrg    if (theme)
3367914d74bSmrg	f = XcursorScanTheme (theme, file);
3377914d74bSmrg    if (!f)
3387914d74bSmrg	f = XcursorScanTheme ("default", file);
3394d939ec7Smrg    if (f != NULL && f != XCURSOR_SCAN_CORE)
3407914d74bSmrg    {
3417914d74bSmrg	images = XcursorFileLoadImages (f, size);
3427914d74bSmrg	if (images)
3437914d74bSmrg	    XcursorImagesSetName (images, file);
3447914d74bSmrg	fclose (f);
3457914d74bSmrg    }
3467914d74bSmrg    return images;
3477914d74bSmrg}
3487914d74bSmrg
3497914d74bSmrgCursor
3507914d74bSmrgXcursorLibraryLoadCursor (Display *dpy, const char *file)
3517914d74bSmrg{
3527914d74bSmrg    int		    size = XcursorGetDefaultSize (dpy);
3537914d74bSmrg    char	    *theme = XcursorGetTheme (dpy);
3547914d74bSmrg    XcursorImages   *images = XcursorLibraryLoadImages (file, theme, size);
3557914d74bSmrg    Cursor	    cursor;
3567914d74bSmrg
3577914d74bSmrg    if (!file)
3584d939ec7Smrg	return 0;
359e6d5e4e0Smrg
3607914d74bSmrg    if (!images)
3617914d74bSmrg    {
3627914d74bSmrg	int id = XcursorLibraryShape (file);
3637914d74bSmrg
3647914d74bSmrg	if (id >= 0)
3654d939ec7Smrg	    return _XcursorCreateFontCursor (dpy, (unsigned) id);
3667914d74bSmrg	else
3677914d74bSmrg	    return 0;
3687914d74bSmrg    }
3697914d74bSmrg    cursor = XcursorImagesLoadCursor (dpy, images);
3707914d74bSmrg    XcursorImagesDestroy (images);
3717914d74bSmrg#if defined HAVE_XFIXES && XFIXES_MAJOR >= 2
3727914d74bSmrg    XFixesSetCursorName (dpy, cursor, file);
3737914d74bSmrg#endif
3747914d74bSmrg    return cursor;
3757914d74bSmrg}
3767914d74bSmrg
3777914d74bSmrgXcursorCursors *
3787914d74bSmrgXcursorLibraryLoadCursors (Display *dpy, const char *file)
3797914d74bSmrg{
3807914d74bSmrg    int		    size = XcursorGetDefaultSize (dpy);
3817914d74bSmrg    char	    *theme = XcursorGetTheme (dpy);
3827914d74bSmrg    XcursorImages   *images = XcursorLibraryLoadImages (file, theme, size);
3837914d74bSmrg    XcursorCursors  *cursors;
384e6d5e4e0Smrg
3857914d74bSmrg    if (!file)
3864d939ec7Smrg	return NULL;
387e6d5e4e0Smrg
3887914d74bSmrg    if (!images)
3897914d74bSmrg    {
3907914d74bSmrg	int id = XcursorLibraryShape (file);
3917914d74bSmrg
3927914d74bSmrg	if (id >= 0)
3937914d74bSmrg	{
3947914d74bSmrg	    cursors = XcursorCursorsCreate (dpy, 1);
3957914d74bSmrg	    if (cursors)
3967914d74bSmrg	    {
3974d939ec7Smrg		cursors->cursors[0] = _XcursorCreateFontCursor (dpy, (unsigned) id);
3987914d74bSmrg		if (cursors->cursors[0] == None)
3997914d74bSmrg		{
4007914d74bSmrg		    XcursorCursorsDestroy (cursors);
4017914d74bSmrg		    cursors = NULL;
4027914d74bSmrg		}
4037914d74bSmrg		else
4047914d74bSmrg		    cursors->ncursor = 1;
4057914d74bSmrg	    }
4067914d74bSmrg	}
4077914d74bSmrg	else
4087914d74bSmrg	    cursors = NULL;
4097914d74bSmrg    }
4107914d74bSmrg    else
4117914d74bSmrg    {
4127914d74bSmrg	cursors = XcursorImagesLoadCursors (dpy, images);
4137914d74bSmrg	XcursorImagesDestroy (images);
4147914d74bSmrg    }
4157914d74bSmrg    return cursors;
4167914d74bSmrg}
4177914d74bSmrg
4187914d74bSmrgstatic const char _XcursorStandardNames[] =
4197914d74bSmrg	"X_cursor\0"
4207914d74bSmrg	"arrow\0"
4217914d74bSmrg	"based_arrow_down\0"
4227914d74bSmrg	"based_arrow_up\0"
4237914d74bSmrg	"boat\0"
4247914d74bSmrg	"bogosity\0"
4257914d74bSmrg	"bottom_left_corner\0"
4267914d74bSmrg	"bottom_right_corner\0"
4277914d74bSmrg	"bottom_side\0"
4287914d74bSmrg	"bottom_tee\0"
4297914d74bSmrg	"box_spiral\0"
4307914d74bSmrg	"center_ptr\0"
4317914d74bSmrg	"circle\0"
4327914d74bSmrg	"clock\0"
4337914d74bSmrg	"coffee_mug\0"
4347914d74bSmrg	"cross\0"
4357914d74bSmrg	"cross_reverse\0"
4367914d74bSmrg	"crosshair\0"
4377914d74bSmrg	"diamond_cross\0"
4387914d74bSmrg	"dot\0"
4397914d74bSmrg	"dotbox\0"
4407914d74bSmrg	"double_arrow\0"
4417914d74bSmrg	"draft_large\0"
4427914d74bSmrg	"draft_small\0"
4437914d74bSmrg	"draped_box\0"
4447914d74bSmrg	"exchange\0"
4457914d74bSmrg	"fleur\0"
4467914d74bSmrg	"gobbler\0"
4477914d74bSmrg	"gumby\0"
4487914d74bSmrg	"hand1\0"
4497914d74bSmrg	"hand2\0"
4507914d74bSmrg	"heart\0"
4517914d74bSmrg	"icon\0"
4527914d74bSmrg	"iron_cross\0"
4537914d74bSmrg	"left_ptr\0"
4547914d74bSmrg	"left_side\0"
4557914d74bSmrg	"left_tee\0"
4567914d74bSmrg	"leftbutton\0"
4577914d74bSmrg	"ll_angle\0"
4587914d74bSmrg	"lr_angle\0"
4597914d74bSmrg	"man\0"
4607914d74bSmrg	"middlebutton\0"
4617914d74bSmrg	"mouse\0"
4627914d74bSmrg	"pencil\0"
4637914d74bSmrg	"pirate\0"
4647914d74bSmrg	"plus\0"
4657914d74bSmrg	"question_arrow\0"
4667914d74bSmrg	"right_ptr\0"
4677914d74bSmrg	"right_side\0"
4687914d74bSmrg	"right_tee\0"
4697914d74bSmrg	"rightbutton\0"
4707914d74bSmrg	"rtl_logo\0"
4717914d74bSmrg	"sailboat\0"
4727914d74bSmrg	"sb_down_arrow\0"
4737914d74bSmrg	"sb_h_double_arrow\0"
4747914d74bSmrg	"sb_left_arrow\0"
4757914d74bSmrg	"sb_right_arrow\0"
4767914d74bSmrg	"sb_up_arrow\0"
4777914d74bSmrg	"sb_v_double_arrow\0"
4787914d74bSmrg	"shuttle\0"
4797914d74bSmrg	"sizing\0"
4807914d74bSmrg	"spider\0"
4817914d74bSmrg	"spraycan\0"
4827914d74bSmrg	"star\0"
4837914d74bSmrg	"target\0"
4847914d74bSmrg	"tcross\0"
4857914d74bSmrg	"top_left_arrow\0"
4867914d74bSmrg	"top_left_corner\0"
4877914d74bSmrg	"top_right_corner\0"
4887914d74bSmrg	"top_side\0"
4897914d74bSmrg	"top_tee\0"
4907914d74bSmrg	"trek\0"
4917914d74bSmrg	"ul_angle\0"
4927914d74bSmrg	"umbrella\0"
4937914d74bSmrg	"ur_angle\0"
4947914d74bSmrg	"watch\0"
4957914d74bSmrg	"xterm";
4967914d74bSmrg
4977914d74bSmrgstatic const unsigned short _XcursorStandardNameOffsets[] = {
4987914d74bSmrg	0, 9, 15, 32, 47, 52, 61, 80, 100, 112, 123, 134, 145, 152, 158,
4997914d74bSmrg	169, 175, 189, 199, 213, 217, 224, 237, 249, 261, 272, 281, 287,
5007914d74bSmrg	295, 301, 307, 313, 319, 324, 335, 344, 354, 363, 374, 383, 392,
5017914d74bSmrg	396, 409, 415, 422, 429, 434, 449, 459, 470, 480, 492, 501, 510,
5027914d74bSmrg	524, 542, 556, 571, 583, 601, 609, 616, 623, 632, 637, 644, 651,
5037914d74bSmrg	666, 682, 699, 708, 716, 721, 730, 739, 748, 754
5047914d74bSmrg};
5057914d74bSmrg
5067914d74bSmrg#define NUM_STANDARD_NAMES  (sizeof _XcursorStandardNameOffsets / sizeof _XcursorStandardNameOffsets[0])
5077914d74bSmrg
5087914d74bSmrg#define STANDARD_NAME(id) \
5097914d74bSmrg    _XcursorStandardNames + _XcursorStandardNameOffsets[id]
5107914d74bSmrg
5117914d74bSmrgXcursorImage *
5127914d74bSmrgXcursorShapeLoadImage (unsigned int shape, const char *theme, int size)
5137914d74bSmrg{
5147914d74bSmrg    unsigned int    id = shape >> 1;
5157914d74bSmrg
5167914d74bSmrg    if (id < NUM_STANDARD_NAMES)
5177914d74bSmrg	return XcursorLibraryLoadImage (STANDARD_NAME (id), theme, size);
5187914d74bSmrg    else
5197914d74bSmrg	return NULL;
5207914d74bSmrg}
5217914d74bSmrg
5227914d74bSmrgXcursorImages *
5237914d74bSmrgXcursorShapeLoadImages (unsigned int shape, const char *theme, int size)
5247914d74bSmrg{
5257914d74bSmrg    unsigned int    id = shape >> 1;
5267914d74bSmrg
5277914d74bSmrg    if (id < NUM_STANDARD_NAMES)
5287914d74bSmrg	return XcursorLibraryLoadImages (STANDARD_NAME (id), theme, size);
5297914d74bSmrg    else
5307914d74bSmrg	return NULL;
5317914d74bSmrg}
5327914d74bSmrg
5337914d74bSmrgCursor
5347914d74bSmrgXcursorShapeLoadCursor (Display *dpy, unsigned int shape)
5357914d74bSmrg{
5367914d74bSmrg    unsigned int    id = shape >> 1;
5377914d74bSmrg
5387914d74bSmrg    if (id < NUM_STANDARD_NAMES)
5397914d74bSmrg	return XcursorLibraryLoadCursor (dpy, STANDARD_NAME (id));
5407914d74bSmrg    else
5417914d74bSmrg	return 0;
5427914d74bSmrg}
5437914d74bSmrg
5447914d74bSmrgXcursorCursors *
5457914d74bSmrgXcursorShapeLoadCursors (Display *dpy, unsigned int shape)
5467914d74bSmrg{
5477914d74bSmrg    unsigned int    id = shape >> 1;
5487914d74bSmrg
5497914d74bSmrg    if (id < NUM_STANDARD_NAMES)
5507914d74bSmrg	return XcursorLibraryLoadCursors (dpy, STANDARD_NAME (id));
5517914d74bSmrg    else
5527914d74bSmrg	return NULL;
5537914d74bSmrg}
5547914d74bSmrg
5557914d74bSmrgint
5567914d74bSmrgXcursorLibraryShape (const char *library)
5577914d74bSmrg{
5587914d74bSmrg    int	low, high;
5597914d74bSmrg
5607914d74bSmrg    low = 0;
5617914d74bSmrg    high = NUM_STANDARD_NAMES - 1;
5627914d74bSmrg    while (low < high - 1)
5637914d74bSmrg    {
5644d939ec7Smrg	int mid = (low + high) >> 1;
5654d939ec7Smrg	int c = strcmp (library, STANDARD_NAME (mid));
5667914d74bSmrg	if (c == 0)
5677914d74bSmrg	    return (mid << 1);
5687914d74bSmrg	if (c > 0)
5697914d74bSmrg	    low = mid;
5707914d74bSmrg	else
5717914d74bSmrg	    high = mid;
5727914d74bSmrg    }
5737914d74bSmrg    while (low <= high)
5747914d74bSmrg    {
5757914d74bSmrg	if (!strcmp (library, STANDARD_NAME (low)))
5767914d74bSmrg	    return (low << 1);
5777914d74bSmrg	low++;
5787914d74bSmrg    }
5797914d74bSmrg    return -1;
5807914d74bSmrg}
581