#include "xcursorint.h"
#include <X11/Xlibint.h>
#include <ctype.h>
static XcursorDisplayInfo *_XcursorDisplayInfo;
static void
_XcursorFreeDisplayInfo (XcursorDisplayInfo *info)
{
if (info->theme)
free (info->theme);
if (info->theme_from_config)
free (info->theme_from_config);
free (info);
}
static int
_XcursorCloseDisplay (Display *dpy, XExtCodes *codes)
{
XcursorDisplayInfo *info, **prev;
_XLockMutex (_Xglobal_lock);
for (prev = &_XcursorDisplayInfo; (info = *prev); prev = &(*prev)->next)
if (info->display == dpy)
{
*prev = info->next;
break;
}
_XUnlockMutex (_Xglobal_lock);
if (info)
_XcursorFreeDisplayInfo (info);
return 0;
}
static int
_XcursorDefaultParseBool (char *v)
{
char c0, c1;
c0 = *v;
if (isupper ((int)c0))
c0 = tolower (c0);
if (c0 == 't' || c0 == 'y' || c0 == '1')
return 1;
if (c0 == 'f' || c0 == 'n' || c0 == '0')
return 0;
if (c0 == 'o')
{
c1 = v[1];
if (isupper ((int)c1))
c1 = tolower (c1);
if (c1 == 'n')
return 1;
if (c1 == 'f')
return 0;
}
return -1;
}
XcursorDisplayInfo *
_XcursorGetDisplayInfo (Display *dpy)
{
XcursorDisplayInfo *info, **prev, *old;
int event_base, error_base;
int major, minor;
char *v;
int i;
_XLockMutex (_Xglobal_lock);
for (prev = &_XcursorDisplayInfo; (info = *prev); prev = &(*prev)->next)
{
if (info->display == dpy)
{
if (prev != &_XcursorDisplayInfo)
{
*prev = info->next;
info->next = _XcursorDisplayInfo;
_XcursorDisplayInfo = info;
}
break;
}
}
_XUnlockMutex (_Xglobal_lock);
if (info)
return info;
info = (XcursorDisplayInfo *) malloc (sizeof (XcursorDisplayInfo));
if (!info)
return NULL;
info->next = NULL;
info->display = dpy;
info->codes = XAddExtension (dpy);
if (!info->codes)
{
free (info);
return NULL;
}
(void) XESetCloseDisplay (dpy, info->codes->extension, _XcursorCloseDisplay);
info->has_render_cursor = XcursorFalse;
info->has_anim_cursor = XcursorFalse;
if (XRenderQueryExtension (dpy, &event_base, &error_base) &&
XRenderQueryVersion (dpy, &major, &minor))
{
if (major > 0 || minor >= 5)
{
info->has_render_cursor = XcursorTrue;
v = getenv ("XCURSOR_CORE");
if (!v)
v = XGetDefault (dpy, "Xcursor", "core");
if (v && _XcursorDefaultParseBool (v) == 1)
info->has_render_cursor = XcursorFalse;
}
if (info->has_render_cursor && (major > 0 || minor >= 8))
{
info->has_anim_cursor = XcursorTrue;
v = getenv ("XCURSOR_ANIM");
if (!v)
v = XGetDefault (dpy, "Xcursor", "anim");
if (v && _XcursorDefaultParseBool (v) == 0)
info->has_anim_cursor = XcursorFalse;
}
}
info->size = 0;
v = getenv ("XCURSOR_SIZE");
if (!v)
v = XGetDefault (dpy, "Xcursor", "size");
if (v)
info->size = atoi (v);
if (info->size == 0)
{
int dpi = 0;
v = XGetDefault (dpy, "Xft", "dpi");
if (v)
dpi = atoi (v);
if (dpi)
info->size = dpi * 16 / 72;
}
if (info->size == 0)
{
int dim;
if (DisplayHeight (dpy, DefaultScreen (dpy)) <
DisplayWidth (dpy, DefaultScreen (dpy)))
dim = DisplayHeight (dpy, DefaultScreen (dpy));
else
dim = DisplayWidth (dpy, DefaultScreen (dpy));
info->size = dim / 48;
}
info->theme = NULL;
info->theme_from_config = NULL;
v = getenv ("XCURSOR_THEME");
if (!v)
v = XGetDefault (dpy, "Xcursor", "theme");
if (v)
{
int len;
len = strlen (v) + 1;
info->theme = malloc (len);
if (info->theme)
strcpy (info->theme, v);
info->theme_from_config = malloc (len);
if (info->theme_from_config)
strcpy (info->theme_from_config, v);
}
info->dither = XcursorDitherThreshold;
v = getenv ("XCURSOR_DITHER");
if (!v)
v = XGetDefault (dpy, "Xcursor", "dither");
if (v)
{
if (!strcmp (v, "threshold"))
info->dither = XcursorDitherThreshold;
if (!strcmp (v, "median"))
info->dither = XcursorDitherMedian;
if (!strcmp (v, "ordered"))
info->dither = XcursorDitherOrdered;
if (!strcmp (v, "diffuse"))
info->dither = XcursorDitherDiffuse;
}
info->theme_core = False;
v = getenv ("XCURSOR_THEME_CORE");
if (!v)
v = XGetDefault (dpy, "Xcursor", "theme_core");
if (v)
{
i = _XcursorDefaultParseBool (v);
if (i >= 0)
info->theme_core = i;
}
info->fonts = NULL;
for (i = 0; i < NUM_BITMAPS; i++)
info->bitmaps[i].bitmap = None;
_XLockMutex (_Xglobal_lock);
for (old = _XcursorDisplayInfo; old; old = old->next)
if (old->display == dpy)
break;
if (old)
{
_XcursorFreeDisplayInfo (info);
info = old;
}
else
{
info->next = _XcursorDisplayInfo;
_XcursorDisplayInfo = info;
}
_XUnlockMutex (_Xglobal_lock);
return info;
}
XcursorBool
XcursorSupportsARGB (Display *dpy)
{
XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy);
return info && info->has_render_cursor;
}
XcursorBool
XcursorSupportsAnim (Display *dpy)
{
XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy);
return info && info->has_anim_cursor;
}
XcursorBool
XcursorSetDefaultSize (Display *dpy, int size)
{
XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy);
if (!info)
return XcursorFalse;
info->size = size;
return XcursorTrue;
}
int
XcursorGetDefaultSize (Display *dpy)
{
XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy);
if (!info)
return 0;
return info->size;
}
XcursorBool
XcursorSetTheme (Display *dpy, const char *theme)
{
XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy);
char *copy;
if (!info)
return XcursorFalse;
if (!theme)
theme = info->theme_from_config;
if (theme)
{
copy = malloc (strlen (theme) + 1);
if (!copy)
return XcursorFalse;
strcpy (copy, theme);
}
else
copy = NULL;
if (info->theme)
free (info->theme);
info->theme = copy;
return XcursorTrue;
}
char *
XcursorGetTheme (Display *dpy)
{
XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy);
if (!info)
return NULL;
return info->theme;
}
XcursorBool
XcursorGetThemeCore (Display *dpy)
{
XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy);
if (!info)
return XcursorFalse;
return info->theme_core;
}
XcursorBool
XcursorSetThemeCore (Display *dpy, XcursorBool theme_core)
{
XcursorDisplayInfo *info = _XcursorGetDisplayInfo (dpy);
if (!info)
return XcursorFalse;
info->theme_core = theme_core;
return XcursorTrue;
}