summaryrefslogtreecommitdiff
path: root/trunk/pango/pangox-fontmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/pango/pangox-fontmap.c')
-rw-r--r--trunk/pango/pangox-fontmap.c1675
1 files changed, 1675 insertions, 0 deletions
diff --git a/trunk/pango/pangox-fontmap.c b/trunk/pango/pangox-fontmap.c
new file mode 100644
index 00000000..3681b939
--- /dev/null
+++ b/trunk/pango/pangox-fontmap.c
@@ -0,0 +1,1675 @@
+/* Pango
+ * pangox-fontmap.c: X font handling
+ *
+ * Copyright (C) 2000 Red Hat Software
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+
+#include <X11/Xatom.h>
+
+/* For XExtSetCloseDisplay */
+#include <X11/Xlibint.h>
+
+#include "pango-engine-private.h"
+#include "pango-fontmap.h"
+#include "pango-impl-utils.h"
+
+#undef PANGO_DISABLE_DEPRECATED
+
+#include "pangox-private.h"
+
+typedef struct _PangoXFamily PangoXFamily;
+typedef struct _PangoXSizeInfo PangoXSizeInfo;
+
+/* Number of freed fonts */
+#define MAX_FREED_FONTS 16
+
+/* This is the largest field length we will accept. If a fontname has a field
+ larger than this we will skip it. */
+#define XLFD_MAX_FIELD_LEN 64
+#define MAX_FONTS 32767
+
+/* These are the field numbers in the X Logical Font Description fontnames,
+ e.g. -adobe-courier-bold-o-normal--25-180-100-100-m-150-iso8859-1 */
+typedef enum
+{
+ XLFD_FOUNDRY = 0,
+ XLFD_FAMILY = 1,
+ XLFD_WEIGHT = 2,
+ XLFD_SLANT = 3,
+ XLFD_SET_WIDTH = 4,
+ XLFD_ADD_STYLE = 5,
+ XLFD_PIXELS = 6,
+ XLFD_POINTS = 7,
+ XLFD_RESOLUTION_X = 8,
+ XLFD_RESOLUTION_Y = 9,
+ XLFD_SPACING = 10,
+ XLFD_AVERAGE_WIDTH = 11,
+ XLFD_CHARSET = 12,
+ XLFD_NUM_FIELDS
+} FontField;
+
+struct _PangoXFamily
+{
+ PangoFontFamily parent_instance;
+
+ char *family_name;
+ GSList *font_entries;
+};
+
+struct _PangoXFace
+{
+ PangoFontFace parent_instance;
+
+ char *xlfd;
+ PangoFontDescription *description;
+ PangoCoverage *coverage;
+
+ char *face_name;
+
+ GSList *cached_fonts;
+};
+
+struct _PangoXSizeInfo
+{
+ char *identifier;
+ GSList *xlfds;
+};
+
+static const struct {
+ const gchar text[12];
+ PangoWeight value;
+} weights_map[] = {
+ { "light", 300 },
+ { "regular", 400 },
+ { "book", 400 },
+ { "medium", 500 },
+ { "semibold", 600 },
+ { "demibold", 600 },
+ { "bold", 700 },
+ { "extrabold", 800 },
+ { "ultrabold", 800 },
+ { "heavy", 900 },
+ { "black", 900 }
+};
+
+static const struct {
+ const gchar text[4];
+ PangoStyle value;
+} styles_map[] = {
+ { "r", PANGO_STYLE_NORMAL },
+ { "i", PANGO_STYLE_ITALIC },
+ { "o", PANGO_STYLE_OBLIQUE }
+};
+
+static const struct {
+ const gchar text[16];
+ PangoStretch value;
+} stretches_map[] = {
+ { "normal", PANGO_STRETCH_NORMAL },
+ { "semicondensed", PANGO_STRETCH_SEMI_CONDENSED },
+ { "condensed", PANGO_STRETCH_CONDENSED },
+};
+
+static void pango_x_font_map_init (PangoXFontMap *fontmap);
+static void pango_x_font_map_class_init (PangoFontMapClass *class);
+
+static void pango_x_font_map_finalize (GObject *object);
+static PangoFont *pango_x_font_map_load_font (PangoFontMap *fontmap,
+ PangoContext *context,
+ const PangoFontDescription *description);
+static void pango_x_font_map_list_families (PangoFontMap *fontmap,
+ PangoFontFamily ***families,
+ int *n_families);
+
+static void pango_x_fontmap_cache_clear (PangoXFontMap *xfontmap);
+static void pango_x_font_map_read_aliases (PangoXFontMap *xfontmap);
+
+static gint pango_x_get_size (PangoXFontMap *fontmap,
+ const char *fontname);
+static void pango_x_insert_font (PangoXFontMap *fontmap,
+ const char *fontname);
+static gboolean pango_x_is_xlfd_font_name (const char *fontname);
+static char * pango_x_get_xlfd_field (const char *fontname,
+ FontField field_num,
+ char *buffer);
+static char * pango_x_get_identifier (const char *fontname);
+
+
+#define PANGO_X_TYPE_FAMILY (pango_x_family_get_type ())
+#define PANGO_X_FAMILY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_X_TYPE_FAMILY, PangoXFamily))
+#define PANGO_X_IS_FAMILY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_X_TYPE_FAMILY))
+
+GType pango_x_family_get_type (void);
+
+
+#define PANGO_X_TYPE_FACE (pango_x_face_get_type ())
+#define PANGO_X_FACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_X_TYPE_FACE, PangoXFace))
+#define PANGO_X_IS_FACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_X_TYPE_FACE))
+
+GType pango_x_face_get_type (void);
+
+
+static PangoFontClass *font_map_parent_class; /* Parent class structure for PangoXFontMap */
+
+GType
+pango_x_font_map_get_type (void)
+{
+ static GType object_type = 0;
+
+ if (G_UNLIKELY (!object_type))
+ {
+ const GTypeInfo object_info =
+ {
+ sizeof (PangoFontMapClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) pango_x_font_map_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (PangoXFontMap),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) pango_x_font_map_init,
+ NULL /* value_table */
+ };
+
+ object_type = g_type_register_static (PANGO_TYPE_FONT_MAP,
+ I_("PangoXFontMap"),
+ &object_info, 0);
+ }
+
+ return object_type;
+}
+
+static void
+pango_x_font_map_init (PangoXFontMap *xfontmap)
+{
+ xfontmap->families = g_hash_table_new (g_str_hash, g_str_equal);
+ xfontmap->size_infos = g_hash_table_new (g_str_hash, g_str_equal);
+ xfontmap->to_atom_cache = g_hash_table_new (g_str_hash, g_str_equal);
+ xfontmap->from_atom_cache = g_hash_table_new (g_direct_hash, g_direct_equal);
+ xfontmap->n_fonts = 0;
+}
+
+static void
+pango_x_font_map_class_init (PangoFontMapClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ font_map_parent_class = g_type_class_peek_parent (class);
+
+ object_class->finalize = pango_x_font_map_finalize;
+ class->load_font = pango_x_font_map_load_font;
+ class->list_families = pango_x_font_map_list_families;
+ class->shape_engine_type = PANGO_RENDER_TYPE_X;
+}
+
+/*
+ * Hackery to set up notification when a Display is closed
+ */
+static GSList *registered_displays;
+
+static int
+close_display_cb (Display *display,
+ XExtCodes *extcodes)
+{
+ pango_x_shutdown_display (display);
+ registered_displays = g_slist_remove (registered_displays, display);
+
+ return 0;
+}
+
+static void
+register_display (Display *display)
+{
+ XExtCodes *extcodes;
+ GSList *tmp_list;
+
+ for (tmp_list = registered_displays; tmp_list; tmp_list = tmp_list->next)
+ {
+ if (tmp_list->data == display)
+ return;
+ }
+
+ registered_displays = g_slist_prepend (registered_displays, display);
+
+ extcodes = XAddExtension (display);
+ XESetCloseDisplay (display, extcodes->extension, close_display_cb);
+}
+
+static GList *fontmaps = NULL;
+
+/**
+ * pango_x_font_map_for_display:
+ * @display: an X #Display.
+ *
+ * Returns a #PangoXFontMap for @display. Font maps are cached and should
+ * not be freed. If the font map for a display is no longer needed, it can
+ * be released with pango_x_shutdown_display().
+ *
+ * Return value: a #PangoXFontMap for @display.
+ **/
+PangoFontMap *
+pango_x_font_map_for_display (Display *display)
+{
+ PangoXFontMap *xfontmap;
+ GList *tmp_list = fontmaps;
+ char **xfontnames;
+ int num_fonts, i;
+ int screen;
+
+ g_return_val_if_fail (display != NULL, NULL);
+
+ /* Make sure that the type system is initialized */
+ g_type_init ();
+
+ while (tmp_list)
+ {
+ xfontmap = tmp_list->data;
+
+ if (xfontmap->display == display)
+ return PANGO_FONT_MAP (xfontmap);
+
+ tmp_list = tmp_list->next;
+ }
+
+ xfontmap = g_object_new (PANGO_TYPE_X_FONT_MAP, NULL);
+
+ xfontmap->display = display;
+ xfontmap->font_cache = pango_x_font_cache_new (display);
+ xfontmap->freed_fonts = g_queue_new ();
+
+ /* Get a maximum of MAX_FONTS fontnames from the X server.
+ Use "-*" as the pattern rather than "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" since
+ the latter may result in fonts being returned which don't actually exist.
+ xlsfonts also uses "*" so I think it's OK. "-*" gets rid of aliases. */
+ xfontnames = XListFonts (xfontmap->display, "-*", MAX_FONTS, &num_fonts);
+ if (num_fonts == MAX_FONTS)
+ g_warning("MAX_FONTS exceeded. Some fonts may be missing.");
+
+ /* Insert the font families into the main table */
+ for (i = 0; i < num_fonts; i++)
+ {
+ if (pango_x_is_xlfd_font_name (xfontnames[i]))
+ pango_x_insert_font (xfontmap, xfontnames[i]);
+ }
+
+ XFreeFontNames (xfontnames);
+
+ pango_x_font_map_read_aliases (xfontmap);
+
+ fontmaps = g_list_prepend (fontmaps, xfontmap);
+
+ /* This is a little screwed up, since different screens on the same display
+ * might have different resolutions
+ */
+ screen = DefaultScreen (xfontmap->display);
+ xfontmap->resolution = (PANGO_SCALE * 72.27 / 25.4) * ((double) DisplayWidthMM (xfontmap->display, screen) /
+ DisplayWidth (xfontmap->display, screen));
+
+ register_display (xfontmap->display);
+
+ return PANGO_FONT_MAP (xfontmap);
+}
+
+/**
+ * pango_x_shutdown_display:
+ * @display: an X #Display
+ *
+ * Free cached resources for the given X display structure.
+ **/
+void
+pango_x_shutdown_display (Display *display)
+{
+ GList *tmp_list;
+
+ g_return_if_fail (display != NULL);
+
+ tmp_list = fontmaps;
+ while (tmp_list)
+ {
+ PangoXFontMap *xfontmap = tmp_list->data;
+
+ if (xfontmap->display == display)
+ {
+ fontmaps = g_list_delete_link (fontmaps, tmp_list);
+ pango_x_fontmap_cache_clear (xfontmap);
+ g_object_unref (xfontmap);
+
+ return;
+ }
+
+ tmp_list = tmp_list->next;
+ }
+}
+
+static void
+pango_x_font_map_finalize (GObject *object)
+{
+ PangoXFontMap *xfontmap = PANGO_X_FONT_MAP (object);
+
+ g_list_foreach (xfontmap->freed_fonts->head, (GFunc)g_object_unref, NULL);
+ g_queue_free (xfontmap->freed_fonts);
+
+ pango_x_font_cache_free (xfontmap->font_cache);
+
+ /* FIXME: Lots more here */
+
+ fontmaps = g_list_remove (fontmaps, xfontmap);
+
+ G_OBJECT_CLASS (font_map_parent_class)->finalize (object);
+}
+
+static void
+list_families_foreach (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ GSList **list = user_data;
+
+ *list = g_slist_prepend (*list, value);
+}
+
+static void
+pango_x_font_map_list_families (PangoFontMap *fontmap,
+ PangoFontFamily ***families,
+ int *n_families)
+{
+ GSList *family_list = NULL;
+ GSList *tmp_list;
+ PangoXFontMap *xfontmap = (PangoXFontMap *)fontmap;
+
+ if (!n_families)
+ return;
+
+ g_hash_table_foreach (xfontmap->families, list_families_foreach, &family_list);
+
+ *n_families = g_slist_length (family_list);
+
+ if (families)
+ {
+ int i = 0;
+
+ *families = g_new (PangoFontFamily *, *n_families);
+
+ tmp_list = family_list;
+ while (tmp_list)
+ {
+ (*families)[i] = tmp_list->data;
+ i++;
+ tmp_list = tmp_list->next;
+ }
+ }
+
+ g_slist_free (family_list);
+}
+
+static PangoXFamily *
+pango_x_get_font_family (PangoXFontMap *xfontmap,
+ const char *family_name)
+{
+ PangoXFamily *font_family = g_hash_table_lookup (xfontmap->families, family_name);
+ if (!font_family)
+ {
+ font_family = g_object_new (PANGO_X_TYPE_FAMILY, NULL);
+ font_family->family_name = g_strdup (family_name);
+ font_family->font_entries = NULL;
+
+ g_hash_table_insert (xfontmap->families, font_family->family_name, font_family);
+ }
+
+ return font_family;
+}
+
+static PangoFont *
+pango_x_font_map_load_font (PangoFontMap *fontmap,
+ PangoContext *context,
+ const PangoFontDescription *description)
+{
+ PangoXFontMap *xfontmap = (PangoXFontMap *)fontmap;
+ PangoXFamily *font_family;
+ PangoFont *result = NULL;
+ GSList *tmp_list;
+ gchar *name;
+ gint size;
+
+ g_return_val_if_fail (description != NULL, NULL);
+
+ name = g_ascii_strdown (pango_font_description_get_family (description), -1);
+ size = pango_font_description_get_size (description);
+
+ if (size < 0)
+ return NULL;
+
+ font_family = g_hash_table_lookup (xfontmap->families, name);
+ if (font_family)
+ {
+ PangoXFace *best_match = NULL;
+
+ tmp_list = font_family->font_entries;
+ while (tmp_list)
+ {
+ PangoXFace *font_entry = tmp_list->data;
+
+ if (pango_font_description_better_match (description,
+ best_match ? best_match->description : NULL,
+ font_entry->description))
+ best_match = font_entry;
+
+ tmp_list = tmp_list->next;
+ }
+
+ if (best_match)
+ {
+ GSList *tmp_list = best_match->cached_fonts;
+
+ while (tmp_list)
+ {
+ PangoXFont *xfont = tmp_list->data;
+ if (xfont->size == size)
+ {
+ result = (PangoFont *)xfont;
+
+ g_object_ref (result);
+ if (xfont->in_cache)
+ pango_x_fontmap_cache_remove (fontmap, xfont);
+
+ break;
+ }
+ tmp_list = tmp_list->next;
+ }
+
+ if (!result)
+ {
+ PangoXFont *xfont = pango_x_font_new (fontmap, best_match->xlfd, size);
+
+ xfont->fontmap = fontmap;
+ xfont->xface = best_match;
+ best_match->cached_fonts = g_slist_prepend (best_match->cached_fonts, xfont);
+
+ result = (PangoFont *)xfont;
+ }
+ }
+ }
+
+ g_free (name);
+ return result;
+}
+
+
+/************************
+ * Coverage Map Caching *
+ ************************/
+
+/* We need to be robust against errors accessing the coverage
+ * cache window, since it is not our window. So we temporarily
+ * set this error handler while accessing it. The error_occurred
+ * global allows us to tell whether an error occurred for
+ * XChangeProperty
+ */
+static gboolean error_occurred;
+
+static int
+ignore_error (Display *d,
+ XErrorEvent *e)
+{
+ return 0;
+}
+
+/* Retrieve the coverage window for the given display.
+ * We look for a property on the root window, and then
+ * check that the window that property points to also
+ * has the same property pointing to itself. The second
+ * check allows us to make sure that a stale property
+ * isn't just pointing to some other apps window
+ */
+static Window
+pango_x_real_get_coverage_win (Display *display)
+{
+ Atom type;
+ int format;
+ gulong n_items;
+ gulong bytes_after;
+ guchar *data;
+ Window retval = None;
+ int (*old_handler) (Display *, XErrorEvent *);
+
+ Atom coverage_win_atom = XInternAtom (display,
+ "PANGO_COVERAGE_WIN",
+ False);
+
+ XGetWindowProperty (display,
+ DefaultRootWindow (display),
+ coverage_win_atom,
+ 0, 4,
+ False, XA_WINDOW,
+ &type, &format, &n_items, &bytes_after,
+ &data);
+
+ if (type == XA_WINDOW)
+ {
+ if (format == 32 && n_items == 1 && bytes_after == 0)
+ retval = *(Atom *)data;
+
+ XFree (data);
+ }
+
+ old_handler= XSetErrorHandler (ignore_error);
+
+ if (XGetWindowProperty (display,
+ retval,
+ coverage_win_atom,
+ 0, 4,
+ False, XA_WINDOW,
+ &type, &format, &n_items, &bytes_after,
+ &data) == Success &&
+ type == XA_WINDOW)
+ {
+ if (format != 32 || n_items != 1 || bytes_after != 0 ||
+ *(Atom *)data != retval)
+ retval = None;
+
+ XFree (data);
+ }
+ else
+ retval = None;
+
+ XSync (display, False);
+ XSetErrorHandler (old_handler);
+
+ return retval;
+}
+
+/* Find or create the persistent window for caching font coverage
+ * information.
+ *
+ * To assure atomic creation, we first look for the window, then if we
+ * don't find it, grab the server, look for it again, and then if that
+ * still didn't find it, create it and ungrab.
+ */
+static Window
+pango_x_get_coverage_win (PangoXFontMap *xfontmap)
+{
+ if (!xfontmap->coverage_win)
+ xfontmap->coverage_win = pango_x_real_get_coverage_win (xfontmap->display);
+
+ if (!xfontmap->coverage_win)
+ {
+ Display *persistant_display;
+
+ persistant_display = XOpenDisplay (DisplayString (xfontmap->display));
+ if (!persistant_display)
+ {
+ g_warning ("Cannot create or retrieve display for font coverage cache");
+ return None;
+ }
+
+ XGrabServer (persistant_display);
+
+ xfontmap->coverage_win = pango_x_real_get_coverage_win (xfontmap->display);
+ if (!xfontmap->coverage_win)
+ {
+ XSetWindowAttributes attr;
+
+ attr.override_redirect = True;
+
+ XSetCloseDownMode (persistant_display, RetainPermanent);
+
+ xfontmap->coverage_win =
+ XCreateWindow (persistant_display,
+ DefaultRootWindow (persistant_display),
+ -100, -100, 10, 10, 0, 0,
+ InputOnly, CopyFromParent,
+ CWOverrideRedirect, &attr);
+
+ XChangeProperty (persistant_display,
+ DefaultRootWindow (persistant_display),
+ XInternAtom (persistant_display,
+ "PANGO_COVERAGE_WIN",
+ FALSE),
+ XA_WINDOW,
+ 32, PropModeReplace,
+ (guchar *)&xfontmap->coverage_win, 1);
+
+
+ XChangeProperty (persistant_display,
+ xfontmap->coverage_win,
+ XInternAtom (persistant_display,
+ "PANGO_COVERAGE_WIN",
+ FALSE),
+ XA_WINDOW,
+ 32, PropModeReplace,
+ (guchar *)&xfontmap->coverage_win, 1);
+ }
+
+ XUngrabServer (persistant_display);
+
+ XSync (persistant_display, False);
+ XCloseDisplay (persistant_display);
+ }
+
+ return xfontmap->coverage_win;
+}
+
+/* Find the cached value for the coverage map on the
+ * coverage cache window, if it exists. *atom is set
+ * to the interned value of str for later use in storing
+ * the property if the lookup fails
+ */
+static PangoCoverage *
+pango_x_get_cached_coverage (PangoXFontMap *xfontmap,
+ const char *str,
+ Atom *atom)
+{
+ int (*old_handler) (Display *, XErrorEvent *);
+ Window coverage_win;
+ PangoCoverage *result = NULL;
+
+ Atom type;
+ int format;
+ int tries = 5;
+ gulong n_items;
+ gulong bytes_after;
+ guchar *data;
+
+ *atom = XInternAtom (xfontmap->display, str, False);
+
+ while (tries--)
+ {
+ coverage_win = pango_x_get_coverage_win (xfontmap);
+
+ if (!coverage_win)
+ return NULL;
+
+ old_handler= XSetErrorHandler (ignore_error);
+
+ if (XGetWindowProperty (xfontmap->display,
+ coverage_win, *atom,
+ 0, G_MAXLONG,
+ False, XA_STRING,
+ &type, &format, &n_items, &bytes_after,
+ &data) == Success
+ && type == XA_STRING)
+ {
+ if (format == 8 && bytes_after == 0)
+ result = pango_coverage_from_bytes (data, n_items);
+
+ XSetErrorHandler (old_handler);
+ XFree (data);
+ break;
+ }
+ else
+ {
+ /* Window disappeared out from under us */
+ XSetErrorHandler (old_handler);
+ xfontmap->coverage_win = None;
+ }
+
+ }
+
+ return result;
+}
+
+/* Store the given coverage map on the coverage cache window.
+ * atom is the intern'ed value of the string that identifies
+ * the cache entry.
+ */
+static void
+pango_x_store_cached_coverage (PangoXFontMap *xfontmap,
+ Atom atom,
+ PangoCoverage *coverage)
+{
+ int (*old_handler) (Display *, XErrorEvent *);
+ guchar *bytes;
+ gint size;
+
+ int tries = 5;
+
+ pango_coverage_to_bytes (coverage, &bytes, &size);
+
+ while (tries--)
+ {
+ Window coverage_win = pango_x_get_coverage_win (xfontmap);
+
+ if (!coverage_win)
+ break;
+
+ old_handler = XSetErrorHandler (ignore_error);
+ error_occurred = False;
+
+ XChangeProperty (xfontmap->display,
+ coverage_win,
+ atom,
+ XA_STRING,
+ 8, PropModeReplace,
+ bytes, size);
+
+ XSync (xfontmap->display, False);
+ XSetErrorHandler (old_handler);
+
+ if (!error_occurred)
+ break;
+ else
+ {
+ /* Window disappeared out from under us */
+ XSetErrorHandler (old_handler);
+ xfontmap->coverage_win = None;
+ }
+ }
+
+ g_free (bytes);
+}
+
+
+static void
+pango_x_font_map_read_alias_file (PangoXFontMap *xfontmap,
+ const char *filename)
+{
+ FILE *infile;
+ char **xlfds;
+ int lineno = 0;
+ int i;
+ PangoXFace *xface = NULL;
+
+ infile = fopen (filename, "r");
+ if (infile)
+ {
+ GString *line_buf = g_string_new (NULL);
+ GString *tmp_buf = g_string_new (NULL);
+ gint lines_read;
+
+ while ((lines_read = pango_read_line (infile, line_buf)))
+ {
+ PangoXFamily *font_family;
+ PangoStyle style;
+ PangoVariant variant;
+ PangoWeight weight;
+ PangoStretch stretch;
+
+ const char *p = line_buf->str;
+
+ lineno += lines_read;
+
+ if (!pango_skip_space (&p))
+ continue;
+
+ if (!pango_scan_string (&p, tmp_buf))
+ goto error;
+
+ xface = g_object_new (PANGO_X_TYPE_FACE, NULL);
+ xface->xlfd = NULL;
+ xface->description = pango_font_description_new ();
+
+ g_string_ascii_down (tmp_buf);
+ pango_font_description_set_family (xface->description, tmp_buf->str);
+
+ if (!pango_scan_string (&p, tmp_buf))
+ goto error;
+
+ if (!pango_parse_style (tmp_buf->str, &style, TRUE))
+ goto error;
+ pango_font_description_set_style (xface->description, style);
+
+ if (!pango_scan_string (&p, tmp_buf))
+ goto error;
+
+ if (!pango_parse_variant (tmp_buf->str, &variant, TRUE))
+ goto error;
+ pango_font_description_set_variant (xface->description, variant);
+
+ if (!pango_scan_string (&p, tmp_buf))
+ goto error;
+
+ if (!pango_parse_weight (tmp_buf->str, &weight, TRUE))
+ goto error;
+ pango_font_description_set_weight (xface->description, weight);
+
+ if (!pango_scan_string (&p, tmp_buf))
+ goto error;
+
+ if (!pango_parse_stretch (tmp_buf->str, &stretch, TRUE))
+ goto error;
+ pango_font_description_set_stretch (xface->description, stretch);
+
+ if (!pango_scan_string (&p, tmp_buf))
+ goto error;
+
+ /* Remove excess whitespace and check for complete fields */
+
+ xlfds = g_strsplit (tmp_buf->str, ",", -1);
+ for (i=0; xlfds[i]; i++)
+ {
+ char *trimmed = pango_trim_string (xlfds[i]);
+ g_free (xlfds[i]);
+ xlfds[i] = trimmed;
+
+ if (!pango_x_is_xlfd_font_name (xlfds[i]))
+ {
+ g_warning ("XLFD '%s' must be complete (14 fields)", xlfds[i]);
+ g_strfreev (xlfds);
+ goto error;
+ }
+ }
+
+ xface->xlfd = g_strjoinv (",", xlfds);
+ g_strfreev (xlfds);
+
+ /* Insert the font entry into our structures */
+
+ font_family = pango_x_get_font_family (xfontmap,
+ pango_font_description_get_family (xface->description));
+ font_family->font_entries = g_slist_prepend (font_family->font_entries, xface);
+ xfontmap->n_fonts++;
+
+ /* Save space by consolidating duplicated string */
+ pango_font_description_set_family_static (xface->description, font_family->family_name);
+ xface->cached_fonts = NULL;
+ xface->coverage = NULL;
+ }
+
+ if (ferror (infile))
+ g_warning ("Error reading '%s': %s", filename, g_strerror(errno));
+
+ goto out;
+
+ error:
+ if (xface)
+ {
+ g_free (xface->xlfd);
+ if (xface->description)
+ pango_font_description_free (xface->description);
+ g_free (xface);
+ }
+
+ g_warning ("Error parsing line %d of alias file '%s'", lineno, filename);
+
+ out:
+ g_string_free (tmp_buf, TRUE);
+ g_string_free (line_buf, TRUE);
+
+ fclose (infile);
+ }
+
+}
+
+static void
+pango_x_font_map_read_aliases (PangoXFontMap *xfontmap)
+{
+ char **files;
+ char *files_str = pango_config_key_get ("PangoX/AliasFiles");
+ int n;
+
+ if (!files_str)
+ files_str = g_strdup ("~/.pangox_aliases:" SYSCONFDIR "/pango/pangox.aliases");
+
+ files = pango_split_file_list (files_str);
+
+ n = 0;
+ while (files[n])
+ n++;
+
+ while (n-- > 0)
+ pango_x_font_map_read_alias_file (xfontmap, files[n]);
+
+ g_strfreev (files);
+ g_free (files_str);
+}
+
+/*
+ * Returns %TRUE if the fontname is a valid XLFD.
+ * (It just checks if the number of dashes is 14, and that each
+ * field < XLFD_MAX_FIELD_LEN characters long - that's not in the XLFD but it
+ * makes it easier for me).
+ */
+static gboolean
+pango_x_is_xlfd_font_name (const char *fontname)
+{
+ int i = 0;
+ int field_len = 0;
+
+ while (*fontname)
+ {
+ if (*fontname++ == '-')
+ {
+ if (field_len > XLFD_MAX_FIELD_LEN) return FALSE;
+ field_len = 0;
+ i++;
+ }
+ else
+ field_len++;
+ }
+
+ return (i == 14) ? TRUE : FALSE;
+}
+
+static int
+pango_x_get_size (PangoXFontMap *xfontmap, const char *fontname)
+{
+ char size_buffer[XLFD_MAX_FIELD_LEN];
+ int size;
+
+ if (!pango_x_get_xlfd_field (fontname, XLFD_PIXELS, size_buffer))
+ return -1;
+
+ size = atoi (size_buffer);
+ if (size != 0)
+ {
+ return (int)(0.5 + size * xfontmap->resolution);
+ }
+ else
+ {
+ /* We use the trick that scaled bitmaps have a non-zero RESOLUTION_X, while
+ * actual scaleable fonts have a zero RESOLUTION_X */
+ if (!pango_x_get_xlfd_field (fontname, XLFD_RESOLUTION_X, size_buffer))
+ return -1;
+
+ if (atoi (size_buffer) == 0)
+ return 0;
+ else
+ return -1;
+ }
+}
+
+static char *
+pango_x_get_identifier (const char *fontname)
+{
+ const char *p = fontname;
+ const char *start;
+ int n_dashes = 0;
+
+ while (n_dashes < 2)
+ {
+ if (*p == '-')
+ n_dashes++;
+ p++;
+ }
+
+ start = p;
+
+ while (n_dashes < 6)
+ {
+ if (*p == '-')
+ n_dashes++;
+ p++;
+ }
+
+ return g_strndup (start, (p - 1 - start));
+}
+
+/*
+ * This fills the buffer with the specified field from the X Logical Font
+ * Description name, and returns it. If fontname is %NULL or the field is
+ * longer than XFLD_MAX_FIELD_LEN it returns %NULL.
+ * Note: For the charset field, we also return the encoding, e.g. 'iso8859-1'.
+ */
+static char*
+pango_x_get_xlfd_field (const char *fontname,
+ FontField field_num,
+ char *buffer)
+{
+ const char *t1, *t2;
+ char *p;
+ int countdown, len, num_dashes;
+
+ if (!fontname)
+ return NULL;
+
+ /* we assume this is a valid fontname...that is, it has 14 fields */
+
+ countdown = field_num;
+ t1 = fontname;
+ while (*t1 && (countdown >= 0))
+ if (*t1++ == '-')
+ countdown--;
+
+ num_dashes = (field_num == XLFD_CHARSET) ? 2 : 1;
+ for (t2 = t1; *t2; t2++)
+ {
+ if (*t2 == '-' && --num_dashes == 0)
+ break;
+ }
+
+ if (t1 != t2)
+ {
+ /* Check we don't overflow the buffer */
+ len = (long) t2 - (long) t1;
+ if (len > XLFD_MAX_FIELD_LEN - 1)
+ return NULL;
+ strncpy (buffer, t1, len);
+ buffer[len] = 0;
+ /* Convert to lower case. */
+ for (p = buffer; *p; p++)
+ *p = g_ascii_tolower (*p);
+ }
+ else
+ strcpy(buffer, "(nil)");
+
+ return buffer;
+}
+
+/* This inserts the given fontname into the FontInfo table.
+ If a FontInfo already exists with the same family and foundry, then the
+ fontname is added to the FontInfos list of fontnames, else a new FontInfo
+ is created and inserted in alphabetical order in the table. */
+static void
+pango_x_insert_font (PangoXFontMap *xfontmap,
+ const char *fontname)
+{
+ PangoFontDescription *description;
+ char *family_name;
+ PangoStyle style;
+ PangoVariant variant;
+ PangoWeight weight;
+ PangoStretch stretch;
+ char family_buffer[XLFD_MAX_FIELD_LEN];
+ char weight_buffer[XLFD_MAX_FIELD_LEN];
+ char slant_buffer[XLFD_MAX_FIELD_LEN];
+ char set_width_buffer[XLFD_MAX_FIELD_LEN];
+ GSList *tmp_list;
+ PangoXFamily *font_family;
+ PangoXFace *xface;
+ PangoXSizeInfo *size_info;
+ char *identifier;
+ unsigned int i;
+
+ /* First insert the XLFD into the list of XLFDs for the "identifier" - which
+ * is the 2-4th fields of the XLFD
+ */
+ identifier = pango_x_get_identifier (fontname);
+ size_info = g_hash_table_lookup (xfontmap->size_infos, identifier);
+ if (!size_info)
+ {
+ size_info = g_new (PangoXSizeInfo, 1);
+ size_info->identifier = identifier;
+ size_info->xlfds = NULL;
+
+ g_hash_table_insert (xfontmap->size_infos, identifier, size_info);
+ }
+ else
+ g_free (identifier);
+
+ size_info->xlfds = g_slist_prepend (size_info->xlfds, g_strdup (fontname));
+
+ /* Convert the XLFD into a PangoFontDescription */
+
+ family_name = pango_x_get_xlfd_field (fontname, XLFD_FAMILY, family_buffer);
+ if (!family_name)
+ return;
+
+ style = PANGO_STYLE_NORMAL;
+ if (pango_x_get_xlfd_field (fontname, XLFD_SLANT, slant_buffer))
+ {
+ for (i=0; i<G_N_ELEMENTS(styles_map); i++)
+ {
+ if (!strcmp (styles_map[i].text, slant_buffer))
+ {
+ style = styles_map[i].value;
+ break;
+ }
+ }
+ }
+ else
+ strcpy (slant_buffer, "*");
+
+ variant = PANGO_VARIANT_NORMAL;
+
+ weight = PANGO_WEIGHT_NORMAL;
+ if (pango_x_get_xlfd_field (fontname, XLFD_WEIGHT, weight_buffer))
+ {
+ for (i=0; i<G_N_ELEMENTS(weights_map); i++)
+ {
+ if (!strcmp (weights_map[i].text, weight_buffer))
+ {
+ weight = weights_map[i].value;
+ break;
+ }
+ }
+ }
+ else
+ strcpy (weight_buffer, "*");
+
+ stretch = PANGO_STRETCH_NORMAL;
+ if (pango_x_get_xlfd_field (fontname, XLFD_SET_WIDTH, set_width_buffer))
+ {
+ for (i=0; i<G_N_ELEMENTS(stretches_map); i++)
+ {
+ if (!strcmp (stretches_map[i].text, set_width_buffer))
+ {
+ stretch = stretches_map[i].value;
+ break;
+ }
+ }
+ }
+ else
+ strcpy (set_width_buffer, "*");
+
+ font_family = pango_x_get_font_family (xfontmap, family_name);
+
+ tmp_list = font_family->font_entries;
+ while (tmp_list)
+ {
+ xface = tmp_list->data;
+
+ if (pango_font_description_get_style (xface->description) == style &&
+ pango_font_description_get_weight (xface->description) == weight &&
+ pango_font_description_get_stretch (xface->description) == stretch &&
+ pango_font_description_get_variant (xface->description) == variant)
+ return;
+
+ tmp_list = tmp_list->next;
+ }
+
+ description = pango_font_description_new ();
+ pango_font_description_set_family_static (description, font_family->family_name);
+ pango_font_description_set_style (description, style);
+ pango_font_description_set_weight (description, weight);
+ pango_font_description_set_stretch (description, stretch);
+ pango_font_description_set_variant (description, variant);
+
+ xface = g_object_new (PANGO_X_TYPE_FACE, NULL);
+ xface->description = description;
+ xface->cached_fonts = NULL;
+ xface->coverage = NULL;
+
+ xface->xlfd = g_strconcat ("-*-",
+ family_buffer,
+ "-",
+ weight_buffer,
+ "-",
+ slant_buffer,
+ "-",
+ set_width_buffer,
+ "--*-*-*-*-*-*-*-*",
+ NULL);
+
+ font_family->font_entries = g_slist_append (font_family->font_entries, xface);
+ xfontmap->n_fonts++;
+}
+
+/* Compare the tail of a to b */
+static gboolean
+match_end (const char *a, const char *b)
+{
+ size_t len_a = strlen (a);
+ size_t len_b = strlen (b);
+
+ if (len_b > len_a)
+ return FALSE;
+ else
+ return (strcmp (a + len_a - len_b, b) == 0);
+}
+
+/* Given a XLFD, charset and size, find the best matching installed X font.
+ * The XLFD must be a full XLFD (14 fields)
+ */
+char *
+pango_x_make_matching_xlfd (PangoFontMap *fontmap, char *xlfd, const char *charset, int size)
+{
+ PangoXFontMap *xfontmap;
+
+ GSList *tmp_list;
+ PangoXSizeInfo *size_info;
+ char *identifier;
+ char *closest_match = NULL;
+ gint match_distance = 0;
+ gboolean match_scaleable = FALSE;
+ char *result = NULL;
+
+ char *dash_charset;
+
+ xfontmap = PANGO_X_FONT_MAP (fontmap);
+
+ dash_charset = g_strconcat ("-", charset, NULL);
+
+ if (!match_end (xlfd, "-*-*") && !match_end (xlfd, dash_charset))
+ {
+ g_free (dash_charset);
+ return NULL;
+ }
+
+ identifier = pango_x_get_identifier (xlfd);
+ size_info = g_hash_table_lookup (xfontmap->size_infos, identifier);
+ g_free (identifier);
+
+ if (!size_info)
+ {
+ g_free (dash_charset);
+ return NULL;
+ }
+
+ tmp_list = size_info->xlfds;
+ while (tmp_list)
+ {
+ char *tmp_xlfd = tmp_list->data;
+
+ if (match_end (tmp_xlfd, dash_charset))
+ {
+ int font_size = pango_x_get_size (xfontmap, tmp_xlfd);
+
+ if (size != -1)
+ {
+ int new_distance = (font_size == 0) ? 0 : abs (font_size - size);
+
+ if (!closest_match ||
+ new_distance < match_distance ||
+ (new_distance < PANGO_SCALE && match_scaleable && font_size != 0))
+ {
+ closest_match = tmp_xlfd;
+ match_scaleable = (font_size == 0);
+ match_distance = new_distance;
+ }
+ }
+ }
+
+ tmp_list = tmp_list->next;
+ }
+
+ if (closest_match)
+ {
+ if (match_scaleable)
+ {
+ char *prefix_end, *p;
+ int n_dashes = 0;
+ int target_size;
+ char *prefix;
+
+ /* OK, we have a match; let's modify it to fit this size and charset */
+
+ p = closest_match;
+ while (n_dashes < 6)
+ {
+ if (*p == '-')
+ n_dashes++;
+ p++;
+ }
+
+ prefix_end = p - 1;
+
+ while (n_dashes < 9)
+ {
+ if (*p == '-')
+ n_dashes++;
+ p++;
+ }
+
+ target_size = (int)((double)size / xfontmap->resolution + 0.5);
+ prefix = g_strndup (closest_match, prefix_end - closest_match);
+ result = g_strdup_printf ("%s--%d-*-*-*-*-*-%s", prefix, target_size, charset);
+ g_free (prefix);
+ }
+ else
+ {
+ result = g_strdup (closest_match);
+ }
+ }
+
+ g_free (dash_charset);
+
+ return result;
+}
+
+/**
+ * pango_x_font_map_get_font_cache:
+ * @font_map: a #PangoXFontMap.
+ *
+ * Obtains the font cache associated with the given font map.
+ *
+ * Return value: the #PangoXFontCache of @font_map.
+ **/
+PangoXFontCache *
+pango_x_font_map_get_font_cache (PangoFontMap *font_map)
+{
+ g_return_val_if_fail (font_map != NULL, NULL);
+ g_return_val_if_fail (PANGO_X_IS_FONT_MAP (font_map), NULL);
+
+ return PANGO_X_FONT_MAP (font_map)->font_cache;
+}
+
+Display *
+pango_x_fontmap_get_display (PangoFontMap *fontmap)
+{
+ g_return_val_if_fail (fontmap != NULL, NULL);
+ g_return_val_if_fail (PANGO_X_IS_FONT_MAP (fontmap), NULL);
+
+ return PANGO_X_FONT_MAP (fontmap)->display;
+}
+
+void
+pango_x_fontmap_cache_add (PangoFontMap *fontmap,
+ PangoXFont *xfont)
+{
+ PangoXFontMap *xfontmap = PANGO_X_FONT_MAP (fontmap);
+
+ if (xfontmap->freed_fonts->length == MAX_FREED_FONTS)
+ {
+ PangoXFont *old_font = g_queue_pop_tail (xfontmap->freed_fonts);
+ g_object_unref (old_font);
+ }
+
+ g_object_ref (xfont);
+ g_queue_push_head (xfontmap->freed_fonts, xfont);
+ xfont->in_cache = TRUE;
+}
+
+void
+pango_x_fontmap_cache_remove (PangoFontMap *fontmap,
+ PangoXFont *xfont)
+{
+ PangoXFontMap *xfontmap = PANGO_X_FONT_MAP (fontmap);
+
+ GList *link = g_list_find (xfontmap->freed_fonts->head, xfont);
+ if (link == xfontmap->freed_fonts->tail)
+ {
+ xfontmap->freed_fonts->tail = xfontmap->freed_fonts->tail->prev;
+ if (xfontmap->freed_fonts->tail)
+ xfontmap->freed_fonts->tail->next = NULL;
+ }
+
+ xfontmap->freed_fonts->head = g_list_delete_link (xfontmap->freed_fonts->head, link);
+ xfontmap->freed_fonts->length--;
+ xfont->in_cache = FALSE;
+
+ g_object_unref (xfont);
+}
+
+static void
+pango_x_fontmap_cache_clear (PangoXFontMap *xfontmap)
+{
+ g_list_foreach (xfontmap->freed_fonts->head, (GFunc)g_object_unref, NULL);
+ g_list_free (xfontmap->freed_fonts->head);
+ xfontmap->freed_fonts->head = NULL;
+ xfontmap->freed_fonts->tail = NULL;
+ xfontmap->freed_fonts->length = 0;
+}
+
+
+Atom
+pango_x_fontmap_atom_from_name (PangoFontMap *fontmap,
+ const char *atomname)
+{
+ PangoXFontMap *xfm = PANGO_X_FONT_MAP(fontmap);
+ gpointer found;
+ Atom atom;
+
+ found = g_hash_table_lookup (xfm->to_atom_cache, atomname);
+
+ if (found)
+ return (Atom)(GPOINTER_TO_UINT(found));
+
+ atom = XInternAtom (xfm->display, atomname, FALSE);
+ g_hash_table_insert (xfm->to_atom_cache, g_strdup (atomname),
+ (gpointer)atom);
+
+ return atom;
+}
+
+
+G_CONST_RETURN char *
+pango_x_fontmap_name_from_atom (PangoFontMap *fontmap,
+ Atom atom)
+{
+ PangoXFontMap *xfm = PANGO_X_FONT_MAP(fontmap);
+ gpointer found;
+ char *name, *name2;
+
+ found = g_hash_table_lookup (xfm->from_atom_cache, GUINT_TO_POINTER(atom));
+
+ if (found)
+ return (const char *)found;
+
+ name = XGetAtomName (xfm->display, atom);
+ name2 = g_strdup (name);
+ XFree (name);
+
+ g_hash_table_insert (xfm->from_atom_cache, (gpointer)atom, name2);
+
+ return name2;
+}
+
+/*
+ * PangoXFace
+ */
+
+static PangoFontDescription *
+pango_x_face_describe (PangoFontFace *face)
+{
+ PangoXFace *xface = PANGO_X_FACE (face);
+
+ return pango_font_description_copy (xface->description);
+}
+
+static const char *
+pango_x_face_get_face_name (PangoFontFace *face)
+{
+ PangoXFace *xface = PANGO_X_FACE (face);
+
+ if (!xface->face_name)
+ {
+ PangoFontDescription *desc = pango_font_face_describe (face);
+
+ pango_font_description_unset_fields (desc,
+ PANGO_FONT_MASK_FAMILY | PANGO_FONT_MASK_SIZE);
+
+ xface->face_name = pango_font_description_to_string (desc);
+ pango_font_description_free (desc);
+ }
+
+ return xface->face_name;
+}
+
+static void
+pango_x_face_class_init (PangoFontFaceClass *class)
+{
+ class->describe = pango_x_face_describe;
+ class->get_face_name = pango_x_face_get_face_name;
+}
+
+GType
+pango_x_face_get_type (void)
+{
+ static GType object_type = 0;
+
+ if (G_UNLIKELY (!object_type))
+ {
+ const GTypeInfo object_info =
+ {
+ sizeof (PangoFontFaceClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) pango_x_face_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (PangoXFace),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) NULL,
+ NULL /* value_table */
+ };
+
+ object_type = g_type_register_static (PANGO_TYPE_FONT_FACE,
+ I_("PangoXFace"),
+ &object_info, 0);
+ }
+
+ return object_type;
+}
+
+/* Cut and paste here to avoid an inter-module dependency */
+static PangoCoverageLevel
+engine_shape_covers (PangoEngineShape *engine,
+ PangoFont *font,
+ PangoLanguage *language,
+ gunichar wc)
+{
+ g_return_val_if_fail (PANGO_IS_ENGINE_SHAPE (engine), PANGO_COVERAGE_NONE);
+ g_return_val_if_fail (PANGO_IS_FONT (font), PANGO_COVERAGE_NONE);
+
+ return PANGO_ENGINE_SHAPE_GET_CLASS (engine)->covers (engine,
+ font,
+ language,
+ wc);
+}
+
+PangoCoverage *
+pango_x_face_get_coverage (PangoXFace *xface,
+ PangoFont *font,
+ PangoLanguage *language)
+{
+ PangoXFont *xfont;
+ PangoXFontMap *xfontmap = NULL; /* Quiet gcc */
+ PangoCoverage *result = NULL;
+ Atom atom = None;
+
+ if (xface)
+ {
+ if (xface->coverage)
+ {
+ pango_coverage_ref (xface->coverage);
+ return xface->coverage;
+ }
+
+ xfont = (PangoXFont *)font;
+
+ xfontmap = (PangoXFontMap *)pango_x_font_map_for_display (xfont->display);
+ if (xface->xlfd)
+ {
+ const char *lang_str = language ? pango_language_to_string (language) : "*";
+
+ char *str = g_strconcat (lang_str, "|", xface->xlfd, NULL);
+ result = pango_x_get_cached_coverage (xfontmap, str, &atom);
+ g_free (str);
+ }
+ }
+
+ if (!result)
+ {
+ PangoMap *shape_map;
+ PangoEngineShape *engine;
+ gunichar wc;
+
+ result = pango_coverage_new ();
+
+ shape_map = pango_x_get_shaper_map (language);
+ engine = (PangoEngineShape *)pango_map_get_engine (shape_map, PANGO_SCRIPT_COMMON);
+
+ for (wc = 0; wc < 65536; wc++)
+ {
+ PangoCoverageLevel level;
+
+ level = engine_shape_covers (engine, font, language, wc);
+ if (level != PANGO_COVERAGE_NONE)
+ pango_coverage_set (result, wc, level);
+ }
+
+ if (atom)
+ pango_x_store_cached_coverage (xfontmap, atom, result);
+ }
+
+ if (xface)
+ {
+ xface->coverage = result;
+ pango_coverage_ref (result);
+ }
+
+ return result;
+}
+
+void
+pango_x_face_remove (PangoXFace *xface,
+ PangoFont *font)
+{
+ xface->cached_fonts = g_slist_remove (xface->cached_fonts, font);
+}
+
+/*
+ * PangoXFontFamily
+ */
+
+static void
+pango_x_family_list_faces (PangoFontFamily *family,
+ PangoFontFace ***faces,
+ int *n_faces)
+{
+ PangoXFamily *xfamily = PANGO_X_FAMILY (family);
+
+ *n_faces = g_slist_length (xfamily->font_entries);
+ if (faces)
+ {
+ GSList *tmp_list;
+ int i = 0;
+
+ *faces = g_new (PangoFontFace *, *n_faces);
+
+ tmp_list = xfamily->font_entries;
+ while (tmp_list)
+ {
+ (*faces)[i++] = tmp_list->data;
+ tmp_list = tmp_list->next;
+ }
+ }
+}
+
+G_CONST_RETURN char *
+pango_x_family_get_name (PangoFontFamily *family)
+{
+ PangoXFamily *xfamily = PANGO_X_FAMILY (family);
+
+ return xfamily->family_name;
+}
+
+static void
+pango_x_family_class_init (PangoFontFamilyClass *class)
+{
+ class->list_faces = pango_x_family_list_faces;
+ class->get_name = pango_x_family_get_name;
+}
+
+GType
+pango_x_family_get_type (void)
+{
+ static GType object_type = 0;
+
+ if (G_UNLIKELY (!object_type))
+ {
+ const GTypeInfo object_info =
+ {
+ sizeof (PangoFontFamilyClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) pango_x_family_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (PangoXFamily),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) NULL,
+ NULL /* value_table */
+ };
+
+ object_type = g_type_register_static (PANGO_TYPE_FONT_FAMILY,
+ I_("PangoXFamily"),
+ &object_info, 0);
+ }
+
+ return object_type;
+}
+