/* Pango
* pangoxft-fontmap.c: Xft font handling
*
* Copyright (C) 2000-2003 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 <stdlib.h>
#include <string.h>
#include "pangofc-fontmap.h"
#include "pangoxft.h"
#include "pangoxft-private.h"
/* For XExtSetCloseDisplay */
#include <X11/Xlibint.h>
typedef struct _PangoXftFamily PangoXftFamily;
typedef struct _PangoXftFontMapClass PangoXftFontMapClass;
#define PANGO_TYPE_XFT_FONT_MAP (pango_xft_font_map_get_type ())
#define PANGO_XFT_FONT_MAP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_XFT_FONT_MAP, PangoXftFontMap))
#define PANGO_XFT_IS_FONT_MAP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_XFT_FONT_MAP))
struct _PangoXftFontMap
{
PangoFcFontMap parent_instance;
guint serial;
Display *display;
int screen;
/* Function to call on prepared patterns to do final
* config tweaking.
*/
PangoXftSubstituteFunc substitute_func;
gpointer substitute_data;
GDestroyNotify substitute_destroy;
PangoRenderer *renderer;
};
struct _PangoXftFontMapClass
{
PangoFcFontMapClass parent_class;
};
static guint pango_xft_font_map_get_serial (PangoFontMap *fontmap);
static void pango_xft_font_map_changed (PangoFontMap *fontmap);
static void pango_xft_font_map_default_substitute (PangoFcFontMap *fcfontmap,
FcPattern *pattern);
static PangoFcFont * pango_xft_font_map_new_font (PangoFcFontMap *fcfontmap,
FcPattern *pattern);
static void pango_xft_font_map_finalize (GObject *object);
G_LOCK_DEFINE_STATIC (fontmaps);
static GSList *fontmaps = NULL; /* MT-safe */
G_DEFINE_TYPE (PangoXftFontMap, pango_xft_font_map, PANGO_TYPE_FC_FONT_MAP)
static void
pango_xft_font_map_class_init (PangoXftFontMapClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
PangoFontMapClass *fontmap_class = PANGO_FONT_MAP_CLASS (class);
PangoFcFontMapClass *fcfontmap_class = PANGO_FC_FONT_MAP_CLASS (class);
gobject_class->finalize = pango_xft_font_map_finalize;
fontmap_class->get_serial = pango_xft_font_map_get_serial;
fontmap_class->changed = pango_xft_font_map_changed;
fcfontmap_class->default_substitute = pango_xft_font_map_default_substitute;
fcfontmap_class->new_font = pango_xft_font_map_new_font;
}
static void
pango_xft_font_map_init (PangoXftFontMap *xftfontmap)
{
xftfontmap->serial = 1;
}
static void
pango_xft_font_map_finalize (GObject *object)
{
PangoXftFontMap *xftfontmap = PANGO_XFT_FONT_MAP (object);
if (xftfontmap->renderer)
g_object_unref (xftfontmap->renderer);
G_LOCK (fontmaps);
fontmaps = g_slist_remove (fontmaps, object);
G_UNLOCK (fontmaps);
if (xftfontmap->substitute_destroy)
xftfontmap->substitute_destroy (xftfontmap->substitute_data);
G_OBJECT_CLASS (pango_xft_font_map_parent_class)->finalize (object);
}
static guint
pango_xft_font_map_get_serial (PangoFontMap *fontmap)
{
PangoXftFontMap *xftfontmap = PANGO_XFT_FONT_MAP (fontmap);
return xftfontmap->serial;
}
static void
pango_xft_font_map_changed (PangoFontMap *fontmap)
{
PangoXftFontMap *xftfontmap = PANGO_XFT_FONT_MAP (fontmap);
xftfontmap->serial++;
if (xftfontmap->serial == 0)
xftfontmap->serial++;
}
static PangoFontMap *
pango_xft_find_font_map (Display *display,
int screen)
{
GSList *tmp_list;
G_LOCK (fontmaps);
tmp_list = fontmaps;
while (tmp_list)
{
PangoXftFontMap *xftfontmap = tmp_list->data;
if (xftfontmap->display == display &&
xftfontmap->screen == screen)
{
G_UNLOCK (fontmaps);
return PANGO_FONT_MAP (xftfontmap);
}
tmp_list = tmp_list->next;
}
G_UNLOCK (fontmaps);
return NULL;
}
/*
* Hackery to set up notification when a Display is closed
*/
static GSList *registered_displays; /* MT-safe, protected by fontmaps lock */
static int
close_display_cb (Display *display,
XExtCodes *extcodes G_GNUC_UNUSED)
{
GSList *tmp_list;
G_LOCK (fontmaps);
tmp_list = g_slist_copy (fontmaps);
G_UNLOCK (fontmaps);
while (tmp_list)
{
PangoXftFontMap *xftfontmap = tmp_list->data;
tmp_list = tmp_list->next;
if (xftfontmap->display == display)
pango_xft_shutdown_display (display, xftfontmap->screen);
}
g_slist_free (tmp_list);
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);
}
/**
* pango_xft_get_font_map:
* @display: an X display
* @screen: the screen number of a screen within @display
*
* Returns the #PangoXftFontMap for the given display and screen.
* The fontmap is owned by Pango and will be valid until
* the display is closed.
*
* Return value: (transfer none): a #PangoFontMap object, owned by Pango.
*
* Since: 1.2
**/
PangoFontMap *
pango_xft_get_font_map (Display *display,
int screen)
{
PangoFontMap *fontmap;
PangoXftFontMap *xftfontmap;
g_return_val_if_fail (display != NULL, NULL);
fontmap = pango_xft_find_font_map (display, screen);
if (fontmap)
return fontmap;
#if !GLIB_CHECK_VERSION (2, 35, 3)
/* Make sure that the type system is initialized */
g_type_init ();
#endif
xftfontmap = (PangoXftFontMap *)g_object_new (PANGO_TYPE_XFT_FONT_MAP, NULL);
xftfontmap->display = display;
xftfontmap->screen = screen;
G_LOCK (fontmaps);
register_display (display);
fontmaps = g_slist_prepend (fontmaps, xftfontmap);
G_UNLOCK (fontmaps);
return PANGO_FONT_MAP (xftfontmap);
}
/**
* pango_xft_shutdown_display:
* @display: an X display
* @screen: the screen number of a screen within @display
*
* Release any resources that have been cached for the
* combination of @display and @screen. Note that when the
* X display is closed, resources are released automatically,
* without needing to call this function.
*
* Since: 1.2
**/
void
pango_xft_shutdown_display (Display *display,
int screen)
{
PangoFontMap *fontmap;
fontmap = pango_xft_find_font_map (display, screen);
if (fontmap)
{
PangoXftFontMap *xftfontmap = PANGO_XFT_FONT_MAP (fontmap);
G_LOCK (fontmaps);
fontmaps = g_slist_remove (fontmaps, fontmap);
G_UNLOCK (fontmaps);
pango_fc_font_map_shutdown (PANGO_FC_FONT_MAP (fontmap));
xftfontmap->display = NULL;
g_object_unref (fontmap);
}
}
/**
* pango_xft_set_default_substitute:
* @display: an X Display
* @screen: the screen number of a screen within @display
* @func: function to call to to do final config tweaking
* on #FcPattern objects.
* @data: data to pass to @func
* @notify: function to call when @data is no longer used.
*
* Sets a function that will be called to do final configuration
* substitution on a #FcPattern before it is used to load
* the font. This function can be used to do things like set
* hinting and antialiasing options.
*
* Since: 1.2
**/
void
pango_xft_set_default_substitute (Display *display,
int screen,
PangoXftSubstituteFunc func,
gpointer data,
GDestroyNotify notify)
{
PangoXftFontMap *xftfontmap = (PangoXftFontMap *)pango_xft_get_font_map (display, screen);
xftfontmap->serial++;
if (xftfontmap->serial == 0)
xftfontmap->serial++;
if (xftfontmap->substitute_destroy)
xftfontmap->substitute_destroy (xftfontmap->substitute_data);
xftfontmap->substitute_func = func;
xftfontmap->substitute_data = data;
xftfontmap->substitute_destroy = notify;
pango_fc_font_map_cache_clear (PANGO_FC_FONT_MAP (xftfontmap));
}
/**
* pango_xft_substitute_changed:
* @display: an X Display
* @screen: the screen number of a screen within @display
*
* Call this function any time the results of the
* default substitution function set with
* pango_xft_set_default_substitute() change.
* That is, if your substitution function will return different
* results for the same input pattern, you must call this function.
*
* Since: 1.2
**/
void
pango_xft_substitute_changed (Display *display,
int screen)
{
PangoXftFontMap *xftfontmap = (PangoXftFontMap *)pango_xft_get_font_map (display, screen);
xftfontmap->serial++;
if (xftfontmap->serial == 0)
xftfontmap->serial++;
pango_fc_font_map_cache_clear (PANGO_FC_FONT_MAP (xftfontmap));
}
void
_pango_xft_font_map_get_info (PangoFontMap *fontmap,
Display **display,
int *screen)
{
PangoXftFontMap *xftfontmap = (PangoXftFontMap *)fontmap;
if (display)
*display = xftfontmap->display;
if (screen)
*screen = xftfontmap->screen;
}
/**
* pango_xft_get_context: (skip)
* @display: an X display.
* @screen: an X screen.
*
* Retrieves a #PangoContext appropriate for rendering with
* Xft fonts on the given screen of the given display.
*
* Return value: the new #PangoContext.
*
* Deprecated: 1.22: Use pango_xft_get_font_map() followed by
* pango_font_map_create_context() instead.
**/
PangoContext *
pango_xft_get_context (Display *display,
int screen)
{
g_return_val_if_fail (display != NULL, NULL);
return pango_font_map_create_context (pango_xft_get_font_map (display, screen));
}
/**
* _pango_xft_font_map_get_renderer:
* @fontmap: a #PangoXftFontMap
*
* Gets the singleton #PangoXFTRenderer for this fontmap.
*
* Return value: the renderer.
**/
PangoRenderer *
_pango_xft_font_map_get_renderer (PangoXftFontMap *xftfontmap)
{
if (!xftfontmap->renderer)
xftfontmap->renderer = pango_xft_renderer_new (xftfontmap->display,
xftfontmap->screen);
return xftfontmap->renderer;
}
static void
pango_xft_font_map_default_substitute (PangoFcFontMap *fcfontmap,
FcPattern *pattern)
{
PangoXftFontMap *xftfontmap = PANGO_XFT_FONT_MAP (fcfontmap);
double d;
FcConfigSubstitute (NULL, pattern, FcMatchPattern);
if (xftfontmap->substitute_func)
xftfontmap->substitute_func (pattern, xftfontmap->substitute_data);
XftDefaultSubstitute (xftfontmap->display, xftfontmap->screen, pattern);
if (FcPatternGetDouble (pattern, FC_PIXEL_SIZE, 0, &d) == FcResultMatch && d == 0.0)
{
FcValue v;
v.type = FcTypeDouble;
v.u.d = 1.0;
FcPatternAdd (pattern, FC_PIXEL_SIZE, v, FcFalse);
}
}
static PangoFcFont *
pango_xft_font_map_new_font (PangoFcFontMap *fcfontmap,
FcPattern *pattern)
{
return (PangoFcFont *)_pango_xft_font_new (PANGO_XFT_FONT_MAP (fcfontmap), pattern);
}