384 lines
8.4 KiB
C
384 lines
8.4 KiB
C
/*
|
|
* $Id: display.c,v 1.1.1.1 2006/11/25 17:00:28 matthieu Exp $
|
|
*
|
|
* Copyright © 2002 Keith Packard
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
* the above copyright notice appear in all copies and that both that
|
|
* copyright notice and this permission notice appear in supporting
|
|
* documentation, and that the name of Keith Packard not be used in
|
|
* advertising or publicity pertaining to distribution of the software without
|
|
* specific, written prior permission. Keith Packard makes no
|
|
* representations about the suitability of this software for any purpose. It
|
|
* is provided "as is" without express or implied warranty.
|
|
*
|
|
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#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;
|
|
|
|
/*
|
|
* Unhook from the global list
|
|
*/
|
|
_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)
|
|
{
|
|
/*
|
|
* MRU the list
|
|
*/
|
|
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);
|
|
|
|
/*
|
|
* Check whether the display supports the Render CreateCursor request
|
|
*/
|
|
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;
|
|
|
|
/*
|
|
* Get desired cursor size
|
|
*/
|
|
v = getenv ("XCURSOR_SIZE");
|
|
if (!v)
|
|
v = XGetDefault (dpy, "Xcursor", "size");
|
|
if (v)
|
|
info->size = atoi (v);
|
|
|
|
/*
|
|
* Use the Xft size to guess a size; make cursors 16 "points" tall
|
|
*/
|
|
if (info->size == 0)
|
|
{
|
|
int dpi = 0;
|
|
v = XGetDefault (dpy, "Xft", "dpi");
|
|
if (v)
|
|
dpi = atoi (v);
|
|
if (dpi)
|
|
info->size = dpi * 16 / 72;
|
|
}
|
|
|
|
/*
|
|
* Use display size to guess a size
|
|
*/
|
|
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));
|
|
/*
|
|
* 16 pixels on a display of dimension 768
|
|
*/
|
|
info->size = dim / 48;
|
|
}
|
|
|
|
info->theme = NULL;
|
|
info->theme_from_config = NULL;
|
|
|
|
/*
|
|
* Get the desired theme
|
|
*/
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* Get the desired dither
|
|
*/
|
|
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;
|
|
/*
|
|
* Find out if core cursors should
|
|
* be themed
|
|
*/
|
|
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;
|
|
|
|
/*
|
|
* Link new info info list, making sure another
|
|
* thread hasn't inserted something into the list while
|
|
* this one was busy setting up the data
|
|
*/
|
|
_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;
|
|
}
|