xftdpy.c revision c76ae52d
1/*
2 * $Id: xftdpy.c,v 1.1.1.1 2008/07/30 02:49:10 mrg Exp $
3 *
4 * Copyright © 2000 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 "xftint.h"
26
27_X_HIDDEN XftDisplayInfo	*_XftDisplayInfo;
28
29static int
30_XftCloseDisplay (Display *dpy, XExtCodes *codes)
31{
32    XftDisplayInfo  *info, **prev;
33
34    info = _XftDisplayInfoGet (dpy, FcFalse);
35    if (!info)
36	return 0;
37
38    /*
39     * Get rid of any dangling unreferenced fonts
40     */
41    info->max_unref_fonts = 0;
42    XftFontManageMemory (dpy);
43
44    /*
45     * Clean up the default values
46     */
47    if (info->defaults)
48	FcPatternDestroy (info->defaults);
49
50    /*
51     * Unhook from the global list
52     */
53    for (prev = &_XftDisplayInfo; (info = *prev); prev = &(*prev)->next)
54	if (info->display == dpy)
55	    break;
56    *prev = info->next;
57
58    free (info);
59    return 0;
60}
61
62
63_X_HIDDEN XftDisplayInfo *
64_XftDisplayInfoGet (Display *dpy, FcBool createIfNecessary)
65{
66    XftDisplayInfo	*info, **prev;
67    XRenderPictFormat	pf;
68    int			i;
69    int			event_base, error_base;
70
71    for (prev = &_XftDisplayInfo; (info = *prev); prev = &(*prev)->next)
72    {
73	if (info->display == dpy)
74	{
75	    /*
76	     * MRU the list
77	     */
78	    if (prev != &_XftDisplayInfo)
79	    {
80		*prev = info->next;
81		info->next = _XftDisplayInfo;
82		_XftDisplayInfo = info;
83	    }
84	    return info;
85	}
86    }
87    if (!createIfNecessary)
88	return 0;
89
90    info = (XftDisplayInfo *) malloc (sizeof (XftDisplayInfo));
91    if (!info)
92	goto bail0;
93    info->codes = XAddExtension (dpy);
94    if (!info->codes)
95	goto bail1;
96    (void) XESetCloseDisplay (dpy, info->codes->extension, _XftCloseDisplay);
97
98    info->display = dpy;
99    info->defaults = 0;
100    info->solidFormat = 0;
101    info->hasRender = (XRenderQueryExtension (dpy, &event_base, &error_base) &&
102		       (XRenderFindVisualFormat (dpy, DefaultVisual (dpy, DefaultScreen (dpy))) != 0));
103    info->use_free_glyphs = FcTrue;
104    if (info->hasRender)
105    {
106	int major, minor;
107	XRenderQueryVersion (dpy, &major, &minor);
108	if (major < 0 || (major == 0 && minor <= 2))
109	    info->use_free_glyphs = FcFalse;
110
111	pf.type = PictTypeDirect;
112	pf.depth = 32;
113	pf.direct.redMask = 0xff;
114	pf.direct.greenMask = 0xff;
115	pf.direct.blueMask = 0xff;
116	pf.direct.alphaMask = 0xff;
117	info->solidFormat = XRenderFindFormat (dpy,
118					       (PictFormatType|
119						PictFormatDepth|
120						PictFormatRedMask|
121						PictFormatGreenMask|
122						PictFormatBlueMask|
123						PictFormatAlphaMask),
124					       &pf,
125					       0);
126    }
127    if (XftDebug () & XFT_DBG_RENDER)
128    {
129	Visual		    *visual = DefaultVisual (dpy, DefaultScreen (dpy));
130	XRenderPictFormat   *format = XRenderFindVisualFormat (dpy, visual);
131
132	printf ("XftDisplayInfoGet Default visual 0x%x ",
133		(int) visual->visualid);
134	if (format)
135	{
136	    if (format->type == PictTypeDirect)
137	    {
138		printf ("format %d,%d,%d,%d\n",
139			format->direct.alpha,
140			format->direct.red,
141			format->direct.green,
142			format->direct.blue);
143	    }
144	    else
145	    {
146		printf ("format indexed\n");
147	    }
148	}
149	else
150	    printf ("No Render format for default visual\n");
151
152	printf ("XftDisplayInfoGet initialized, hasRender set to \"%s\"\n",
153		info->hasRender ? "True" : "False");
154    }
155    for (i = 0; i < XFT_NUM_SOLID_COLOR; i++)
156    {
157	info->colors[i].screen = -1;
158	info->colors[i].pict = 0;
159    }
160    info->fonts = 0;
161
162    info->next = _XftDisplayInfo;
163    _XftDisplayInfo = info;
164
165    info->glyph_memory = 0;
166    info->max_glyph_memory = XftDefaultGetInteger (dpy,
167						   XFT_MAX_GLYPH_MEMORY, 0,
168						   XFT_DPY_MAX_GLYPH_MEMORY);
169    if (XftDebug () & XFT_DBG_CACHE)
170	printf ("global max cache memory %ld\n", info->max_glyph_memory);
171
172
173    info->num_unref_fonts = 0;
174    info->max_unref_fonts = XftDefaultGetInteger (dpy,
175						  XFT_MAX_UNREF_FONTS, 0,
176						  XFT_DPY_MAX_UNREF_FONTS);
177    if (XftDebug() & XFT_DBG_CACHE)
178	printf ("global max unref fonts %d\n", info->max_unref_fonts);
179
180    memset (info->fontHash, '\0', sizeof (XftFont *) * XFT_NUM_FONT_HASH);
181    return info;
182
183bail1:
184    free (info);
185bail0:
186    if (XftDebug () & XFT_DBG_RENDER)
187    {
188	printf ("XftDisplayInfoGet failed to initialize, Xft unhappy\n");
189    }
190    return 0;
191}
192
193/*
194 * Reduce memory usage in X server
195 */
196
197static void
198_XftDisplayValidateMemory (XftDisplayInfo *info)
199{
200    XftFont	    *public;
201    XftFontInt	    *font;
202    unsigned long   glyph_memory;
203
204    glyph_memory = 0;
205    for (public = info->fonts; public; public = font->next)
206    {
207	font = (XftFontInt *) public;
208	glyph_memory += font->glyph_memory;
209    }
210    if (glyph_memory != info->glyph_memory)
211	printf ("Display glyph cache incorrect has %ld bytes, should have %ld\n",
212		info->glyph_memory, glyph_memory);
213}
214
215_X_HIDDEN void
216_XftDisplayManageMemory (Display *dpy)
217{
218    XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, False);
219    unsigned long   glyph_memory;
220    XftFont	    *public;
221    XftFontInt	    *font;
222
223    if (!info || !info->max_glyph_memory)
224	return;
225    if (XftDebug () & XFT_DBG_CACHE)
226    {
227	if (info->glyph_memory > info->max_glyph_memory)
228	    printf ("Reduce global memory from %ld to %ld\n",
229		    info->glyph_memory, info->max_glyph_memory);
230	_XftDisplayValidateMemory (info);
231    }
232    while (info->glyph_memory > info->max_glyph_memory)
233    {
234	glyph_memory = rand () % info->glyph_memory;
235	public = info->fonts;
236	while (public)
237	{
238	    font = (XftFontInt *) public;
239
240	    if (font->glyph_memory > glyph_memory)
241	    {
242		_XftFontUncacheGlyph (dpy, public);
243		break;
244	    }
245	    public = font->next;
246	    glyph_memory -= font->glyph_memory;
247	}
248    }
249    if (XftDebug () & XFT_DBG_CACHE)
250	_XftDisplayValidateMemory (info);
251}
252
253_X_EXPORT Bool
254XftDefaultHasRender (Display *dpy)
255{
256    XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, True);
257
258    if (!info)
259	return False;
260    return info->hasRender;
261}
262
263_X_EXPORT Bool
264XftDefaultSet (Display *dpy, FcPattern *defaults)
265{
266    XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, True);
267
268    if (!info)
269	return False;
270    if (info->defaults)
271	FcPatternDestroy (info->defaults);
272    info->defaults = defaults;
273    if (!info->max_glyph_memory)
274	info->max_glyph_memory = XFT_DPY_MAX_GLYPH_MEMORY;
275    info->max_glyph_memory = XftDefaultGetInteger (dpy,
276						   XFT_MAX_GLYPH_MEMORY, 0,
277						   info->max_glyph_memory);
278    if (!info->max_unref_fonts)
279	info->max_unref_fonts = XFT_DPY_MAX_UNREF_FONTS;
280    info->max_unref_fonts = XftDefaultGetInteger (dpy,
281						  XFT_MAX_UNREF_FONTS, 0,
282						  info->max_unref_fonts);
283    return True;
284}
285
286_X_HIDDEN int
287XftDefaultParseBool (char *v)
288{
289    char    c0, c1;
290
291    c0 = *v;
292    if (isupper ((int)c0))
293	c0 = tolower (c0);
294    if (c0 == 't' || c0 == 'y' || c0 == '1')
295	return 1;
296    if (c0 == 'f' || c0 == 'n' || c0 == '0')
297	return 0;
298    if (c0 == 'o')
299    {
300	c1 = v[1];
301	if (isupper ((int)c1))
302	    c1 = tolower (c1);
303	if (c1 == 'n')
304	    return 1;
305	if (c1 == 'f')
306	    return 0;
307    }
308    return -1;
309}
310
311static Bool
312_XftDefaultInitBool (Display *dpy, FcPattern *pat, char *option)
313{
314    char    *v;
315    int	    i;
316
317    v = XGetDefault (dpy, "Xft", option);
318    if (v && (i = XftDefaultParseBool (v)) >= 0)
319	return FcPatternAddBool (pat, option, i != 0);
320    return True;
321}
322
323static Bool
324_XftDefaultInitDouble (Display *dpy, FcPattern *pat, char *option)
325{
326    char    *v, *e;
327    double  d;
328
329    v = XGetDefault (dpy, "Xft", option);
330    if (v)
331    {
332	d = strtod (v, &e);
333	if (e != v)
334	    return FcPatternAddDouble (pat, option, d);
335    }
336    return True;
337}
338
339static Bool
340_XftDefaultInitInteger (Display *dpy, FcPattern *pat, char *option)
341{
342    char    *v, *e;
343    int	    i;
344
345    v = XGetDefault (dpy, "Xft", option);
346    if (v)
347    {
348	if (FcNameConstant ((FcChar8 *) v, &i))
349	    return FcPatternAddInteger (pat, option, i);
350	i = strtol (v, &e, 0);
351	if (e != v)
352	    return FcPatternAddInteger (pat, option, i);
353    }
354    return True;
355}
356
357static FcPattern *
358_XftDefaultInit (Display *dpy)
359{
360    FcPattern	*pat;
361
362    pat = FcPatternCreate ();
363    if (!pat)
364	goto bail0;
365
366    if (!_XftDefaultInitDouble (dpy, pat, FC_SCALE))
367	goto bail1;
368    if (!_XftDefaultInitDouble (dpy, pat, FC_DPI))
369	goto bail1;
370    if (!_XftDefaultInitBool (dpy, pat, XFT_RENDER))
371	goto bail1;
372    if (!_XftDefaultInitInteger (dpy, pat, FC_RGBA))
373	goto bail1;
374    if (!_XftDefaultInitBool (dpy, pat, FC_ANTIALIAS))
375	goto bail1;
376#ifdef FC_EMBOLDEN
377    if (!_XftDefaultInitBool (dpy, pat, FC_EMBOLDEN))
378	goto bail1;
379#endif
380    if (!_XftDefaultInitBool (dpy, pat, FC_AUTOHINT))
381	goto bail1;
382#ifdef FC_HINT_STYLE
383    if (!_XftDefaultInitInteger (dpy, pat, FC_HINT_STYLE))
384	goto bail1;
385#endif
386    if (!_XftDefaultInitBool (dpy, pat, FC_HINTING))
387	goto bail1;
388    if (!_XftDefaultInitBool (dpy, pat, FC_MINSPACE))
389	goto bail1;
390    if (!_XftDefaultInitInteger (dpy, pat, XFT_MAX_GLYPH_MEMORY))
391	goto bail1;
392
393    return pat;
394
395bail1:
396    FcPatternDestroy (pat);
397bail0:
398    return 0;
399}
400
401static FcResult
402_XftDefaultGet (Display *dpy, const char *object, int screen, FcValue *v)
403{
404    XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, True);
405    FcResult	    r;
406
407    if (!info)
408	return FcResultNoMatch;
409
410    if (!info->defaults)
411    {
412	info->defaults = _XftDefaultInit (dpy);
413	if (!info->defaults)
414	    return FcResultNoMatch;
415    }
416    r = FcPatternGet (info->defaults, object, screen, v);
417    if (r == FcResultNoId && screen > 0)
418	r = FcPatternGet (info->defaults, object, 0, v);
419    return r;
420}
421
422_X_HIDDEN Bool
423XftDefaultGetBool (Display *dpy, const char *object, int screen, Bool def)
424{
425    FcResult	    r;
426    FcValue	    v;
427
428    r = _XftDefaultGet (dpy, object, screen, &v);
429    if (r != FcResultMatch || v.type != FcTypeBool)
430	return def;
431    return v.u.b;
432}
433
434_X_HIDDEN int
435XftDefaultGetInteger (Display *dpy, const char *object, int screen, int def)
436{
437    FcResult	    r;
438    FcValue	    v;
439
440    r = _XftDefaultGet (dpy, object, screen, &v);
441    if (r != FcResultMatch || v.type != FcTypeInteger)
442	return def;
443    return v.u.i;
444}
445
446_X_HIDDEN double
447XftDefaultGetDouble (Display *dpy, const char *object, int screen, double def)
448{
449    FcResult	    r;
450    FcValue	    v;
451
452    r = _XftDefaultGet (dpy, object, screen, &v);
453    if (r != FcResultMatch || v.type != FcTypeDouble)
454	return def;
455    return v.u.d;
456}
457
458_X_EXPORT void
459XftDefaultSubstitute (Display *dpy, int screen, FcPattern *pattern)
460{
461    FcValue	v;
462    double	dpi;
463
464    if (FcPatternGet (pattern, XFT_RENDER, 0, &v) == FcResultNoMatch)
465    {
466	FcPatternAddBool (pattern, XFT_RENDER,
467			   XftDefaultGetBool (dpy, XFT_RENDER, screen,
468					      XftDefaultHasRender (dpy)));
469    }
470    if (FcPatternGet (pattern, FC_ANTIALIAS, 0, &v) == FcResultNoMatch)
471    {
472	FcPatternAddBool (pattern, FC_ANTIALIAS,
473			   XftDefaultGetBool (dpy, FC_ANTIALIAS, screen,
474					      True));
475    }
476#ifdef FC_EMBOLDEN
477    if (FcPatternGet (pattern, FC_EMBOLDEN, 0, &v) == FcResultNoMatch)
478    {
479	FcPatternAddBool (pattern, FC_EMBOLDEN,
480			   XftDefaultGetBool (dpy, FC_EMBOLDEN, screen,
481					      False));
482    }
483#endif
484    if (FcPatternGet (pattern, FC_HINTING, 0, &v) == FcResultNoMatch)
485    {
486	FcPatternAddBool (pattern, FC_HINTING,
487			  XftDefaultGetBool (dpy, FC_HINTING, screen,
488					     True));
489    }
490#ifdef FC_HINT_STYLE
491    if (FcPatternGet (pattern, FC_HINT_STYLE, 0, &v) == FcResultNoMatch)
492    {
493	FcPatternAddInteger (pattern, FC_HINT_STYLE,
494			     XftDefaultGetInteger (dpy, FC_HINT_STYLE, screen,
495						   FC_HINT_FULL));
496    }
497#endif
498    if (FcPatternGet (pattern, FC_AUTOHINT, 0, &v) == FcResultNoMatch)
499    {
500	FcPatternAddBool (pattern, FC_AUTOHINT,
501			  XftDefaultGetBool (dpy, FC_AUTOHINT, screen,
502					     False));
503    }
504    if (FcPatternGet (pattern, FC_RGBA, 0, &v) == FcResultNoMatch)
505    {
506	int	subpixel = FC_RGBA_UNKNOWN;
507#if RENDER_MAJOR > 0 || RENDER_MINOR >= 6
508	if (XftDefaultHasRender (dpy))
509	{
510	    int render_order = XRenderQuerySubpixelOrder (dpy, screen);
511	    switch (render_order) {
512	    default:
513	    case SubPixelUnknown:	subpixel = FC_RGBA_UNKNOWN; break;
514	    case SubPixelHorizontalRGB:	subpixel = FC_RGBA_RGB; break;
515	    case SubPixelHorizontalBGR:	subpixel = FC_RGBA_BGR; break;
516	    case SubPixelVerticalRGB:	subpixel = FC_RGBA_VRGB; break;
517	    case SubPixelVerticalBGR:	subpixel = FC_RGBA_VBGR; break;
518	    case SubPixelNone:		subpixel = FC_RGBA_NONE; break;
519	    }
520	}
521#endif
522	FcPatternAddInteger (pattern, FC_RGBA,
523			      XftDefaultGetInteger (dpy, FC_RGBA, screen,
524						    subpixel));
525    }
526    if (FcPatternGet (pattern, FC_MINSPACE, 0, &v) == FcResultNoMatch)
527    {
528	FcPatternAddBool (pattern, FC_MINSPACE,
529			   XftDefaultGetBool (dpy, FC_MINSPACE, screen,
530					      False));
531    }
532    if (FcPatternGet (pattern, FC_DPI, 0, &v) == FcResultNoMatch)
533    {
534	dpi = (((double) DisplayHeight (dpy, screen) * 25.4) /
535	       (double) DisplayHeightMM (dpy, screen));
536	FcPatternAddDouble (pattern, FC_DPI,
537			    XftDefaultGetDouble (dpy, FC_DPI, screen,
538						 dpi));
539    }
540    if (FcPatternGet (pattern, FC_SCALE, 0, &v) == FcResultNoMatch)
541    {
542	FcPatternAddDouble (pattern, FC_SCALE,
543			    XftDefaultGetDouble (dpy, FC_SCALE, screen, 1.0));
544    }
545    if (FcPatternGet (pattern, XFT_MAX_GLYPH_MEMORY, 0, &v) == FcResultNoMatch)
546    {
547	FcPatternAddInteger (pattern, XFT_MAX_GLYPH_MEMORY,
548			     XftDefaultGetInteger (dpy, XFT_MAX_GLYPH_MEMORY,
549						   screen,
550						   XFT_FONT_MAX_GLYPH_MEMORY));
551    }
552    FcDefaultSubstitute (pattern);
553}
554
555