xftdpy.c revision 0e0b1094
1/*
2 * Copyright © 2000 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Keith Packard not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission.  Keith Packard makes no
11 * representations about the suitability of this software for any purpose.  It
12 * is provided "as is" without express or implied warranty.
13 *
14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#include "xftint.h"
24
25_X_HIDDEN XftDisplayInfo	*_XftDisplayInfo;
26
27static int
28_XftCloseDisplay (Display *dpy, XExtCodes *codes)
29{
30    XftDisplayInfo  *info, **prev;
31
32    info = _XftDisplayInfoGet (dpy, FcFalse);
33    if (!info)
34	return 0;
35
36    /*
37     * Get rid of any dangling unreferenced fonts
38     */
39    info->max_unref_fonts = 0;
40    XftFontManageMemory (dpy);
41
42    /*
43     * Clean up the default values
44     */
45    if (info->defaults)
46	FcPatternDestroy (info->defaults);
47
48    /*
49     * Unhook from the global list
50     */
51    for (prev = &_XftDisplayInfo; (info = *prev); prev = &(*prev)->next)
52	if (info->display == dpy)
53	    break;
54    *prev = info->next;
55
56    free (info);
57    return 0;
58}
59
60
61_X_HIDDEN XftDisplayInfo *
62_XftDisplayInfoGet (Display *dpy, FcBool createIfNecessary)
63{
64    XftDisplayInfo	*info, **prev;
65    XRenderPictFormat	pf;
66    int			i;
67    int			event_base, error_base;
68
69    for (prev = &_XftDisplayInfo; (info = *prev); prev = &(*prev)->next)
70    {
71	if (info->display == dpy)
72	{
73	    /*
74	     * MRU the list
75	     */
76	    if (prev != &_XftDisplayInfo)
77	    {
78		*prev = info->next;
79		info->next = _XftDisplayInfo;
80		_XftDisplayInfo = info;
81	    }
82	    return info;
83	}
84    }
85    if (!createIfNecessary)
86	return NULL;
87
88    info = (XftDisplayInfo *) malloc (sizeof (XftDisplayInfo));
89    if (!info)
90	goto bail0;
91    info->codes = XAddExtension (dpy);
92    if (!info->codes)
93	goto bail1;
94    (void) XESetCloseDisplay (dpy, info->codes->extension, _XftCloseDisplay);
95
96    info->display = dpy;
97    info->defaults = NULL;
98    info->solidFormat = NULL;
99    info->hasRender = (XRenderQueryExtension (dpy, &event_base, &error_base) &&
100		       (XRenderFindVisualFormat (dpy, DefaultVisual (dpy, DefaultScreen (dpy))) != NULL));
101    info->use_free_glyphs = FcTrue;
102    if (info->hasRender)
103    {
104	int major, minor;
105	XRenderQueryVersion (dpy, &major, &minor);
106	if (major < 0 || (major == 0 && minor <= 2))
107	    info->use_free_glyphs = FcFalse;
108
109	info->hasSolid = FcFalse;
110	if (major > 0 || (major == 0 && minor >= 10))
111	    info->hasSolid = FcTrue;
112
113	pf.type = PictTypeDirect;
114	pf.depth = 32;
115	pf.direct.redMask = 0xff;
116	pf.direct.greenMask = 0xff;
117	pf.direct.blueMask = 0xff;
118	pf.direct.alphaMask = 0xff;
119	info->solidFormat = XRenderFindFormat (dpy,
120					       (PictFormatType|
121						PictFormatDepth|
122						PictFormatRedMask|
123						PictFormatGreenMask|
124						PictFormatBlueMask|
125						PictFormatAlphaMask),
126					       &pf,
127					       0);
128    }
129    if (XftDebug () & XFT_DBG_RENDER)
130    {
131	Visual		    *visual = DefaultVisual (dpy, DefaultScreen (dpy));
132	XRenderPictFormat   *format = XRenderFindVisualFormat (dpy, visual);
133
134	printf ("XftDisplayInfoGet Default visual 0x%x ",
135		(int) visual->visualid);
136	if (format)
137	{
138	    if (format->type == PictTypeDirect)
139	    {
140		printf ("format %d,%d,%d,%d\n",
141			format->direct.alpha,
142			format->direct.red,
143			format->direct.green,
144			format->direct.blue);
145	    }
146	    else
147	    {
148		printf ("format indexed\n");
149	    }
150	}
151	else
152	    printf ("No Render format for default visual\n");
153
154	printf ("XftDisplayInfoGet initialized, hasRender set to \"%s\"\n",
155		info->hasRender ? "True" : "False");
156    }
157    for (i = 0; i < XFT_NUM_SOLID_COLOR; i++)
158    {
159	info->colors[i].screen = -1;
160	info->colors[i].pict = 0;
161    }
162    info->fonts = NULL;
163
164    info->next = _XftDisplayInfo;
165    _XftDisplayInfo = info;
166
167    info->glyph_memory = 0;
168    info->max_glyph_memory = (unsigned long)XftDefaultGetInteger (dpy,
169						   XFT_MAX_GLYPH_MEMORY, 0,
170						   XFT_DPY_MAX_GLYPH_MEMORY);
171    if (XftDebug () & XFT_DBG_CACHE)
172	printf ("global max cache memory %ld\n", info->max_glyph_memory);
173
174
175    info->num_unref_fonts = 0;
176    info->max_unref_fonts = XftDefaultGetInteger (dpy,
177						  XFT_MAX_UNREF_FONTS, 0,
178						  XFT_DPY_MAX_UNREF_FONTS);
179    if (XftDebug() & XFT_DBG_CACHE)
180	printf ("global max unref fonts %d\n", info->max_unref_fonts);
181
182    memset (info->fontHash, '\0', sizeof (XftFont *) * XFT_NUM_FONT_HASH);
183    return info;
184
185bail1:
186    free (info);
187bail0:
188    if (XftDebug () & XFT_DBG_RENDER)
189    {
190	printf ("XftDisplayInfoGet failed to initialize, Xft unhappy\n");
191    }
192    return NULL;
193}
194
195/*
196 * Reduce memory usage in X server
197 */
198
199static void
200_XftDisplayValidateMemory (XftDisplayInfo *info)
201{
202    XftFont	    *public;
203    XftFontInt	    *font;
204    unsigned long   glyph_memory;
205
206    glyph_memory = 0;
207    for (public = info->fonts; public; public = font->next)
208    {
209	font = (XftFontInt *) public;
210	glyph_memory += font->glyph_memory;
211    }
212    if (glyph_memory != info->glyph_memory)
213	printf ("Display glyph cache incorrect has %ld bytes, should have %ld\n",
214		info->glyph_memory, glyph_memory);
215}
216
217_X_HIDDEN void
218_XftDisplayManageMemory (Display *dpy)
219{
220    XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, False);
221    unsigned long   glyph_memory;
222    XftFont	    *public;
223    XftFontInt	    *font;
224
225    if (!info || !info->max_glyph_memory)
226	return;
227    if (XftDebug () & XFT_DBG_CACHE)
228    {
229	if (info->glyph_memory > info->max_glyph_memory)
230	    printf ("Reduce global memory from %ld to %ld\n",
231		    info->glyph_memory, info->max_glyph_memory);
232	_XftDisplayValidateMemory (info);
233    }
234    while (info->glyph_memory > info->max_glyph_memory)
235    {
236	glyph_memory = (unsigned long)rand () % info->glyph_memory;
237	public = info->fonts;
238	while (public)
239	{
240	    font = (XftFontInt *) public;
241
242	    if (font->glyph_memory > glyph_memory)
243	    {
244		_XftFontUncacheGlyph (dpy, public);
245		break;
246	    }
247	    public = font->next;
248	    glyph_memory -= font->glyph_memory;
249	}
250    }
251    if (XftDebug () & XFT_DBG_CACHE)
252	_XftDisplayValidateMemory (info);
253}
254
255_X_EXPORT Bool
256XftDefaultHasRender (Display *dpy)
257{
258    XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, True);
259
260    if (!info)
261	return False;
262    return info->hasRender;
263}
264
265_X_EXPORT Bool
266XftDefaultSet (Display *dpy, FcPattern *defaults)
267{
268    XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, True);
269
270    if (!info)
271	return False;
272    if (info->defaults)
273	FcPatternDestroy (info->defaults);
274    info->defaults = defaults;
275    if (!info->max_glyph_memory)
276	info->max_glyph_memory = XFT_DPY_MAX_GLYPH_MEMORY;
277    info->max_glyph_memory = (unsigned long)XftDefaultGetInteger (dpy,
278						   XFT_MAX_GLYPH_MEMORY, 0,
279						   (int)info->max_glyph_memory);
280    if (!info->max_unref_fonts)
281	info->max_unref_fonts = XFT_DPY_MAX_UNREF_FONTS;
282    info->max_unref_fonts = XftDefaultGetInteger (dpy,
283						  XFT_MAX_UNREF_FONTS, 0,
284						  info->max_unref_fonts);
285    return True;
286}
287
288_X_HIDDEN int
289XftDefaultParseBool (const char *v)
290{
291    char    c0, c1;
292
293    c0 = *v;
294    if (isupper ((int)c0))
295	c0 = (char)tolower (c0);
296    if (c0 == 't' || c0 == 'y' || c0 == '1')
297	return 1;
298    if (c0 == 'f' || c0 == 'n' || c0 == '0')
299	return 0;
300    if (c0 == 'o')
301    {
302	c1 = v[1];
303	if (isupper ((int)c1))
304	    c1 = (char)tolower (c1);
305	if (c1 == 'n')
306	    return 1;
307	if (c1 == 'f')
308	    return 0;
309    }
310    return -1;
311}
312
313static Bool
314_XftDefaultInitBool (Display *dpy, FcPattern *pat, const char *option)
315{
316    char    *v;
317    int	    i;
318
319    v = XGetDefault (dpy, "Xft", option);
320    if (v && (i = XftDefaultParseBool (v)) >= 0)
321	return FcPatternAddBool (pat, option, i != 0);
322    return True;
323}
324
325static Bool
326_XftDefaultInitDouble (Display *dpy, FcPattern *pat, const char *option)
327{
328    char    *v, *e;
329    double  d;
330
331    v = XGetDefault (dpy, "Xft", option);
332    if (v)
333    {
334	d = strtod (v, &e);
335	if (e != v)
336	    return FcPatternAddDouble (pat, option, d);
337    }
338    return True;
339}
340
341static Bool
342_XftDefaultInitInteger (Display *dpy, FcPattern *pat, const char *option)
343{
344    char    *v, *e;
345    int	    i;
346
347    v = XGetDefault (dpy, "Xft", option);
348    if (v)
349    {
350	if (FcNameConstant ((FcChar8 *) v, &i))
351	    return FcPatternAddInteger (pat, option, i);
352	i = (int)strtol (v, &e, 0);
353	if (e != v)
354	    return FcPatternAddInteger (pat, option, i);
355    }
356    return True;
357}
358
359static FcPattern *
360_XftDefaultInit (Display *dpy)
361{
362    FcPattern	*pat;
363
364    pat = FcPatternCreate ();
365    if (!pat)
366	goto bail0;
367
368    if (!_XftDefaultInitDouble (dpy, pat, FC_SCALE))
369	goto bail1;
370    if (!_XftDefaultInitDouble (dpy, pat, FC_DPI))
371	goto bail1;
372    if (!_XftDefaultInitBool (dpy, pat, XFT_RENDER))
373	goto bail1;
374    if (!_XftDefaultInitInteger (dpy, pat, FC_RGBA))
375	goto bail1;
376    if (!_XftDefaultInitInteger (dpy, pat, FC_LCD_FILTER))
377	goto bail1;
378    if (!_XftDefaultInitBool (dpy, pat, FC_ANTIALIAS))
379	goto bail1;
380    if (!_XftDefaultInitBool (dpy, pat, FC_EMBOLDEN))
381	goto bail1;
382    if (!_XftDefaultInitBool (dpy, pat, FC_AUTOHINT))
383	goto bail1;
384    if (!_XftDefaultInitInteger (dpy, pat, FC_HINT_STYLE))
385	goto bail1;
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 NULL;
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    if (FcPatternGet (pattern, FC_EMBOLDEN, 0, &v) == FcResultNoMatch)
477    {
478	FcPatternAddBool (pattern, FC_EMBOLDEN,
479			   XftDefaultGetBool (dpy, FC_EMBOLDEN, screen,
480					      False));
481    }
482    if (FcPatternGet (pattern, FC_HINTING, 0, &v) == FcResultNoMatch)
483    {
484	FcPatternAddBool (pattern, FC_HINTING,
485			  XftDefaultGetBool (dpy, FC_HINTING, screen,
486					     True));
487    }
488    if (FcPatternGet (pattern, FC_HINT_STYLE, 0, &v) == FcResultNoMatch)
489    {
490	FcPatternAddInteger (pattern, FC_HINT_STYLE,
491			     XftDefaultGetInteger (dpy, FC_HINT_STYLE, screen,
492						   FC_HINT_FULL));
493    }
494    if (FcPatternGet (pattern, FC_AUTOHINT, 0, &v) == FcResultNoMatch)
495    {
496	FcPatternAddBool (pattern, FC_AUTOHINT,
497			  XftDefaultGetBool (dpy, FC_AUTOHINT, screen,
498					     False));
499    }
500    if (FcPatternGet (pattern, FC_RGBA, 0, &v) == FcResultNoMatch)
501    {
502	int	subpixel = FC_RGBA_UNKNOWN;
503#if RENDER_MAJOR > 0 || RENDER_MINOR >= 6
504	if (XftDefaultHasRender (dpy))
505	{
506	    int render_order = XRenderQuerySubpixelOrder (dpy, screen);
507	    switch (render_order) {
508	    default:
509	    case SubPixelUnknown:	subpixel = FC_RGBA_UNKNOWN; break;
510	    case SubPixelHorizontalRGB:	subpixel = FC_RGBA_RGB; break;
511	    case SubPixelHorizontalBGR:	subpixel = FC_RGBA_BGR; break;
512	    case SubPixelVerticalRGB:	subpixel = FC_RGBA_VRGB; break;
513	    case SubPixelVerticalBGR:	subpixel = FC_RGBA_VBGR; break;
514	    case SubPixelNone:		subpixel = FC_RGBA_NONE; break;
515	    }
516	}
517#endif
518	FcPatternAddInteger (pattern, FC_RGBA,
519			      XftDefaultGetInteger (dpy, FC_RGBA, screen,
520						    subpixel));
521    }
522    if (FcPatternGet (pattern, FC_LCD_FILTER, 0, &v) == FcResultNoMatch)
523    {
524	FcPatternAddInteger (pattern, FC_LCD_FILTER,
525			     XftDefaultGetInteger (dpy, FC_LCD_FILTER, screen,
526						   FC_LCD_DEFAULT));
527    }
528    if (FcPatternGet (pattern, FC_MINSPACE, 0, &v) == FcResultNoMatch)
529    {
530	FcPatternAddBool (pattern, FC_MINSPACE,
531			   XftDefaultGetBool (dpy, FC_MINSPACE, screen,
532					      False));
533    }
534    if (FcPatternGet (pattern, FC_DPI, 0, &v) == FcResultNoMatch)
535    {
536	dpi = (((double) DisplayHeight (dpy, screen) * 25.4) /
537	       (double) DisplayHeightMM (dpy, screen));
538	FcPatternAddDouble (pattern, FC_DPI,
539			    XftDefaultGetDouble (dpy, FC_DPI, screen,
540						 dpi));
541    }
542    if (FcPatternGet (pattern, FC_SCALE, 0, &v) == FcResultNoMatch)
543    {
544	FcPatternAddDouble (pattern, FC_SCALE,
545			    XftDefaultGetDouble (dpy, FC_SCALE, screen, 1.0));
546    }
547    if (FcPatternGet (pattern, XFT_MAX_GLYPH_MEMORY, 0, &v) == FcResultNoMatch)
548    {
549	FcPatternAddInteger (pattern, XFT_MAX_GLYPH_MEMORY,
550			     XftDefaultGetInteger (dpy, XFT_MAX_GLYPH_MEMORY,
551						   screen,
552						   XFT_FONT_MAX_GLYPH_MEMORY));
553    }
554    FcDefaultSubstitute (pattern);
555}
556
557