2 * Copyright (C) 2003 Red Hat, Inc.
4 * This is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Library General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "../config.h"
26 #include <pango/pango.h>
27 #include <fontconfig/fontconfig.h>
33 _vte_fc_weight_from_pango_weight(int weight)
35 /* Cut-and-pasted from Pango. */
36 if (weight < (PANGO_WEIGHT_NORMAL + PANGO_WEIGHT_LIGHT) / 2)
37 return FC_WEIGHT_LIGHT;
38 else if (weight < (PANGO_WEIGHT_NORMAL + 600) / 2)
39 return FC_WEIGHT_MEDIUM;
40 else if (weight < (600 + PANGO_WEIGHT_BOLD) / 2)
41 return FC_WEIGHT_DEMIBOLD;
42 else if (weight < (PANGO_WEIGHT_BOLD + PANGO_WEIGHT_ULTRABOLD) / 2)
43 return FC_WEIGHT_BOLD;
45 return FC_WEIGHT_BLACK;
49 _vte_fc_slant_from_pango_style(int style)
52 case PANGO_STYLE_NORMAL:
53 return FC_SLANT_ROMAN;
55 case PANGO_STYLE_ITALIC:
56 return FC_SLANT_ITALIC;
58 case PANGO_STYLE_OBLIQUE:
59 return FC_SLANT_OBLIQUE;
62 return FC_SLANT_ROMAN;
66 _vte_fc_transcribe_from_pango_font_description(GtkWidget *widget,
68 const PangoFontDescription *font_desc)
70 #if GTK_CHECK_VERSION(2,2,0)
73 const char *family = "monospace";
74 PangoLanguage *language;
77 PangoContext *context;
80 if (font_desc == NULL) {
84 pango_mask = pango_font_description_get_set_fields(font_desc);
86 /* Set the family for the pattern, or use a sensible default. */
87 if (pango_mask & PANGO_FONT_MASK_FAMILY) {
88 family = pango_font_description_get_family(font_desc);
90 FcPatternAddString(pattern, FC_FAMILY, family);
92 /* Set the font size for the pattern, or use a sensible default. */
93 if (pango_mask & PANGO_FONT_MASK_SIZE) {
94 size = pango_font_description_get_size(font_desc);
97 FcPatternAddDouble(pattern, FC_SIZE, size);
99 /* Set the language for the pattern. */
100 #if GTK_CHECK_VERSION(2,2,0)
101 if (gtk_widget_has_screen(widget)) {
102 screen = gtk_widget_get_screen(widget);
104 screen = gdk_display_get_default_screen(gtk_widget_get_display(widget));
106 context = gdk_pango_context_get_for_screen(screen);
108 context = gdk_pango_context_get();
110 language = pango_context_get_language(context);
111 if (pango_language_to_string(language) != NULL) {
112 FcPatternAddString(pattern, FC_LANG,
113 pango_language_to_string(language));
116 /* There aren't any fallbacks for these, so just omit them from the
117 * pattern if they're not set in the pango font. */
118 if (pango_mask & PANGO_FONT_MASK_WEIGHT) {
119 weight = pango_font_description_get_weight(font_desc);
120 FcPatternAddInteger(pattern, FC_WEIGHT,
121 _vte_fc_weight_from_pango_weight(weight));
124 if (pango_mask & PANGO_FONT_MASK_STYLE) {
125 style = pango_font_description_get_style(font_desc);
126 FcPatternAddInteger(pattern, FC_SLANT,
127 _vte_fc_slant_from_pango_style(style));
130 g_object_unref(G_OBJECT(context));
134 _vte_fc_defaults_from_gtk(GtkWidget *widget, FcPattern *pattern)
136 GtkSettings *settings;
137 #if GTK_CHECK_VERSION(2,2,0)
141 int i, antialias = -1, hinting = -1, dpi = -1;
142 char *rgba = NULL, *hintstyle = NULL;
144 /* Add any defaults configured for GTK+. */
145 #if GTK_CHECK_VERSION(2,2,0)
146 if (gtk_widget_has_screen(widget)) {
147 screen = gtk_widget_get_screen(widget);
149 screen = gdk_display_get_default_screen(gtk_widget_get_display(widget));
151 settings = gtk_settings_get_for_screen(screen);
153 settings = gtk_settings_get_default();
155 if (settings == NULL) {
159 /* Check that the properties we're looking at are defined. */
160 klass = G_OBJECT_CLASS(GTK_SETTINGS_GET_CLASS(settings));
161 if (g_object_class_find_property(klass, "gtk-xft-antialias") == NULL) {
165 /* Read the settings. */
166 g_object_get(G_OBJECT(settings),
167 "gtk-xft-antialias", &antialias,
169 "gtk-xft-rgba", &rgba,
170 "gtk-xft-hinting", &hinting,
171 "gtk-xft-hintstyle", &hintstyle,
174 /* Pick up the antialiasing setting. */
175 if (antialias >= 0) {
176 FcPatternDel(pattern, FC_ANTIALIAS);
177 FcPatternAddBool(pattern, FC_ANTIALIAS, antialias > 0);
180 /* Pick up the configured DPI setting. */
182 FcPatternDel(pattern, FC_DPI);
183 FcPatternAddDouble(pattern, FC_DPI, dpi / 1024.0);
186 /* Pick up the configured subpixel rendering setting. */
192 if (g_ascii_strcasecmp(rgba, "none") == 0) {
196 if (g_ascii_strcasecmp(rgba, "rgb") == 0) {
200 if (g_ascii_strcasecmp(rgba, "bgr") == 0) {
204 if (g_ascii_strcasecmp(rgba, "vrgb") == 0) {
208 if (g_ascii_strcasecmp(rgba, "vbgr") == 0) {
215 FcPatternDel(pattern, FC_RGBA);
216 FcPatternAddInteger(pattern, FC_RGBA, i);
221 /* Pick up the configured hinting setting. */
223 FcPatternDel(pattern, FC_HINTING);
224 FcPatternAddBool(pattern, FC_HINTING, hinting > 0);
228 /* Pick up the default hinting style. */
229 if (hintstyle != NULL) {
234 if (g_ascii_strcasecmp(hintstyle, "hintnone") == 0) {
238 if (g_ascii_strcasecmp(hintstyle, "hintslight") == 0) {
242 if (g_ascii_strcasecmp(hintstyle, "hintmedium") == 0) {
246 if (g_ascii_strcasecmp(hintstyle, "hintfull") == 0) {
253 FcPatternDel(pattern, FC_HINT_STYLE);
254 FcPatternAddInteger(pattern, FC_HINT_STYLE, i);
262 _vte_fc_defaults_from_rdb(GtkWidget *widget, FcPattern *pattern)
266 int antialias = -1, hinting = -1, fci;
268 const char *rgba = NULL, *hintstyle = NULL;
270 /* Read the settings. */
271 hintstyle = _vte_rdb_get_hintstyle(widget);
272 rgba = _vte_rdb_get_rgba(widget);
274 /* Pick up the antialiasing setting. */
275 if (FcPatternGetBool(pattern, FC_ANTIALIAS, 0,
276 &fcb) == FcResultNoMatch) {
277 antialias = _vte_rdb_get_antialias(widget);
278 FcPatternAddBool(pattern, FC_ANTIALIAS, antialias);
281 /* Pick up the hinting setting. */
282 if (FcPatternGetBool(pattern, FC_HINTING, 0,
283 &fcb) == FcResultNoMatch) {
284 hinting = _vte_rdb_get_hinting(widget);
285 FcPatternAddBool(pattern, FC_HINTING, hinting);
288 /* Pick up the configured DPI setting. */
289 if (FcPatternGetDouble(pattern, FC_DPI, 0,
290 &fcd) == FcResultNoMatch) {
291 dpi = _vte_rdb_get_dpi(widget);
293 FcPatternAddDouble(pattern, FC_DPI, dpi);
297 /* Pick up the configured subpixel rendering setting. */
298 if (FcPatternGetInteger(pattern, FC_RGBA, 0,
299 &fci) == FcResultNoMatch) {
300 rgba = _vte_rdb_get_rgba(widget);
301 if (g_ascii_strcasecmp(rgba, "none") == 0) {
302 FcPatternAddInteger(pattern, FC_RGBA, FC_RGBA_NONE);
304 if (g_ascii_strcasecmp(rgba, "rgb") == 0) {
305 FcPatternAddInteger(pattern, FC_RGBA, FC_RGBA_RGB);
307 if (g_ascii_strcasecmp(rgba, "bgr") == 0) {
308 FcPatternAddInteger(pattern, FC_RGBA, FC_RGBA_BGR);
310 if (g_ascii_strcasecmp(rgba, "vrgb") == 0) {
311 FcPatternAddInteger(pattern, FC_RGBA, FC_RGBA_VRGB);
313 if (g_ascii_strcasecmp(rgba, "vbgr") == 0) {
314 FcPatternAddInteger(pattern, FC_RGBA, FC_RGBA_VBGR);
319 /* Pick up the default hinting style. */
320 if (FcPatternGetInteger(pattern, FC_HINT_STYLE, 0,
321 &fci) == FcResultNoMatch) {
322 hintstyle = _vte_rdb_get_hintstyle(widget);
323 if (g_ascii_strcasecmp(hintstyle, "hintnone") == 0) {
324 FcPatternAddInteger(pattern, FC_HINT_STYLE,
327 if (g_ascii_strcasecmp(hintstyle, "hintslight") == 0) {
328 FcPatternAddInteger(pattern, FC_HINT_STYLE,
331 if (g_ascii_strcasecmp(hintstyle, "hintmedium") == 0) {
332 FcPatternAddInteger(pattern, FC_HINT_STYLE,
335 if (g_ascii_strcasecmp(hintstyle, "hintfull") == 0) {
336 FcPatternAddInteger(pattern, FC_HINT_STYLE,
343 /* Create a sorted set of fontconfig patterns from a Pango font description
344 * and append them to the array. */
346 _vte_fc_patterns_from_pango_font_desc(GtkWidget *widget,
347 const PangoFontDescription *font_desc,
348 GArray *pattern_array,
349 _vte_fc_defaults_cb defaults_cb,
350 gpointer defaults_data)
353 FcPattern *pattern, *match, *tmp, *save;
356 gboolean ret = FALSE;
359 g_return_val_if_fail(pattern_array != NULL, FALSE);
361 /* Create a scratch pattern. */
362 pattern = FcPatternCreate();
364 /* Transcribe what we can get from the Pango font description. */
365 _vte_fc_transcribe_from_pango_font_description(widget, pattern,
368 /* Add any defaults specified in the configuration. */
369 FcConfigSubstitute(NULL, pattern, FcMatchPattern);
371 /* Add any defaults configured for GTK+. */
372 _vte_fc_defaults_from_gtk(widget, pattern);
374 /* Add defaults configured via the resource database. */
375 _vte_fc_defaults_from_rdb(widget, pattern);
377 /* Add any defaults which are hard-coded in fontconfig. */
378 FcDefaultSubstitute(pattern);
380 /* Add any defaults via a callback. */
381 if (defaults_cb != NULL) {
382 defaults_cb(pattern, defaults_data);
385 /* Get a sorted list of patterns, duplicate them, and append them
386 * to the passed-in array. */
387 fontset = FcFontSort(NULL, pattern, FcTrue, NULL, &result);
388 if (fontset != NULL) {
389 for (i = 0; i < fontset->nfont; i++) {
390 tmp = FcFontRenderPrepare(NULL,
393 _vte_fc_defaults_from_gtk(widget, tmp);
394 save = FcPatternDuplicate(tmp);
395 FcPatternDestroy(tmp);
396 g_array_append_val(pattern_array, save);
398 FcFontSetDestroy(fontset);
402 /* Last ditch effort. */
403 if (pattern_array->len == 0) {
404 match = FcFontMatch(NULL, pattern, &result);
405 if (result == FcResultMatch) {
406 tmp = FcPatternDuplicate(match);
407 _vte_fc_defaults_from_gtk(widget, tmp);
408 save = FcPatternDuplicate(tmp);
409 FcPatternDestroy(tmp);
410 g_array_append_val(pattern_array, save);
417 FcPatternDestroy(pattern);
423 _vte_fc_connect_settings_changes(GtkWidget *widget, GCallback *changed_cb)
425 GtkSettings *settings;
428 /* Get the settings object used by the widget. */
429 settings = gtk_widget_get_settings(widget);
430 if (settings == NULL) {
434 /* Check that the properties we're looking at are defined. */
435 klass = G_OBJECT_CLASS(GTK_SETTINGS_GET_CLASS(settings));
436 if (g_object_class_find_property(klass, "gtk-xft-antialias") == NULL) {
440 /* Start listening for changes to the fontconfig settings. */
441 g_signal_connect(G_OBJECT(settings),
442 "notify::gtk-xft-antialias",
443 G_CALLBACK(changed_cb), widget);
444 g_signal_connect(G_OBJECT(settings),
445 "notify::gtk-xft-hinting",
446 G_CALLBACK(changed_cb), widget);
447 g_signal_connect(G_OBJECT(settings),
448 "notify::gtk-xft-hintstyle",
449 G_CALLBACK(changed_cb), widget);
450 g_signal_connect(G_OBJECT(settings),
451 "notify::gtk-xft-rgba",
452 G_CALLBACK(changed_cb), widget);
453 g_signal_connect(G_OBJECT(settings),
454 "notify::gtk-xft-dpi",
455 G_CALLBACK(changed_cb), widget);
459 _vte_fc_disconnect_settings_changes(GtkWidget *widget, GCallback *changed_cb)
461 GtkSettings *settings;
463 /* Get the settings object used by the widget. */
464 settings = gtk_widget_get_settings(widget);
465 if (settings == NULL) {
469 /* Stop listening for changes to the fontconfig settings. */
470 g_signal_handlers_disconnect_matched(G_OBJECT(settings),
471 G_SIGNAL_MATCH_FUNC |