GtkFontChooser: Allow a custom font map

This lets applications show their own fonts instead of
or in addition to system fonts.

https://bugzilla.gnome.org/show_bug.cgi?id=748771
This commit is contained in:
Matthias Clasen 2015-05-04 23:21:17 -04:00
parent 0c922a9443
commit 049cbc8b74
8 changed files with 187 additions and 26 deletions

View File

@ -1634,6 +1634,8 @@ gtk_font_chooser_get_show_preview_entry
gtk_font_chooser_set_show_preview_entry gtk_font_chooser_set_show_preview_entry
GtkFontFilterFunc GtkFontFilterFunc
gtk_font_chooser_set_filter_func gtk_font_chooser_set_filter_func
gtk_font_chooser_set_font_map
gtk_font_chooser_get_font_map
<SUBSECTION Standard> <SUBSECTION Standard>
GtkFontChooserIface GtkFontChooserIface

View File

@ -58,18 +58,18 @@
*/ */
struct _GtkFontButtonPrivate struct _GtkFontButtonPrivate
{ {
gchar *title; gchar *title;
gchar *fontname; gchar *fontname;
guint use_font : 1; guint use_font : 1;
guint use_size : 1; guint use_size : 1;
guint show_style : 1; guint show_style : 1;
guint show_size : 1; guint show_size : 1;
guint show_preview_entry : 1; guint show_preview_entry : 1;
GtkWidget *font_dialog; GtkWidget *font_dialog;
GtkWidget *font_label; GtkWidget *font_label;
GtkWidget *size_label; GtkWidget *size_label;
@ -78,6 +78,7 @@ struct _GtkFontButtonPrivate
PangoFontDescription *font_desc; PangoFontDescription *font_desc;
PangoFontFamily *font_family; PangoFontFamily *font_family;
PangoFontFace *font_face; PangoFontFace *font_face;
PangoFontMap *font_map;
gint font_size; gint font_size;
gchar *preview_text; gchar *preview_text;
GtkFontFilterFunc font_filter; GtkFontFilterFunc font_filter;
@ -87,7 +88,7 @@ struct _GtkFontButtonPrivate
}; };
/* Signals */ /* Signals */
enum enum
{ {
FONT_SET, FONT_SET,
LAST_SIGNAL LAST_SIGNAL
@ -361,7 +362,7 @@ gtk_font_button_take_font_desc (GtkFontButton *font_button,
if (pango_font_description_get_size_is_absolute (priv->font_desc)) if (pango_font_description_get_size_is_absolute (priv->font_desc))
priv->font_size = pango_font_description_get_size (priv->font_desc); priv->font_size = pango_font_description_get_size (priv->font_desc);
else else
priv->font_size = pango_font_description_get_size (priv->font_desc) / PANGO_SCALE; priv->font_size = pango_font_description_get_size (priv->font_desc) / PANGO_SCALE;
gtk_font_button_update_font_data (font_button); gtk_font_button_update_font_data (font_button);
@ -384,6 +385,24 @@ gtk_font_button_get_font_desc (GtkFontButton *font_button)
return font_button->priv->font_desc; return font_button->priv->font_desc;
} }
static void
gtk_font_button_set_font_map (GtkFontButton *font_button,
PangoFontMap *font_map)
{
if (g_set_object (&font_button->priv->font_map, font_map))
{
PangoContext *context;
if (!font_map)
font_map = pango_cairo_font_map_get_default ();
context = gtk_widget_get_pango_context (font_button->priv->font_label);
pango_context_set_font_map (context, font_map);
g_object_notify (G_OBJECT (font_button), "font-map");
}
}
static void static void
gtk_font_button_font_chooser_notify (GObject *object, gtk_font_button_font_chooser_notify (GObject *object,
GParamSpec *pspec, GParamSpec *pspec,
@ -636,6 +655,9 @@ gtk_font_button_set_property (GObject *object,
case PROP_SHOW_SIZE: case PROP_SHOW_SIZE:
gtk_font_button_set_show_size (font_button, g_value_get_boolean (value)); gtk_font_button_set_show_size (font_button, g_value_get_boolean (value));
break; break;
case GTK_FONT_CHOOSER_PROP_FONT_MAP:
gtk_font_button_set_font_map (font_button, g_value_get_object (value));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break; break;
@ -680,11 +702,14 @@ gtk_font_button_get_property (GObject *object,
case PROP_SHOW_SIZE: case PROP_SHOW_SIZE:
g_value_set_boolean (value, gtk_font_button_get_show_size (font_button)); g_value_set_boolean (value, gtk_font_button_get_show_size (font_button));
break; break;
case GTK_FONT_CHOOSER_PROP_FONT_MAP:
g_value_set_object (value, font_button->priv->font_map);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break; break;
} }
} }
/** /**
@ -700,7 +725,7 @@ GtkWidget *
gtk_font_button_new (void) gtk_font_button_new (void)
{ {
return g_object_new (GTK_TYPE_FONT_BUTTON, NULL); return g_object_new (GTK_TYPE_FONT_BUTTON, NULL);
} }
/** /**
* gtk_font_button_new_with_font: * gtk_font_button_new_with_font:
@ -1014,6 +1039,8 @@ gtk_font_button_clicked (GtkButton *button)
priv->font_dialog = gtk_font_chooser_dialog_new (priv->title, NULL); priv->font_dialog = gtk_font_chooser_dialog_new (priv->title, NULL);
font_dialog = GTK_FONT_CHOOSER (font_button->priv->font_dialog); font_dialog = GTK_FONT_CHOOSER (font_button->priv->font_dialog);
if (priv->font_map)
gtk_font_chooser_set_font_map (font_dialog, priv->font_map);
gtk_font_chooser_set_show_preview_entry (font_dialog, priv->show_preview_entry); gtk_font_chooser_set_show_preview_entry (font_dialog, priv->show_preview_entry);
if (priv->preview_text) if (priv->preview_text)

View File

@ -106,6 +106,18 @@ gtk_font_chooser_default_init (GtkFontChooserInterface *iface)
TRUE, TRUE,
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY)); GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
/**
* GtkFontChooser:font-map:
*
* A custom font map to use for this widget, instead of the
* default one.
*
* Since: 3.18
*/
g_object_interface_install_property (iface,
g_param_spec_object ("font-map", P_("Font map"), P_("A custom PangoFontMap"),
PANGO_TYPE_FONT_MAP,
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
/** /**
* GtkFontChooser::font-activated: * GtkFontChooser::font-activated:
* @self: the object which received the signal * @self: the object which received the signal
@ -415,3 +427,47 @@ _gtk_font_chooser_font_activated (GtkFontChooser *chooser,
g_signal_emit (chooser, chooser_signals[SIGNAL_FONT_ACTIVATED], 0, fontname); g_signal_emit (chooser, chooser_signals[SIGNAL_FONT_ACTIVATED], 0, fontname);
} }
/**
* gtk_font_chooser_set_font_map:
* @fontchooser: a #GtkFontChooser
* @fontmap: (allow-none): a #PangoFontMap
*
* Sets a custom font map to use for this font chooser widget.
* A custom font map can be used to present application-specific
* fonts instead of or in addition to the normal system fonts.
*
* Since: 3.18
*/
void
gtk_font_chooser_set_font_map (GtkFontChooser *fontchooser,
PangoFontMap *fontmap)
{
g_return_if_fail (GTK_IS_FONT_CHOOSER (fontchooser));
g_return_if_fail (fontmap == NULL || PANGO_IS_FONT_MAP (fontmap));
g_object_set (fontchooser, "font-map", fontmap, NULL);
}
/**
* gtk_font_chooser_get_font_map:
* @fontchooser: a #GtkFontChooser
*
* Gets the custom font map of this font chooser widget,
* or %NULL if it does not have one.
*
* Returns: (transfer full) (allow-none): a #PangoFontMap, or %NULL
*
* Since: 3.18
*/
PangoFontMap *
gtk_font_chooser_get_font_map (GtkFontChooser *fontchooser)
{
PangoFontMap *fontmap;
g_return_if_fail (GTK_IS_FONT_CHOOSER (fontchooser));
g_object_get (fontchooser, "font-map", &fontmap, NULL);
return fontmap;
}

View File

@ -112,6 +112,11 @@ void gtk_font_chooser_set_filter_func (GtkFontChooser *fo
GtkFontFilterFunc filter, GtkFontFilterFunc filter,
gpointer user_data, gpointer user_data,
GDestroyNotify destroy); GDestroyNotify destroy);
GDK_AVAILABLE_IN_3_18
void gtk_font_chooser_set_font_map (GtkFontChooser *fontchooser,
PangoFontMap *fontmap);
GDK_AVAILABLE_IN_3_18
PangoFontMap * gtk_font_chooser_get_font_map (GtkFontChooser *fontchooser);
G_END_DECLS G_END_DECLS

View File

@ -121,6 +121,9 @@ _gtk_font_chooser_install_properties (GObjectClass *klass)
g_object_class_override_property (klass, g_object_class_override_property (klass,
GTK_FONT_CHOOSER_PROP_SHOW_PREVIEW_ENTRY, GTK_FONT_CHOOSER_PROP_SHOW_PREVIEW_ENTRY,
"show-preview-entry"); "show-preview-entry");
g_object_class_override_property (klass,
GTK_FONT_CHOOSER_PROP_FONT_MAP,
"font-map");
} }
/** /**

View File

@ -37,6 +37,7 @@ typedef enum {
GTK_FONT_CHOOSER_PROP_FONT_DESC, GTK_FONT_CHOOSER_PROP_FONT_DESC,
GTK_FONT_CHOOSER_PROP_PREVIEW_TEXT, GTK_FONT_CHOOSER_PROP_PREVIEW_TEXT,
GTK_FONT_CHOOSER_PROP_SHOW_PREVIEW_ENTRY, GTK_FONT_CHOOSER_PROP_SHOW_PREVIEW_ENTRY,
GTK_FONT_CHOOSER_PROP_FONT_MAP,
GTK_FONT_CHOOSER_PROP_LAST GTK_FONT_CHOOSER_PROP_LAST
} GtkFontChooserProp; } GtkFontChooserProp;

View File

@ -90,6 +90,8 @@ struct _GtkFontChooserWidgetPrivate
GtkWidget *size_spin; GtkWidget *size_spin;
GtkWidget *size_slider; GtkWidget *size_slider;
PangoFontMap *font_map;
PangoFontDescription *font_desc; PangoFontDescription *font_desc;
GtkTreeIter font_iter; /* invalid if font not available or pointer into model GtkTreeIter font_iter; /* invalid if font not available or pointer into model
(not filter_model) to the row containing font */ (not filter_model) to the row containing font */
@ -160,7 +162,8 @@ static void gtk_font_chooser_widget_set_show_preview_entry (GtkFontChooserWi
gboolean show_preview_entry); gboolean show_preview_entry);
static void gtk_font_chooser_widget_set_cell_size (GtkFontChooserWidget *fontchooser); static void gtk_font_chooser_widget_set_cell_size (GtkFontChooserWidget *fontchooser);
static void gtk_font_chooser_widget_load_fonts (GtkFontChooserWidget *fontchooser); static void gtk_font_chooser_widget_load_fonts (GtkFontChooserWidget *fontchooser,
gboolean force);
static gboolean visible_func (GtkTreeModel *model, static gboolean visible_func (GtkTreeModel *model,
GtkTreeIter *iter, GtkTreeIter *iter,
gpointer user_data); gpointer user_data);
@ -169,6 +172,8 @@ static void gtk_font_chooser_widget_cell_data_func (GtkTreeViewColum
GtkTreeModel *tree_model, GtkTreeModel *tree_model,
GtkTreeIter *iter, GtkTreeIter *iter,
gpointer user_data); gpointer user_data);
static void gtk_font_chooser_widget_set_font_map (GtkFontChooserWidget *fontchooser,
PangoFontMap *fontmap);
static void gtk_font_chooser_widget_iface_init (GtkFontChooserIface *iface); static void gtk_font_chooser_widget_iface_init (GtkFontChooserIface *iface);
@ -199,6 +204,9 @@ gtk_font_chooser_widget_set_property (GObject *object,
case GTK_FONT_CHOOSER_PROP_SHOW_PREVIEW_ENTRY: case GTK_FONT_CHOOSER_PROP_SHOW_PREVIEW_ENTRY:
gtk_font_chooser_widget_set_show_preview_entry (fontchooser, g_value_get_boolean (value)); gtk_font_chooser_widget_set_show_preview_entry (fontchooser, g_value_get_boolean (value));
break; break;
case GTK_FONT_CHOOSER_PROP_FONT_MAP:
gtk_font_chooser_widget_set_font_map (fontchooser, g_value_get_object (value));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -227,6 +235,9 @@ gtk_font_chooser_widget_get_property (GObject *object,
case GTK_FONT_CHOOSER_PROP_SHOW_PREVIEW_ENTRY: case GTK_FONT_CHOOSER_PROP_SHOW_PREVIEW_ENTRY:
g_value_set_boolean (value, gtk_font_chooser_widget_get_show_preview_entry (fontchooser)); g_value_set_boolean (value, gtk_font_chooser_widget_get_show_preview_entry (fontchooser));
break; break;
case GTK_FONT_CHOOSER_PROP_FONT_MAP:
g_value_set_object (value, fontchooser->priv->font_map);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -599,7 +610,7 @@ gtk_font_chooser_widget_init (GtkFontChooserWidget *fontchooser)
NULL); NULL);
/* Load data and set initial style-dependent parameters */ /* Load data and set initial style-dependent parameters */
gtk_font_chooser_widget_load_fonts (fontchooser); gtk_font_chooser_widget_load_fonts (fontchooser, TRUE);
gtk_font_chooser_widget_set_cell_size (fontchooser); gtk_font_chooser_widget_set_cell_size (fontchooser);
gtk_font_chooser_widget_take_font_desc (fontchooser, NULL); gtk_font_chooser_widget_take_font_desc (fontchooser, NULL);
} }
@ -630,7 +641,8 @@ cmp_families (const void *a,
} }
static void static void
gtk_font_chooser_widget_load_fonts (GtkFontChooserWidget *fontchooser) gtk_font_chooser_widget_load_fonts (GtkFontChooserWidget *fontchooser,
gboolean force)
{ {
GtkFontChooserWidgetPrivate *priv = fontchooser->priv; GtkFontChooserWidgetPrivate *priv = fontchooser->priv;
GtkListStore *list_store; GtkListStore *list_store;
@ -638,6 +650,8 @@ gtk_font_chooser_widget_load_fonts (GtkFontChooserWidget *fontchooser)
PangoFontFamily **families; PangoFontFamily **families;
gchar *family_and_face; gchar *family_and_face;
guint fontconfig_timestamp; guint fontconfig_timestamp;
gboolean need_reload;
PangoFontMap *font_map;
g_object_get (gtk_widget_get_settings (GTK_WIDGET (fontchooser)), g_object_get (gtk_widget_get_settings (GTK_WIDGET (fontchooser)),
"gtk-fontconfig-timestamp", &fontconfig_timestamp, "gtk-fontconfig-timestamp", &fontconfig_timestamp,
@ -647,21 +661,25 @@ gtk_font_chooser_widget_load_fonts (GtkFontChooserWidget *fontchooser)
* other platform will set it to 0. For those systems, we fall back to * other platform will set it to 0. For those systems, we fall back to
* reloading the fonts every time. * reloading the fonts every time.
*/ */
if (fontconfig_timestamp != 0 && need_reload = fontconfig_timestamp == 0 ||
priv->last_fontconfig_timestamp == fontconfig_timestamp) fontconfig_timestamp != priv->last_fontconfig_timestamp;
return;
priv->last_fontconfig_timestamp = fontconfig_timestamp; priv->last_fontconfig_timestamp = fontconfig_timestamp;
if (!need_reload && !force)
return;
list_store = GTK_LIST_STORE (priv->model); list_store = GTK_LIST_STORE (priv->model);
pango_context_list_families (gtk_widget_get_pango_context (GTK_WIDGET (fontchooser)), if (priv->font_map)
&families, font_map = priv->font_map;
&n_families); else
font_map = pango_cairo_font_map_get_default ();
pango_font_map_list_families (font_map, &families, &n_families);
qsort (families, n_families, sizeof (PangoFontFamily *), cmp_families); qsort (families, n_families, sizeof (PangoFontFamily *), cmp_families);
g_signal_handlers_block_by_func(priv->family_face_list, cursor_changed_cb, fontchooser); g_signal_handlers_block_by_func (priv->family_face_list, cursor_changed_cb, fontchooser);
gtk_list_store_clear (list_store); gtk_list_store_clear (list_store);
g_signal_handlers_unblock_by_func (priv->family_face_list, cursor_changed_cb, fontchooser); g_signal_handlers_unblock_by_func (priv->family_face_list, cursor_changed_cb, fontchooser);
@ -698,9 +716,7 @@ gtk_font_chooser_widget_load_fonts (GtkFontChooserWidget *fontchooser)
g_free (families); g_free (families);
/* now make sure the font list looks right */ /* now make sure the font list looks right */
if (!gtk_font_chooser_widget_find_font (fontchooser, if (!gtk_font_chooser_widget_find_font (fontchooser, priv->font_desc, &priv->font_iter))
priv->font_desc,
&priv->font_iter))
memset (&priv->font_iter, 0, sizeof (GtkTreeIter)); memset (&priv->font_iter, 0, sizeof (GtkTreeIter));
gtk_font_chooser_widget_ensure_selection (fontchooser); gtk_font_chooser_widget_ensure_selection (fontchooser);
@ -899,6 +915,8 @@ gtk_font_chooser_widget_finalize (GObject *object)
g_free (priv->preview_text); g_free (priv->preview_text);
g_clear_object (&priv->font_map);
G_OBJECT_CLASS (gtk_font_chooser_widget_parent_class)->finalize (object); G_OBJECT_CLASS (gtk_font_chooser_widget_parent_class)->finalize (object);
} }
@ -950,6 +968,12 @@ gtk_font_chooser_widget_find_font (GtkFontChooserWidget *fontchooser,
return valid; return valid;
} }
static void
fontconfig_changed (GtkFontChooserWidget *fontchooser)
{
gtk_font_chooser_widget_load_fonts (fontchooser, TRUE);
}
static void static void
gtk_font_chooser_widget_screen_changed (GtkWidget *widget, gtk_font_chooser_widget_screen_changed (GtkWidget *widget,
GdkScreen *previous_screen) GdkScreen *previous_screen)
@ -963,11 +987,11 @@ gtk_font_chooser_widget_screen_changed (GtkWidget *widget,
if (previous_screen) if (previous_screen)
{ {
settings = gtk_settings_get_for_screen (previous_screen); settings = gtk_settings_get_for_screen (previous_screen);
g_signal_handlers_disconnect_by_func (settings, gtk_font_chooser_widget_load_fonts, widget); g_signal_handlers_disconnect_by_func (settings, fontconfig_changed, widget);
} }
settings = gtk_widget_get_settings (widget); settings = gtk_widget_get_settings (widget);
g_signal_connect_object (settings, "notify::gtk-fontconfig-timestamp", g_signal_connect_object (settings, "notify::gtk-fontconfig-timestamp",
G_CALLBACK (gtk_font_chooser_widget_load_fonts), widget, G_CONNECT_SWAPPED); G_CALLBACK (fontconfig_changed), widget, G_CONNECT_SWAPPED);
if (previous_screen == NULL) if (previous_screen == NULL)
previous_screen = gdk_screen_get_default (); previous_screen = gdk_screen_get_default ();
@ -975,7 +999,7 @@ gtk_font_chooser_widget_screen_changed (GtkWidget *widget,
if (previous_screen == gtk_widget_get_screen (widget)) if (previous_screen == gtk_widget_get_screen (widget))
return; return;
gtk_font_chooser_widget_load_fonts (fontchooser); gtk_font_chooser_widget_load_fonts (fontchooser, FALSE);
} }
static void static void
@ -985,7 +1009,7 @@ gtk_font_chooser_widget_style_updated (GtkWidget *widget)
GTK_WIDGET_CLASS (gtk_font_chooser_widget_parent_class)->style_updated (widget); GTK_WIDGET_CLASS (gtk_font_chooser_widget_parent_class)->style_updated (widget);
gtk_font_chooser_widget_load_fonts (fontchooser); gtk_font_chooser_widget_load_fonts (fontchooser, FALSE);
} }
static PangoFontFamily * static PangoFontFamily *
@ -1161,7 +1185,6 @@ gtk_font_chooser_widget_take_font_desc (GtkFontChooserWidget *fontchooser,
else else
{ {
gtk_font_chooser_widget_merge_font_desc (fontchooser, font_desc, &priv->font_iter); gtk_font_chooser_widget_merge_font_desc (fontchooser, font_desc, &priv->font_iter);
} }
} }
@ -1214,6 +1237,28 @@ gtk_font_chooser_widget_set_show_preview_entry (GtkFontChooserWidget *fontchoose
} }
} }
static void
gtk_font_chooser_widget_set_font_map (GtkFontChooserWidget *fontchooser,
PangoFontMap *fontmap)
{
GtkFontChooserWidgetPrivate *priv = fontchooser->priv;
if (g_set_object (&priv->font_map, fontmap))
{
PangoContext *context;
if (!fontmap)
fontmap = pango_cairo_font_map_get_default ();
context = gtk_widget_get_pango_context (priv->family_face_list);
pango_context_set_font_map (context, fontmap);
gtk_font_chooser_widget_load_fonts (fontchooser, TRUE);
g_object_notify (G_OBJECT (fontchooser), "font-map");
}
}
static void static void
gtk_font_chooser_widget_set_filter_func (GtkFontChooser *chooser, gtk_font_chooser_widget_set_filter_func (GtkFontChooser *chooser,
GtkFontFilterFunc filter, GtkFontFilterFunc filter,

View File

@ -16,6 +16,7 @@
*/ */
#include <string.h> #include <string.h>
#include <pango/pangofc-fontmap.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
static gboolean static gboolean
@ -71,8 +72,29 @@ main (int argc, char *argv[])
gtk_init (&argc, &argv); gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
font_button = gtk_font_button_new (); font_button = gtk_font_button_new ();
if (argc > 0)
{
FcConfig *config;
PangoFontMap *fontmap;
gint i;
/* Create a custom font configuration by adding font files specified
* on the commandline to the default config.
*/
config = FcInitLoadConfigAndFonts ();
for (i = 0; i < argc; i++)
FcConfigAppFontAddFile (config, (const FcChar8 *)argv[i]);
fontmap = pango_cairo_font_map_new_for_font_type (CAIRO_FONT_TYPE_FT);
pango_fc_font_map_set_config (PANGO_FC_FONT_MAP (fontmap), config);
gtk_font_chooser_set_font_map (GTK_FONT_CHOOSER (font_button), fontmap);
}
gtk_font_button_set_use_font (GTK_FONT_BUTTON (font_button), TRUE);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_container_add (GTK_CONTAINER (window), font_button); gtk_container_add (GTK_CONTAINER (window), font_button);
gtk_widget_show_all (window); gtk_widget_show_all (window);