display.c revision 7914d74b
1/*
2 * $Id: display.c,v 1.1.1.1 2008/07/30 02:45:52 mrg Exp $
3 *
4 * Copyright © 2002 Keith Packard
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of Keith Packard not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission.  Keith Packard makes no
13 * representations about the suitability of this software for any purpose.  It
14 * is provided "as is" without express or implied warranty.
15 *
16 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
23 */
24
25#include "xcursorint.h"
26#include <X11/Xlibint.h>
27#include <ctype.h>
28
29static XcursorDisplayInfo *_XcursorDisplayInfo;
30
31static void
32_XcursorFreeDisplayInfo (XcursorDisplayInfo *info)
33{
34    if (info->theme)
35	free (info->theme);
36
37    if (info->theme_from_config)
38	free (info->theme_from_config);
39
40    free (info);
41}
42
43static int
44_XcursorCloseDisplay (Display *dpy, XExtCodes *codes)
45{
46    XcursorDisplayInfo  *info, **prev;
47
48    /*
49     * Unhook from the global list
50     */
51    _XLockMutex (_Xglobal_lock);
52    for (prev = &_XcursorDisplayInfo; (info = *prev); prev = &(*prev)->next)
53	if (info->display == dpy)
54	{
55            *prev = info->next;
56	    break;
57	}
58    _XUnlockMutex (_Xglobal_lock);
59
60    if (info)
61	_XcursorFreeDisplayInfo (info);
62    return 0;
63}
64
65static int
66_XcursorDefaultParseBool (char *v)
67{
68    char    c0, c1;
69
70    c0 = *v;
71    if (isupper ((int)c0))
72	c0 = tolower (c0);
73    if (c0 == 't' || c0 == 'y' || c0 == '1')
74	return 1;
75    if (c0 == 'f' || c0 == 'n' || c0 == '0')
76	return 0;
77    if (c0 == 'o')
78    {
79	c1 = v[1];
80	if (isupper ((int)c1))
81	    c1 = tolower (c1);
82	if (c1 == 'n')
83	    return 1;
84	if (c1 == 'f')
85	    return 0;
86    }
87    return -1;
88}
89
90XcursorDisplayInfo *
91_XcursorGetDisplayInfo (Display *dpy)
92{
93    XcursorDisplayInfo	*info, **prev, *old;
94    int			event_base, error_base;
95    int			major, minor;
96    char		*v;
97    int			i;
98
99    _XLockMutex (_Xglobal_lock);
100    for (prev = &_XcursorDisplayInfo; (info = *prev); prev = &(*prev)->next)
101    {
102	if (info->display == dpy)
103	{
104	    /*
105	     * MRU the list
106	     */
107	    if (prev != &_XcursorDisplayInfo)
108	    {
109		*prev = info->next;
110		info->next = _XcursorDisplayInfo;
111		_XcursorDisplayInfo = info;
112	    }
113	    break;
114	}
115    }
116    _XUnlockMutex (_Xglobal_lock);
117    if (info)
118        return info;
119    info = (XcursorDisplayInfo *) malloc (sizeof (XcursorDisplayInfo));
120    if (!info)
121	return NULL;
122    info->next = NULL;
123    info->display = dpy;
124
125    info->codes = XAddExtension (dpy);
126    if (!info->codes)
127    {
128	free (info);
129	return NULL;
130    }
131    (void) XESetCloseDisplay (dpy, info->codes->extension, _XcursorCloseDisplay);
132
133    /*
134     * Check whether the display supports the Render CreateCursor request
135     */
136    info->has_render_cursor = XcursorFalse;
137    info->has_anim_cursor = XcursorFalse;
138    if (XRenderQueryExtension (dpy, &event_base, &error_base) &&
139	XRenderQueryVersion (dpy, &major, &minor))
140    {
141	if (major > 0 || minor >= 5)
142	{
143	    info->has_render_cursor = XcursorTrue;
144	    v = getenv ("XCURSOR_CORE");
145	    if (!v)
146		v = XGetDefault (dpy, "Xcursor", "core");
147	    if (v && _XcursorDefaultParseBool (v) == 1)
148		info->has_render_cursor = XcursorFalse;
149	}
150	if (info->has_render_cursor && (major > 0 || minor >= 8))
151	{
152	    info->has_anim_cursor = XcursorTrue;
153	    v = getenv ("XCURSOR_ANIM");
154	    if (!v)
155		v = XGetDefault (dpy, "Xcursor", "anim");
156	    if (v && _XcursorDefaultParseBool (v) == 0)
157		info->has_anim_cursor = XcursorFalse;
158	}
159    }
160
161    info->size = 0;
162
163    /*
164     * Get desired cursor size
165     */
166    v = getenv ("XCURSOR_SIZE");
167    if (!v)
168	v = XGetDefault (dpy, "Xcursor", "size");
169    if (v)
170	info->size = atoi (v);
171
172    /*
173     * Use the Xft size to guess a size; make cursors 16 "points" tall
174     */
175    if (info->size == 0)
176    {
177	int dpi = 0;
178	v = XGetDefault (dpy, "Xft", "dpi");
179	if (v)
180	    dpi = atoi (v);
181	if (dpi)
182	    info->size = dpi * 16 / 72;
183    }
184
185    /*
186     * Use display size to guess a size
187     */
188    if (info->size == 0)
189    {
190	int dim;
191
192	if (DisplayHeight (dpy, DefaultScreen (dpy)) <
193	    DisplayWidth (dpy, DefaultScreen (dpy)))
194	    dim = DisplayHeight (dpy, DefaultScreen (dpy));
195	else
196	    dim = DisplayWidth (dpy, DefaultScreen (dpy));
197	/*
198	 * 16 pixels on a display of dimension 768
199	 */
200	info->size = dim / 48;
201    }
202
203    info->theme = NULL;
204    info->theme_from_config = NULL;
205
206    /*
207     * Get the desired theme
208     */
209    v = getenv ("XCURSOR_THEME");
210    if (!v)
211	v = XGetDefault (dpy, "Xcursor", "theme");
212    if (v)
213    {
214	int len;
215
216	len = strlen (v) + 1;
217
218	info->theme = malloc (len);
219	if (info->theme)
220	    strcpy (info->theme, v);
221
222	info->theme_from_config = malloc (len);
223	if (info->theme_from_config)
224	    strcpy (info->theme_from_config, v);
225    }
226
227    /*
228     * Get the desired dither
229     */
230    info->dither = XcursorDitherThreshold;
231    v = getenv ("XCURSOR_DITHER");
232    if (!v)
233	v = XGetDefault (dpy, "Xcursor", "dither");
234    if (v)
235    {
236	if (!strcmp (v, "threshold"))
237	    info->dither = XcursorDitherThreshold;
238	if (!strcmp (v, "median"))
239	    info->dither = XcursorDitherMedian;
240	if (!strcmp (v, "ordered"))
241	    info->dither = XcursorDitherOrdered;
242	if (!strcmp (v, "diffuse"))
243	    info->dither = XcursorDitherDiffuse;
244    }
245
246    info->theme_core = False;
247    /*
248     * Find out if core cursors should
249     * be themed
250     */
251    v = getenv ("XCURSOR_THEME_CORE");
252    if (!v)
253	v = XGetDefault (dpy, "Xcursor", "theme_core");
254    if (v)
255    {
256	i = _XcursorDefaultParseBool (v);
257	if (i >= 0)
258	    info->theme_core = i;
259    }
260
261    info->fonts = NULL;
262    for (i = 0; i < NUM_BITMAPS; i++)
263	info->bitmaps[i].bitmap = None;
264
265    /*
266     * Link new info info list, making sure another
267     * thread hasn't inserted something into the list while
268     * this one was busy setting up the data
269     */
270    _XLockMutex (_Xglobal_lock);
271    for (old = _XcursorDisplayInfo; old; old = old->next)
272	if (old->display == dpy)
273	    break;
274    if (old)
275    {
276	_XcursorFreeDisplayInfo (info);
277	info = old;
278    }
279    else
280    {
281	info->next = _XcursorDisplayInfo;
282	_XcursorDisplayInfo = info;
283    }
284    _XUnlockMutex (_Xglobal_lock);
285
286    return info;
287}
288
289XcursorBool
290XcursorSupportsARGB (Display *dpy)
291{
292    XcursorDisplayInfo	*info = _XcursorGetDisplayInfo (dpy);
293
294    return info && info->has_render_cursor;
295}
296
297XcursorBool
298XcursorSupportsAnim (Display *dpy)
299{
300    XcursorDisplayInfo	*info = _XcursorGetDisplayInfo (dpy);
301
302    return info && info->has_anim_cursor;
303}
304
305XcursorBool
306XcursorSetDefaultSize (Display *dpy, int size)
307{
308    XcursorDisplayInfo	*info = _XcursorGetDisplayInfo (dpy);
309
310    if (!info)
311	return XcursorFalse;
312    info->size = size;
313    return XcursorTrue;
314}
315
316int
317XcursorGetDefaultSize (Display *dpy)
318{
319    XcursorDisplayInfo	*info = _XcursorGetDisplayInfo (dpy);
320
321    if (!info)
322	return 0;
323    return info->size;
324}
325
326XcursorBool
327XcursorSetTheme (Display *dpy, const char *theme)
328{
329    XcursorDisplayInfo	*info = _XcursorGetDisplayInfo (dpy);
330    char		*copy;
331
332    if (!info)
333	return XcursorFalse;
334
335    if (!theme)
336	theme = info->theme_from_config;
337
338    if (theme)
339    {
340	copy = malloc (strlen (theme) + 1);
341	if (!copy)
342	    return XcursorFalse;
343	strcpy (copy, theme);
344    }
345    else
346	copy = NULL;
347    if (info->theme)
348	free (info->theme);
349    info->theme = copy;
350    return XcursorTrue;
351}
352
353char *
354XcursorGetTheme (Display *dpy)
355{
356    XcursorDisplayInfo	*info = _XcursorGetDisplayInfo (dpy);
357
358    if (!info)
359	return NULL;
360    return info->theme;
361}
362
363XcursorBool
364XcursorGetThemeCore (Display *dpy)
365{
366    XcursorDisplayInfo	*info = _XcursorGetDisplayInfo (dpy);
367
368    if (!info)
369	return XcursorFalse;
370    return info->theme_core;
371
372}
373
374XcursorBool
375XcursorSetThemeCore (Display *dpy, XcursorBool theme_core)
376{
377    XcursorDisplayInfo	*info = _XcursorGetDisplayInfo (dpy);
378
379    if (!info)
380	return XcursorFalse;
381    info->theme_core = theme_core;
382    return XcursorTrue;
383}
384