1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * Massively updated for Pango by Owen Taylor, May 2000
5 * GtkFontSelection widget for Gtk+, by Damon Chaplin, May 1998.
6 * Based on the GnomeFontSelector widget, by Elliot Lee, but major changes.
7 * The GnomeFontSelector was derived from app/text_tool.c in the GIMP.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
26 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
27 * file for a list of people on the GTK+ Team. See the ChangeLog
28 * files for a list of changes. These files are distributed with
29 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
34 #include <glib/gprintf.h>
38 #include "gdk/gdkkeysyms.h"
40 #include "gtkfontsel.h"
42 #include "gtkbutton.h"
43 #include "gtkcellrenderertext.h"
49 #include "gtkliststore.h"
53 #include "gtktreeselection.h"
54 #include "gtktreeview.h"
56 #include "gtkscrolledwindow.h"
59 /* We don't enable the font and style entries because they don't add
60 * much in terms of visible effect and have a weird effect on keynav.
61 * the Windows font selector has entries similarly positioned but they
62 * act in conjunction with the associated lists to form a single focus
65 #undef INCLUDE_FONT_ENTRIES
67 /* This is the default text shown in the preview entry, though the user
68 can set it. Remember that some fonts only have capital letters. */
69 #define PREVIEW_TEXT N_("abcdefghijk ABCDEFGHIJK")
71 /* This is the initial and maximum height of the preview entry (it expands
72 when large font sizes are selected). Initial height is also the minimum. */
73 #define INITIAL_PREVIEW_HEIGHT 44
74 #define MAX_PREVIEW_HEIGHT 300
76 /* These are the sizes of the font, style & size lists. */
77 #define FONT_LIST_HEIGHT 136
78 #define FONT_LIST_WIDTH 190
79 #define FONT_STYLE_LIST_WIDTH 170
80 #define FONT_SIZE_LIST_WIDTH 60
82 /* These are what we use as the standard font sizes, for the size list.
84 static const guint16 font_sizes[] = {
85 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28,
86 32, 36, 40, 48, 56, 64, 72
111 static void gtk_font_selection_class_init (GtkFontSelectionClass *klass);
112 static void gtk_font_selection_set_property (GObject *object,
116 static void gtk_font_selection_get_property (GObject *object,
120 static void gtk_font_selection_init (GtkFontSelection *fontsel);
121 static void gtk_font_selection_finalize (GObject *object);
122 static void gtk_font_selection_screen_changed (GtkWidget *widget,
123 GdkScreen *previous_screen);
125 /* These are the callbacks & related functions. */
126 static void gtk_font_selection_select_font (GtkTreeSelection *selection,
128 static void gtk_font_selection_show_available_fonts (GtkFontSelection *fs);
130 static void gtk_font_selection_show_available_styles (GtkFontSelection *fs);
131 static void gtk_font_selection_select_best_style (GtkFontSelection *fs,
133 static void gtk_font_selection_select_style (GtkTreeSelection *selection,
136 static void gtk_font_selection_select_best_size (GtkFontSelection *fs);
137 static void gtk_font_selection_show_available_sizes (GtkFontSelection *fs,
138 gboolean first_time);
139 static void gtk_font_selection_size_activate (GtkWidget *w,
141 static gboolean gtk_font_selection_size_focus_out (GtkWidget *w,
142 GdkEventFocus *event,
144 static void gtk_font_selection_select_size (GtkTreeSelection *selection,
147 static void gtk_font_selection_scroll_on_map (GtkWidget *w,
150 static void gtk_font_selection_preview_changed (GtkWidget *entry,
151 GtkFontSelection *fontsel);
153 /* Misc. utility functions. */
154 static void gtk_font_selection_load_font (GtkFontSelection *fs);
155 static void gtk_font_selection_update_preview (GtkFontSelection *fs);
157 static GdkFont* gtk_font_selection_get_font_internal (GtkFontSelection *fontsel);
159 /* FontSelectionDialog */
160 static void gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass);
161 static void gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag);
163 static GtkVBoxClass *font_selection_parent_class = NULL;
164 static GtkWindowClass *font_selection_dialog_parent_class = NULL;
168 gtk_font_selection_get_type (void)
170 static GType font_selection_type = 0;
172 if (!font_selection_type)
174 static const GTypeInfo fontsel_type_info =
176 sizeof (GtkFontSelectionClass),
177 NULL, /* base_init */
178 NULL, /* base_finalize */
179 (GClassInitFunc) gtk_font_selection_class_init,
180 NULL, /* class_finalize */
181 NULL, /* class_data */
182 sizeof (GtkFontSelection),
184 (GInstanceInitFunc) gtk_font_selection_init,
187 font_selection_type =
188 g_type_register_static (GTK_TYPE_VBOX, "GtkFontSelection",
189 &fontsel_type_info, 0);
192 return font_selection_type;
196 gtk_font_selection_class_init (GtkFontSelectionClass *klass)
198 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
199 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
201 font_selection_parent_class = g_type_class_peek_parent (klass);
203 gobject_class->set_property = gtk_font_selection_set_property;
204 gobject_class->get_property = gtk_font_selection_get_property;
206 widget_class->screen_changed = gtk_font_selection_screen_changed;
208 g_object_class_install_property (gobject_class,
210 g_param_spec_string ("font_name",
212 P_("The X string that represents this font"),
215 g_object_class_install_property (gobject_class,
217 g_param_spec_boxed ("font",
219 P_("The GdkFont that is currently selected"),
222 g_object_class_install_property (gobject_class,
224 g_param_spec_string ("preview_text",
226 P_("The text to display in order to demonstrate the selected font"),
229 gobject_class->finalize = gtk_font_selection_finalize;
233 gtk_font_selection_set_property (GObject *object,
238 GtkFontSelection *fontsel;
240 fontsel = GTK_FONT_SELECTION (object);
245 gtk_font_selection_set_font_name (fontsel, g_value_get_string (value));
247 case PROP_PREVIEW_TEXT:
248 gtk_font_selection_set_preview_text (fontsel, g_value_get_string (value));
251 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
256 static void gtk_font_selection_get_property (GObject *object,
261 GtkFontSelection *fontsel;
263 fontsel = GTK_FONT_SELECTION (object);
268 g_value_set_string (value, gtk_font_selection_get_font_name (fontsel));
271 g_value_set_object (value, gtk_font_selection_get_font_internal (fontsel));
273 case PROP_PREVIEW_TEXT:
274 g_value_set_string (value, gtk_font_selection_get_preview_text (fontsel));
277 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
284 gtk_font_selection_init (GtkFontSelection *fontsel)
286 GtkWidget *scrolled_win;
287 GtkWidget *text_frame;
289 GtkWidget *table, *label;
290 GtkWidget *font_label, *style_label;
292 GtkTreeViewColumn *column;
293 GList *focus_chain = NULL;
295 gtk_widget_push_composite_child ();
297 fontsel->size = 12 * PANGO_SCALE;
299 /* Create the table of font, style & size. */
300 table = gtk_table_new (3, 3, FALSE);
301 gtk_widget_show (table);
302 gtk_table_set_col_spacings (GTK_TABLE (table), 8);
303 gtk_box_pack_start (GTK_BOX (fontsel), table, TRUE, TRUE, 0);
305 #ifdef INCLUDE_FONT_ENTRIES
306 fontsel->font_entry = gtk_entry_new ();
307 gtk_editable_set_editable (GTK_EDITABLE (fontsel->font_entry), FALSE);
308 gtk_widget_set_size_request (fontsel->font_entry, 20, -1);
309 gtk_widget_show (fontsel->font_entry);
310 gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
313 fontsel->font_style_entry = gtk_entry_new ();
314 gtk_editable_set_editable (GTK_EDITABLE (fontsel->font_style_entry), FALSE);
315 gtk_widget_set_size_request (fontsel->font_style_entry, 20, -1);
316 gtk_widget_show (fontsel->font_style_entry);
317 gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
319 #endif /* INCLUDE_FONT_ENTRIES */
321 fontsel->size_entry = gtk_entry_new ();
322 gtk_widget_set_size_request (fontsel->size_entry, 20, -1);
323 gtk_widget_show (fontsel->size_entry);
324 gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
326 g_signal_connect (fontsel->size_entry, "activate",
327 G_CALLBACK (gtk_font_selection_size_activate),
329 g_signal_connect_after (fontsel->size_entry, "focus_out_event",
330 G_CALLBACK (gtk_font_selection_size_focus_out),
333 font_label = gtk_label_new_with_mnemonic (_("_Family:"));
334 gtk_misc_set_alignment (GTK_MISC (font_label), 0.0, 0.5);
335 gtk_widget_show (font_label);
336 gtk_table_attach (GTK_TABLE (table), font_label, 0, 1, 0, 1,
339 style_label = gtk_label_new_with_mnemonic (_("_Style:"));
340 gtk_misc_set_alignment (GTK_MISC (style_label), 0.0, 0.5);
341 gtk_widget_show (style_label);
342 gtk_table_attach (GTK_TABLE (table), style_label, 1, 2, 0, 1,
345 label = gtk_label_new_with_mnemonic (_("Si_ze:"));
346 gtk_label_set_mnemonic_widget (GTK_LABEL (label),
347 fontsel->size_entry);
348 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
349 gtk_widget_show (label);
350 gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
354 /* Create the lists */
356 model = gtk_list_store_new (2,
357 G_TYPE_OBJECT, /* FAMILY_COLUMN */
358 G_TYPE_STRING); /* FAMILY_NAME_COLUMN */
359 fontsel->family_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
360 g_object_unref (model);
362 column = gtk_tree_view_column_new_with_attributes ("Family",
363 gtk_cell_renderer_text_new (),
364 "text", FAMILY_NAME_COLUMN,
366 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
367 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->family_list), column);
369 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->family_list), FALSE);
370 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)),
371 GTK_SELECTION_BROWSE);
373 gtk_label_set_mnemonic_widget (GTK_LABEL (font_label), fontsel->family_list);
375 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
376 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
377 gtk_widget_set_size_request (scrolled_win,
378 FONT_LIST_WIDTH, FONT_LIST_HEIGHT);
379 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->family_list);
380 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
381 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
382 gtk_widget_show (fontsel->family_list);
383 gtk_widget_show (scrolled_win);
385 gtk_table_attach (GTK_TABLE (table), scrolled_win, 0, 1, 1, 3,
386 GTK_EXPAND | GTK_FILL,
387 GTK_EXPAND | GTK_FILL, 0, 0);
388 focus_chain = g_list_append (focus_chain, scrolled_win);
390 model = gtk_list_store_new (2,
391 G_TYPE_OBJECT, /* FACE_COLUMN */
392 G_TYPE_STRING); /* FACE_NAME_COLUMN */
393 fontsel->face_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
394 g_object_unref (model);
396 gtk_label_set_mnemonic_widget (GTK_LABEL (style_label), fontsel->face_list);
398 column = gtk_tree_view_column_new_with_attributes ("Face",
399 gtk_cell_renderer_text_new (),
400 "text", FACE_NAME_COLUMN,
402 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
403 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->face_list), column);
405 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->face_list), FALSE);
406 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)),
407 GTK_SELECTION_BROWSE);
409 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
410 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
411 gtk_widget_set_size_request (scrolled_win,
412 FONT_STYLE_LIST_WIDTH, FONT_LIST_HEIGHT);
413 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->face_list);
414 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
415 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
416 gtk_widget_show (fontsel->face_list);
417 gtk_widget_show (scrolled_win);
418 gtk_table_attach (GTK_TABLE (table), scrolled_win, 1, 2, 1, 3,
419 GTK_EXPAND | GTK_FILL,
420 GTK_EXPAND | GTK_FILL, 0, 0);
421 focus_chain = g_list_append (focus_chain, scrolled_win);
423 focus_chain = g_list_append (focus_chain, fontsel->size_entry);
425 model = gtk_list_store_new (1, G_TYPE_INT);
426 fontsel->size_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
427 g_object_unref (model);
429 column = gtk_tree_view_column_new_with_attributes ("Size",
430 gtk_cell_renderer_text_new (),
433 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
434 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->size_list), column);
436 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->size_list), FALSE);
437 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)),
438 GTK_SELECTION_BROWSE);
440 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
441 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
442 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->size_list);
443 gtk_widget_set_size_request (scrolled_win, -1, FONT_LIST_HEIGHT);
444 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
445 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
446 gtk_widget_show (fontsel->size_list);
447 gtk_widget_show (scrolled_win);
448 gtk_table_attach (GTK_TABLE (table), scrolled_win, 2, 3, 2, 3,
449 GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
450 focus_chain = g_list_append (focus_chain, scrolled_win);
452 gtk_container_set_focus_chain (GTK_CONTAINER (table), focus_chain);
453 g_list_free (focus_chain);
455 /* Insert the fonts. */
456 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)), "changed",
457 G_CALLBACK (gtk_font_selection_select_font), fontsel);
459 g_signal_connect_after (fontsel->family_list, "map",
460 G_CALLBACK (gtk_font_selection_scroll_on_map),
463 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)), "changed",
464 G_CALLBACK (gtk_font_selection_select_style), fontsel);
466 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)), "changed",
467 G_CALLBACK (gtk_font_selection_select_size), fontsel);
469 /* create the text entry widget */
470 label = gtk_label_new_with_mnemonic (_("_Preview:"));
471 gtk_widget_show (label);
473 text_frame = gtk_frame_new (NULL);
474 gtk_frame_set_label_widget (GTK_FRAME (text_frame), label);
476 gtk_widget_show (text_frame);
477 gtk_frame_set_shadow_type (GTK_FRAME (text_frame), GTK_SHADOW_ETCHED_IN);
478 gtk_box_pack_start (GTK_BOX (fontsel), text_frame,
481 /* This is just used to get a 4-pixel space around the preview entry. */
482 text_box = gtk_hbox_new (FALSE, 0);
483 gtk_widget_show (text_box);
484 gtk_container_add (GTK_CONTAINER (text_frame), text_box);
485 gtk_container_set_border_width (GTK_CONTAINER (text_box), 4);
487 fontsel->preview_entry = gtk_entry_new ();
488 gtk_label_set_mnemonic_widget (GTK_LABEL (label), fontsel->preview_entry);
490 gtk_widget_show (fontsel->preview_entry);
491 g_signal_connect (fontsel->preview_entry, "changed",
492 G_CALLBACK (gtk_font_selection_preview_changed), fontsel);
493 gtk_widget_set_size_request (fontsel->preview_entry,
494 -1, INITIAL_PREVIEW_HEIGHT);
495 gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
498 gtk_widget_pop_composite_child();
502 gtk_font_selection_new ()
504 GtkFontSelection *fontsel;
506 fontsel = g_object_new (GTK_TYPE_FONT_SELECTION, NULL);
508 return GTK_WIDGET (fontsel);
512 gtk_font_selection_finalize (GObject *object)
514 GtkFontSelection *fontsel;
516 g_return_if_fail (GTK_IS_FONT_SELECTION (object));
518 fontsel = GTK_FONT_SELECTION (object);
521 gdk_font_unref (fontsel->font);
523 if (G_OBJECT_CLASS (font_selection_parent_class)->finalize)
524 (* G_OBJECT_CLASS (font_selection_parent_class)->finalize) (object);
528 gtk_font_selection_screen_changed (GtkWidget *widget,
529 GdkScreen *previous_screen)
531 GtkFontSelection *fontsel = GTK_FONT_SELECTION (widget);
533 if (gtk_widget_has_screen (GTK_WIDGET (fontsel)))
535 gtk_font_selection_show_available_fonts (fontsel);
536 gtk_font_selection_show_available_sizes (fontsel, TRUE);
537 gtk_font_selection_show_available_styles (fontsel);
542 gtk_font_selection_preview_changed (GtkWidget *entry,
543 GtkFontSelection *fontsel)
545 g_object_notify (G_OBJECT (fontsel), "preview_text");
549 scroll_to_selection (GtkTreeView *tree_view)
551 GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
555 if (gtk_tree_selection_get_selected (selection, &model, &iter))
557 GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
558 gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.5);
559 gtk_tree_path_free (path);
564 set_cursor_to_iter (GtkTreeView *view,
567 GtkTreeModel *model = gtk_tree_view_get_model (view);
568 GtkTreePath *path = gtk_tree_model_get_path (model, iter);
570 gtk_tree_view_set_cursor (view, path, 0, FALSE);
572 gtk_tree_path_free (path);
575 /* This is called when the list is mapped. Here we scroll to the current
576 font if necessary. */
578 gtk_font_selection_scroll_on_map (GtkWidget *widget,
581 GtkFontSelection *fontsel;
584 g_message ("In expose_list\n");
586 fontsel = GTK_FONT_SELECTION (data);
588 /* Try to scroll the font family list to the selected item */
589 scroll_to_selection (GTK_TREE_VIEW (fontsel->family_list));
591 /* Try to scroll the font family list to the selected item */
592 scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
594 /* Try to scroll the font family list to the selected item */
595 scroll_to_selection (GTK_TREE_VIEW (fontsel->size_list));
598 /* This is called when a family is selected in the list. */
600 gtk_font_selection_select_font (GtkTreeSelection *selection,
603 GtkFontSelection *fontsel;
606 const gchar *family_name;
608 fontsel = GTK_FONT_SELECTION (data);
610 if (gtk_tree_selection_get_selected (selection, &model, &iter))
612 PangoFontFamily *family;
614 gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
615 if (fontsel->family != family)
617 fontsel->family = family;
619 family_name = pango_font_family_get_name (fontsel->family);
621 #ifdef INCLUDE_FONT_ENTRIES
622 gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), family_name);
625 gtk_font_selection_show_available_styles (fontsel);
626 gtk_font_selection_select_best_style (fontsel, TRUE);
629 g_object_unref (family);
634 cmp_families (const void *a, const void *b)
636 const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a);
637 const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b);
639 return g_utf8_collate (a_name, b_name);
643 gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
646 PangoFontFamily **families;
647 PangoFontFamily *match_family = NULL;
649 GtkTreeIter match_row;
651 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list)));
653 pango_context_list_families (gtk_widget_get_pango_context (GTK_WIDGET (fontsel)),
654 &families, &n_families);
655 qsort (families, n_families, sizeof (PangoFontFamily *), cmp_families);
657 gtk_list_store_clear (model);
659 for (i=0; i<n_families; i++)
661 const gchar *name = pango_font_family_get_name (families[i]);
664 gtk_list_store_append (model, &iter);
665 gtk_list_store_set (model, &iter,
666 FAMILY_COLUMN, families[i],
667 FAMILY_NAME_COLUMN, name,
670 if (i == 0 || !g_ascii_strcasecmp (name, "sans"))
672 match_family = families[i];
677 fontsel->family = match_family;
680 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &match_row);
681 #ifdef INCLUDE_FONT_ENTRIES
682 gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry),
683 pango_font_family_get_name (match_family));
684 #endif /* INCLUDE_FONT_ENTRIES */
691 compare_font_descriptions (const PangoFontDescription *a, const PangoFontDescription *b)
693 int val = strcmp (pango_font_description_get_family (a), pango_font_description_get_family (b));
697 if (pango_font_description_get_weight (a) != pango_font_description_get_weight (b))
698 return pango_font_description_get_weight (a) - pango_font_description_get_weight (b);
700 if (pango_font_description_get_style (a) != pango_font_description_get_style (b))
701 return pango_font_description_get_style (a) - pango_font_description_get_style (b);
703 if (pango_font_description_get_stretch (a) != pango_font_description_get_stretch (b))
704 return pango_font_description_get_stretch (a) - pango_font_description_get_stretch (b);
706 if (pango_font_description_get_variant (a) != pango_font_description_get_variant (b))
707 return pango_font_description_get_variant (a) - pango_font_description_get_variant (b);
713 faces_sort_func (const void *a, const void *b)
715 PangoFontDescription *desc_a = pango_font_face_describe (*(PangoFontFace **)a);
716 PangoFontDescription *desc_b = pango_font_face_describe (*(PangoFontFace **)b);
718 int ord = compare_font_descriptions (desc_a, desc_b);
720 pango_font_description_free (desc_a);
721 pango_font_description_free (desc_b);
727 font_description_style_equal (const PangoFontDescription *a,
728 const PangoFontDescription *b)
730 return (pango_font_description_get_weight (a) == pango_font_description_get_weight (b) &&
731 pango_font_description_get_style (a) == pango_font_description_get_style (b) &&
732 pango_font_description_get_stretch (a) == pango_font_description_get_stretch (b) &&
733 pango_font_description_get_variant (a) == pango_font_description_get_variant (b));
736 /* This fills the font style list with all the possible style combinations
737 for the current font family. */
739 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
742 PangoFontFace **faces;
743 PangoFontDescription *old_desc;
745 GtkTreeIter match_row;
746 PangoFontFace *match_face = NULL;
748 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list)));
751 old_desc = pango_font_face_describe (fontsel->face);
755 pango_font_family_list_faces (fontsel->family, &faces, &n_faces);
756 qsort (faces, n_faces, sizeof (PangoFontFace *), faces_sort_func);
758 gtk_list_store_clear (model);
760 for (i=0; i < n_faces; i++)
763 const gchar *str = pango_font_face_get_face_name (faces[i]);
765 gtk_list_store_append (model, &iter);
766 gtk_list_store_set (model, &iter,
767 FACE_COLUMN, faces[i],
768 FACE_NAME_COLUMN, str,
774 match_face = faces[i];
778 PangoFontDescription *tmp_desc = pango_font_face_describe (faces[i]);
780 if (font_description_style_equal (tmp_desc, old_desc))
783 match_face = faces[i];
786 pango_font_description_free (tmp_desc);
791 pango_font_description_free (old_desc);
793 fontsel->face = match_face;
796 #ifdef INCLUDE_FONT_ENTRIES
797 const gchar *str = pango_font_face_get_face_name (fontsel->face);
799 gtk_entry_set_text (GTK_ENTRY (fontsel->font_style_entry), str);
801 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_row);
807 /* This selects a style when the user selects a font. It just uses the first
808 available style at present. I was thinking of trying to maintain the
809 selected style, e.g. bold italic, when the user selects different fonts.
810 However, the interface is so easy to use now I'm not sure it's worth it.
811 Note: This will load a font. */
813 gtk_font_selection_select_best_style (GtkFontSelection *fontsel,
819 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
821 if (gtk_tree_model_get_iter_first (model, &iter))
823 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &iter);
824 scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
827 gtk_font_selection_show_available_sizes (fontsel, FALSE);
828 gtk_font_selection_select_best_size (fontsel);
832 /* This is called when a style is selected in the list. */
834 gtk_font_selection_select_style (GtkTreeSelection *selection,
837 GtkFontSelection *fontsel = GTK_FONT_SELECTION (data);
841 if (gtk_tree_selection_get_selected (selection, &model, &iter))
845 gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
846 fontsel->face = face;
848 g_object_unref (face);
851 gtk_font_selection_show_available_sizes (fontsel, FALSE);
852 gtk_font_selection_select_best_size (fontsel);
856 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel,
861 GtkTreeSelection *selection;
865 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->size_list)));
866 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
868 /* Insert the standard font sizes */
871 gtk_list_store_clear (model);
873 for (i = 0; i < G_N_ELEMENTS (font_sizes); i++)
877 gtk_list_store_append (model, &iter);
878 gtk_list_store_set (model, &iter, SIZE_COLUMN, font_sizes[i], -1);
880 if (font_sizes[i] * PANGO_SCALE == fontsel->size)
881 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
887 gboolean found = FALSE;
889 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
890 for (i = 0; i < G_N_ELEMENTS (font_sizes) && !found; i++)
892 if (font_sizes[i] * PANGO_SCALE == fontsel->size)
894 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
898 gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter);
903 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
904 gtk_tree_selection_unselect_all (selection);
908 /* Set the entry to the new size, rounding to 1 digit,
909 * trimming of trailing 0's and a trailing period
911 g_snprintf (buffer, sizeof (buffer), "%.1f", fontsel->size / (1.0 * PANGO_SCALE));
912 if (strchr (buffer, '.'))
914 p = buffer + strlen (buffer) - 1;
922 /* Compare, to avoid moving the cursor unecessarily */
923 if (strcmp (gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry)), buffer) != 0)
924 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
928 gtk_font_selection_select_best_size (GtkFontSelection *fontsel)
930 gtk_font_selection_load_font (fontsel);
934 gtk_font_selection_set_size (GtkFontSelection *fontsel,
937 if (fontsel->size != new_size)
939 fontsel->size = new_size;
941 gtk_font_selection_show_available_sizes (fontsel, FALSE);
942 gtk_font_selection_load_font (fontsel);
946 /* If the user hits return in the font size entry, we change to the new font
949 gtk_font_selection_size_activate (GtkWidget *w,
952 GtkFontSelection *fontsel;
956 fontsel = GTK_FONT_SELECTION (data);
958 text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
959 new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);
961 gtk_font_selection_set_size (fontsel, new_size);
965 gtk_font_selection_size_focus_out (GtkWidget *w,
966 GdkEventFocus *event,
969 gtk_font_selection_size_activate (w, data);
974 /* This is called when a size is selected in the list. */
976 gtk_font_selection_select_size (GtkTreeSelection *selection,
979 GtkFontSelection *fontsel;
984 fontsel = GTK_FONT_SELECTION (data);
986 if (gtk_tree_selection_get_selected (selection, &model, &iter))
988 gtk_tree_model_get (model, &iter, SIZE_COLUMN, &new_size, -1);
989 gtk_font_selection_set_size (fontsel, new_size * PANGO_SCALE);
994 gtk_font_selection_load_font (GtkFontSelection *fontsel)
997 gdk_font_unref (fontsel->font);
998 fontsel->font = NULL;
1000 gtk_font_selection_update_preview (fontsel);
1003 static PangoFontDescription *
1004 gtk_font_selection_get_font_description (GtkFontSelection *fontsel)
1006 PangoFontDescription *font_desc;
1010 font_desc = pango_font_face_describe (fontsel->face);
1011 pango_font_description_set_size (font_desc, fontsel->size);
1014 font_desc = pango_font_description_from_string ("Sans 10");
1019 /* This sets the font in the preview entry to the selected font, and tries to
1020 make sure that the preview entry is a reasonable size, i.e. so that the
1021 text can be seen with a bit of space to spare. But it tries to avoid
1022 resizing the entry every time the font changes.
1023 This also used to shrink the preview if the font size was decreased, but
1024 that made it awkward if the user wanted to resize the window themself. */
1026 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1028 GtkRcStyle *rc_style;
1030 GtkRequisition old_requisition;
1031 GtkWidget *preview_entry = fontsel->preview_entry;
1034 gtk_widget_get_child_requisition (preview_entry, &old_requisition);
1036 rc_style = gtk_rc_style_new ();
1037 rc_style->font_desc = gtk_font_selection_get_font_description (fontsel);
1039 gtk_widget_modify_style (preview_entry, rc_style);
1040 gtk_rc_style_unref (rc_style);
1042 gtk_widget_size_request (preview_entry, NULL);
1044 /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1045 new_height = CLAMP (preview_entry->requisition.height, INITIAL_PREVIEW_HEIGHT, MAX_PREVIEW_HEIGHT);
1047 if (new_height > old_requisition.height || new_height < old_requisition.height - 30)
1048 gtk_widget_set_size_request (preview_entry, -1, new_height);
1050 /* This sets the preview text, if it hasn't been set already. */
1051 text = gtk_entry_get_text (GTK_ENTRY (preview_entry));
1052 if (strlen (text) == 0)
1053 gtk_entry_set_text (GTK_ENTRY (preview_entry), _(PREVIEW_TEXT));
1054 gtk_editable_set_position (GTK_EDITABLE (preview_entry), 0);
1058 gtk_font_selection_get_font_internal (GtkFontSelection *fontsel)
1062 PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1063 fontsel->font = gdk_font_from_description_for_display (gtk_widget_get_display (GTK_WIDGET (fontsel)), font_desc);
1064 pango_font_description_free (font_desc);
1067 return fontsel->font;
1071 /*****************************************************************************
1072 * These functions are the main public interface for getting/setting the font.
1073 *****************************************************************************/
1076 gtk_font_selection_get_font (GtkFontSelection *fontsel)
1078 return gtk_font_selection_get_font_internal (fontsel);
1082 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
1086 PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1087 result = pango_font_description_to_string (font_desc);
1088 pango_font_description_free (font_desc);
1094 /* This sets the current font, selecting the appropriate list rows.
1095 First we check the fontname is valid and try to find the font family
1096 - i.e. the name in the main list. If we can't find that, then just return.
1097 Next we try to set each of the properties according to the fontname.
1098 Finally we select the font family & style in the lists. */
1100 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
1101 const gchar *fontname)
1103 PangoFontFamily *new_family = NULL;
1104 PangoFontFace *new_face = NULL;
1105 PangoFontFace *fallback_face = NULL;
1106 PangoFontDescription *new_desc;
1107 GtkTreeModel *model;
1109 GtkTreeIter match_iter;
1112 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
1114 new_desc = pango_font_description_from_string (fontname);
1116 /* Check to make sure that this is in the list of allowed fonts */
1118 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list));
1119 for (valid = gtk_tree_model_get_iter_first (model, &iter);
1121 valid = gtk_tree_model_iter_next (model, &iter))
1123 PangoFontFamily *family;
1125 gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
1127 if (g_ascii_strcasecmp (pango_font_family_get_name (family),
1128 pango_font_description_get_family (new_desc)) == 0)
1129 new_family = family;
1131 g_object_unref (family);
1140 fontsel->family = new_family;
1141 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &iter);
1142 gtk_font_selection_show_available_styles (fontsel);
1144 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
1145 for (valid = gtk_tree_model_get_iter_first (model, &iter);
1147 valid = gtk_tree_model_iter_next (model, &iter))
1149 PangoFontFace *face;
1150 PangoFontDescription *tmp_desc;
1152 gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
1153 tmp_desc = pango_font_face_describe (face);
1155 if (font_description_style_equal (tmp_desc, new_desc))
1160 fallback_face = face;
1164 pango_font_description_free (tmp_desc);
1165 g_object_unref (face);
1175 new_face = fallback_face;
1177 fontsel->face = new_face;
1178 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_iter);
1180 gtk_font_selection_set_size (fontsel, pango_font_description_get_size (new_desc));
1182 g_object_freeze_notify (G_OBJECT (fontsel));
1183 g_object_notify (G_OBJECT (fontsel), "font_name");
1184 g_object_notify (G_OBJECT (fontsel), "font");
1185 g_object_thaw_notify (G_OBJECT (fontsel));
1187 pango_font_description_free (new_desc);
1193 /* This returns the text in the preview entry. You should copy the returned
1194 text if you need it. */
1195 G_CONST_RETURN gchar*
1196 gtk_font_selection_get_preview_text (GtkFontSelection *fontsel)
1198 return gtk_entry_get_text (GTK_ENTRY (fontsel->preview_entry));
1202 /* This sets the text in the preview entry. */
1204 gtk_font_selection_set_preview_text (GtkFontSelection *fontsel,
1207 gtk_entry_set_text (GTK_ENTRY (fontsel->preview_entry), text);
1210 /*****************************************************************************
1211 * GtkFontSelectionDialog
1212 *****************************************************************************/
1215 gtk_font_selection_dialog_get_type (void)
1217 static GType font_selection_dialog_type = 0;
1219 if (!font_selection_dialog_type)
1221 static const GTypeInfo fontsel_diag_info =
1223 sizeof (GtkFontSelectionDialogClass),
1224 NULL, /* base_init */
1225 NULL, /* base_finalize */
1226 (GClassInitFunc) gtk_font_selection_dialog_class_init,
1227 NULL, /* class_finalize */
1228 NULL, /* class_data */
1229 sizeof (GtkFontSelectionDialog),
1230 0, /* n_preallocs */
1231 (GInstanceInitFunc) gtk_font_selection_dialog_init,
1234 font_selection_dialog_type =
1235 g_type_register_static (GTK_TYPE_DIALOG, "GtkFontSelectionDialog",
1236 &fontsel_diag_info, 0);
1239 return font_selection_dialog_type;
1243 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
1245 font_selection_dialog_parent_class = g_type_class_peek_parent (klass);
1249 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
1253 gtk_widget_push_composite_child ();
1255 dialog = GTK_DIALOG (fontseldiag);
1257 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag), 4);
1258 gtk_window_set_resizable (GTK_WINDOW (fontseldiag), TRUE);
1260 fontseldiag->main_vbox = dialog->vbox;
1262 fontseldiag->fontsel = gtk_font_selection_new ();
1263 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag->fontsel), 4);
1264 gtk_widget_show (fontseldiag->fontsel);
1265 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
1266 fontseldiag->fontsel, TRUE, TRUE, 0);
1268 /* Create the action area */
1269 fontseldiag->action_area = dialog->action_area;
1271 fontseldiag->cancel_button = gtk_dialog_add_button (dialog,
1273 GTK_RESPONSE_CANCEL);
1275 fontseldiag->apply_button = gtk_dialog_add_button (dialog,
1277 GTK_RESPONSE_APPLY);
1278 gtk_widget_hide (fontseldiag->apply_button);
1280 fontseldiag->ok_button = gtk_dialog_add_button (dialog,
1283 gtk_widget_grab_default (fontseldiag->ok_button);
1285 gtk_window_set_title (GTK_WINDOW (fontseldiag),
1286 _("Font Selection"));
1288 gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
1290 gtk_widget_pop_composite_child ();
1294 gtk_font_selection_dialog_new (const gchar *title)
1296 GtkFontSelectionDialog *fontseldiag;
1298 fontseldiag = g_object_new (GTK_TYPE_FONT_SELECTION_DIALOG, NULL);
1301 gtk_window_set_title (GTK_WINDOW (fontseldiag), title);
1303 return GTK_WIDGET (fontseldiag);
1307 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
1309 return gtk_font_selection_get_font_name (GTK_FONT_SELECTION (fsd->fontsel));
1313 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
1315 return gtk_font_selection_get_font (GTK_FONT_SELECTION (fsd->fontsel));
1319 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
1320 const gchar *fontname)
1322 return gtk_font_selection_set_font_name (GTK_FONT_SELECTION (fsd->fontsel), fontname);
1325 G_CONST_RETURN gchar*
1326 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
1328 return gtk_font_selection_get_preview_text (GTK_FONT_SELECTION (fsd->fontsel));
1332 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
1335 gtk_font_selection_set_preview_text (GTK_FONT_SELECTION (fsd->fontsel), text);