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/.
37 #include "gdk/gdkkeysyms.h"
39 #include "gtkfontsel.h"
41 #include "gtkbutton.h"
42 #include "gtkcellrenderertext.h"
48 #include "gtkliststore.h"
52 #include "gtktreeselection.h"
53 #include "gtktreeview.h"
55 #include "gtkscrolledwindow.h"
58 /* We don't enable the font and style entries because they don't add
59 * much in terms of visible effect and have a weird effect on keynav.
60 * the Windows font selector has entries similarly positioned but they
61 * act in conjunction with the associated lists to form a single focus
64 #undef INCLUDE_FONT_ENTRIES
66 /* This is the default text shown in the preview entry, though the user
67 can set it. Remember that some fonts only have capital letters. */
68 #define PREVIEW_TEXT N_("abcdefghijk ABCDEFGHIJK")
70 /* This is the initial and maximum height of the preview entry (it expands
71 when large font sizes are selected). Initial height is also the minimum. */
72 #define INITIAL_PREVIEW_HEIGHT 44
73 #define MAX_PREVIEW_HEIGHT 300
75 /* These are the sizes of the font, style & size lists. */
76 #define FONT_LIST_HEIGHT 136
77 #define FONT_LIST_WIDTH 190
78 #define FONT_STYLE_LIST_WIDTH 170
79 #define FONT_SIZE_LIST_WIDTH 60
81 /* These are what we use as the standard font sizes, for the size list.
83 static const guint16 font_sizes[] = {
84 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28,
85 32, 36, 40, 48, 56, 64, 72
110 static void gtk_font_selection_class_init (GtkFontSelectionClass *klass);
111 static void gtk_font_selection_set_property (GObject *object,
115 static void gtk_font_selection_get_property (GObject *object,
119 static void gtk_font_selection_init (GtkFontSelection *fontsel);
120 static void gtk_font_selection_finalize (GObject *object);
121 static void gtk_font_selection_screen_changed (GtkWidget *widget,
122 GdkScreen *previous_screen);
124 /* These are the callbacks & related functions. */
125 static void gtk_font_selection_select_font (GtkTreeSelection *selection,
127 static void gtk_font_selection_show_available_fonts (GtkFontSelection *fs);
129 static void gtk_font_selection_show_available_styles (GtkFontSelection *fs);
130 static void gtk_font_selection_select_best_style (GtkFontSelection *fs,
132 static void gtk_font_selection_select_style (GtkTreeSelection *selection,
135 static void gtk_font_selection_select_best_size (GtkFontSelection *fs);
136 static void gtk_font_selection_show_available_sizes (GtkFontSelection *fs,
137 gboolean first_time);
138 static void gtk_font_selection_size_activate (GtkWidget *w,
140 static gboolean gtk_font_selection_size_focus_out (GtkWidget *w,
141 GdkEventFocus *event,
143 static void gtk_font_selection_select_size (GtkTreeSelection *selection,
146 static void gtk_font_selection_scroll_on_map (GtkWidget *w,
149 static void gtk_font_selection_preview_changed (GtkWidget *entry,
150 GtkFontSelection *fontsel);
152 /* Misc. utility functions. */
153 static void gtk_font_selection_load_font (GtkFontSelection *fs);
154 static void gtk_font_selection_update_preview (GtkFontSelection *fs);
156 static GdkFont* gtk_font_selection_get_font_internal (GtkFontSelection *fontsel);
158 /* FontSelectionDialog */
159 static void gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass);
160 static void gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag);
162 static GtkVBoxClass *font_selection_parent_class = NULL;
163 static GtkWindowClass *font_selection_dialog_parent_class = NULL;
167 gtk_font_selection_get_type (void)
169 static GType font_selection_type = 0;
171 if (!font_selection_type)
173 static const GTypeInfo fontsel_type_info =
175 sizeof (GtkFontSelectionClass),
176 NULL, /* base_init */
177 NULL, /* base_finalize */
178 (GClassInitFunc) gtk_font_selection_class_init,
179 NULL, /* class_finalize */
180 NULL, /* class_data */
181 sizeof (GtkFontSelection),
183 (GInstanceInitFunc) gtk_font_selection_init,
186 font_selection_type =
187 g_type_register_static (GTK_TYPE_VBOX, "GtkFontSelection",
188 &fontsel_type_info, 0);
191 return font_selection_type;
195 gtk_font_selection_class_init (GtkFontSelectionClass *klass)
197 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
198 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
200 font_selection_parent_class = g_type_class_peek_parent (klass);
202 gobject_class->set_property = gtk_font_selection_set_property;
203 gobject_class->get_property = gtk_font_selection_get_property;
205 widget_class->screen_changed = gtk_font_selection_screen_changed;
207 g_object_class_install_property (gobject_class,
209 g_param_spec_string ("font_name",
211 _("The X string that represents this font"),
214 g_object_class_install_property (gobject_class,
216 g_param_spec_boxed ("font",
218 _("The GdkFont that is currently selected"),
221 g_object_class_install_property (gobject_class,
223 g_param_spec_string ("preview_text",
225 _("The text to display in order to demonstrate the selected font"),
228 gobject_class->finalize = gtk_font_selection_finalize;
232 gtk_font_selection_set_property (GObject *object,
237 GtkFontSelection *fontsel;
239 fontsel = GTK_FONT_SELECTION (object);
244 gtk_font_selection_set_font_name (fontsel, g_value_get_string (value));
246 case PROP_PREVIEW_TEXT:
247 gtk_font_selection_set_preview_text (fontsel, g_value_get_string (value));
250 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
255 static void gtk_font_selection_get_property (GObject *object,
260 GtkFontSelection *fontsel;
262 fontsel = GTK_FONT_SELECTION (object);
267 g_value_set_string (value, gtk_font_selection_get_font_name (fontsel));
270 g_value_set_object (value, gtk_font_selection_get_font_internal (fontsel));
272 case PROP_PREVIEW_TEXT:
273 g_value_set_string (value, gtk_font_selection_get_preview_text (fontsel));
276 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
283 gtk_font_selection_init (GtkFontSelection *fontsel)
285 GtkWidget *scrolled_win;
286 GtkWidget *text_frame;
288 GtkWidget *table, *label;
289 GtkWidget *font_label, *style_label;
291 GtkTreeViewColumn *column;
292 GList *focus_chain = NULL;
294 gtk_widget_push_composite_child ();
296 fontsel->size = 12 * PANGO_SCALE;
298 /* Create the table of font, style & size. */
299 table = gtk_table_new (3, 3, FALSE);
300 gtk_widget_show (table);
301 gtk_table_set_col_spacings (GTK_TABLE (table), 8);
302 gtk_box_pack_start (GTK_BOX (fontsel), table, TRUE, TRUE, 0);
304 #ifdef INCLUDE_FONT_ENTRIES
305 fontsel->font_entry = gtk_entry_new ();
306 gtk_editable_set_editable (GTK_EDITABLE (fontsel->font_entry), FALSE);
307 gtk_widget_set_size_request (fontsel->font_entry, 20, -1);
308 gtk_widget_show (fontsel->font_entry);
309 gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
312 fontsel->font_style_entry = gtk_entry_new ();
313 gtk_editable_set_editable (GTK_EDITABLE (fontsel->font_style_entry), FALSE);
314 gtk_widget_set_size_request (fontsel->font_style_entry, 20, -1);
315 gtk_widget_show (fontsel->font_style_entry);
316 gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
318 #endif /* INCLUDE_FONT_ENTRIES */
320 fontsel->size_entry = gtk_entry_new ();
321 gtk_widget_set_size_request (fontsel->size_entry, 20, -1);
322 gtk_widget_show (fontsel->size_entry);
323 gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
325 g_signal_connect (fontsel->size_entry, "activate",
326 G_CALLBACK (gtk_font_selection_size_activate),
328 g_signal_connect_after (fontsel->size_entry, "focus_out_event",
329 G_CALLBACK (gtk_font_selection_size_focus_out),
332 font_label = gtk_label_new_with_mnemonic (_("_Family:"));
333 gtk_misc_set_alignment (GTK_MISC (font_label), 0.0, 0.5);
334 gtk_widget_show (font_label);
335 gtk_table_attach (GTK_TABLE (table), font_label, 0, 1, 0, 1,
338 style_label = gtk_label_new_with_mnemonic (_("_Style:"));
339 gtk_misc_set_alignment (GTK_MISC (style_label), 0.0, 0.5);
340 gtk_widget_show (style_label);
341 gtk_table_attach (GTK_TABLE (table), style_label, 1, 2, 0, 1,
344 label = gtk_label_new_with_mnemonic (_("Si_ze:"));
345 gtk_label_set_mnemonic_widget (GTK_LABEL (label),
346 fontsel->size_entry);
347 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
348 gtk_widget_show (label);
349 gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
353 /* Create the lists */
355 model = gtk_list_store_new (2,
356 G_TYPE_OBJECT, /* FAMILY_COLUMN */
357 G_TYPE_STRING); /* FAMILY_NAME_COLUMN */
358 fontsel->family_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
359 g_object_unref (model);
361 column = gtk_tree_view_column_new_with_attributes ("Family",
362 gtk_cell_renderer_text_new (),
363 "text", FAMILY_NAME_COLUMN,
365 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
366 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->family_list), column);
368 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->family_list), FALSE);
369 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)),
370 GTK_SELECTION_BROWSE);
372 gtk_label_set_mnemonic_widget (GTK_LABEL (font_label), fontsel->family_list);
374 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
375 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
376 gtk_widget_set_size_request (scrolled_win,
377 FONT_LIST_WIDTH, FONT_LIST_HEIGHT);
378 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->family_list);
379 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
380 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
381 gtk_widget_show (fontsel->family_list);
382 gtk_widget_show (scrolled_win);
384 gtk_table_attach (GTK_TABLE (table), scrolled_win, 0, 1, 1, 3,
385 GTK_EXPAND | GTK_FILL,
386 GTK_EXPAND | GTK_FILL, 0, 0);
387 focus_chain = g_list_append (focus_chain, scrolled_win);
389 model = gtk_list_store_new (2,
390 G_TYPE_OBJECT, /* FACE_COLUMN */
391 G_TYPE_STRING); /* FACE_NAME_COLUMN */
392 fontsel->face_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
393 g_object_unref (model);
395 gtk_label_set_mnemonic_widget (GTK_LABEL (style_label), fontsel->face_list);
397 column = gtk_tree_view_column_new_with_attributes ("Face",
398 gtk_cell_renderer_text_new (),
399 "text", FACE_NAME_COLUMN,
401 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
402 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->face_list), column);
404 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->face_list), FALSE);
405 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)),
406 GTK_SELECTION_BROWSE);
408 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
409 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
410 gtk_widget_set_size_request (scrolled_win,
411 FONT_STYLE_LIST_WIDTH, FONT_LIST_HEIGHT);
412 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->face_list);
413 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
414 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
415 gtk_widget_show (fontsel->face_list);
416 gtk_widget_show (scrolled_win);
417 gtk_table_attach (GTK_TABLE (table), scrolled_win, 1, 2, 1, 3,
418 GTK_EXPAND | GTK_FILL,
419 GTK_EXPAND | GTK_FILL, 0, 0);
420 focus_chain = g_list_append (focus_chain, scrolled_win);
422 focus_chain = g_list_append (focus_chain, fontsel->size_entry);
424 model = gtk_list_store_new (1, G_TYPE_INT);
425 fontsel->size_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
426 g_object_unref (model);
428 column = gtk_tree_view_column_new_with_attributes ("Size",
429 gtk_cell_renderer_text_new (),
432 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
433 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->size_list), column);
435 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->size_list), FALSE);
436 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)),
437 GTK_SELECTION_BROWSE);
439 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
440 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
441 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->size_list);
442 gtk_widget_set_size_request (scrolled_win, -1, FONT_LIST_HEIGHT);
443 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
444 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
445 gtk_widget_show (fontsel->size_list);
446 gtk_widget_show (scrolled_win);
447 gtk_table_attach (GTK_TABLE (table), scrolled_win, 2, 3, 2, 3,
448 GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
449 focus_chain = g_list_append (focus_chain, scrolled_win);
451 gtk_container_set_focus_chain (GTK_CONTAINER (table), focus_chain);
452 g_list_free (focus_chain);
454 /* Insert the fonts. */
455 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)), "changed",
456 G_CALLBACK (gtk_font_selection_select_font), fontsel);
458 g_signal_connect_after (fontsel->family_list, "map",
459 G_CALLBACK (gtk_font_selection_scroll_on_map),
462 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)), "changed",
463 G_CALLBACK (gtk_font_selection_select_style), fontsel);
465 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)), "changed",
466 G_CALLBACK (gtk_font_selection_select_size), fontsel);
468 /* create the text entry widget */
469 label = gtk_label_new_with_mnemonic (_("_Preview:"));
470 gtk_widget_show (label);
472 text_frame = gtk_frame_new (NULL);
473 gtk_frame_set_label_widget (GTK_FRAME (text_frame), label);
475 gtk_widget_show (text_frame);
476 gtk_frame_set_shadow_type (GTK_FRAME (text_frame), GTK_SHADOW_ETCHED_IN);
477 gtk_box_pack_start (GTK_BOX (fontsel), text_frame,
480 /* This is just used to get a 4-pixel space around the preview entry. */
481 text_box = gtk_hbox_new (FALSE, 0);
482 gtk_widget_show (text_box);
483 gtk_container_add (GTK_CONTAINER (text_frame), text_box);
484 gtk_container_set_border_width (GTK_CONTAINER (text_box), 4);
486 fontsel->preview_entry = gtk_entry_new ();
487 gtk_label_set_mnemonic_widget (GTK_LABEL (label), fontsel->preview_entry);
489 gtk_widget_show (fontsel->preview_entry);
490 g_signal_connect (fontsel->preview_entry, "changed",
491 G_CALLBACK (gtk_font_selection_preview_changed), fontsel);
492 gtk_widget_set_size_request (fontsel->preview_entry,
493 -1, INITIAL_PREVIEW_HEIGHT);
494 gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
497 gtk_widget_pop_composite_child();
501 gtk_font_selection_new ()
503 GtkFontSelection *fontsel;
505 fontsel = g_object_new (GTK_TYPE_FONT_SELECTION, NULL);
507 return GTK_WIDGET (fontsel);
511 gtk_font_selection_finalize (GObject *object)
513 GtkFontSelection *fontsel;
515 g_return_if_fail (GTK_IS_FONT_SELECTION (object));
517 fontsel = GTK_FONT_SELECTION (object);
520 gdk_font_unref (fontsel->font);
522 if (G_OBJECT_CLASS (font_selection_parent_class)->finalize)
523 (* G_OBJECT_CLASS (font_selection_parent_class)->finalize) (object);
527 gtk_font_selection_screen_changed (GtkWidget *widget,
528 GdkScreen *previous_screen)
530 GtkFontSelection *fontsel = GTK_FONT_SELECTION (widget);
532 if (gtk_widget_has_screen (GTK_WIDGET (fontsel)))
534 gtk_font_selection_show_available_fonts (fontsel);
535 gtk_font_selection_show_available_sizes (fontsel, TRUE);
536 gtk_font_selection_show_available_styles (fontsel);
541 gtk_font_selection_preview_changed (GtkWidget *entry,
542 GtkFontSelection *fontsel)
544 g_object_notify (G_OBJECT (fontsel), "preview_text");
548 scroll_to_selection (GtkTreeView *tree_view)
550 GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
554 if (gtk_tree_selection_get_selected (selection, &model, &iter))
556 GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
557 gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.5);
558 gtk_tree_path_free (path);
563 set_cursor_to_iter (GtkTreeView *view,
566 GtkTreeModel *model = gtk_tree_view_get_model (view);
567 GtkTreePath *path = gtk_tree_model_get_path (model, iter);
569 gtk_tree_view_set_cursor (view, path, 0, FALSE);
571 gtk_tree_path_free (path);
574 /* This is called when the list is mapped. Here we scroll to the current
575 font if necessary. */
577 gtk_font_selection_scroll_on_map (GtkWidget *widget,
580 GtkFontSelection *fontsel;
583 g_message ("In expose_list\n");
585 fontsel = GTK_FONT_SELECTION (data);
587 /* Try to scroll the font family list to the selected item */
588 scroll_to_selection (GTK_TREE_VIEW (fontsel->family_list));
590 /* Try to scroll the font family list to the selected item */
591 scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
593 /* Try to scroll the font family list to the selected item */
594 scroll_to_selection (GTK_TREE_VIEW (fontsel->size_list));
597 /* This is called when a family is selected in the list. */
599 gtk_font_selection_select_font (GtkTreeSelection *selection,
602 GtkFontSelection *fontsel;
605 const gchar *family_name;
607 fontsel = GTK_FONT_SELECTION (data);
609 if (gtk_tree_selection_get_selected (selection, &model, &iter))
611 PangoFontFamily *family;
613 gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
614 if (fontsel->family != family)
616 fontsel->family = family;
618 family_name = pango_font_family_get_name (fontsel->family);
620 #ifdef INCLUDE_FONT_ENTRIES
621 gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), family_name);
624 gtk_font_selection_show_available_styles (fontsel);
625 gtk_font_selection_select_best_style (fontsel, TRUE);
628 g_object_unref (family);
633 cmp_families (const void *a, const void *b)
635 const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a);
636 const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b);
638 return g_utf8_collate (a_name, b_name);
642 gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
645 PangoFontFamily **families;
646 PangoFontFamily *match_family = NULL;
648 GtkTreeIter match_row;
650 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list)));
652 pango_context_list_families (gtk_widget_get_pango_context (GTK_WIDGET (fontsel)),
653 &families, &n_families);
654 qsort (families, n_families, sizeof (PangoFontFamily *), cmp_families);
656 gtk_list_store_clear (model);
658 for (i=0; i<n_families; i++)
660 const gchar *name = pango_font_family_get_name (families[i]);
663 gtk_list_store_append (model, &iter);
664 gtk_list_store_set (model, &iter,
665 FAMILY_COLUMN, families[i],
666 FAMILY_NAME_COLUMN, name,
669 if (i == 0 || !g_ascii_strcasecmp (name, "sans"))
671 match_family = families[i];
676 fontsel->family = match_family;
679 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &match_row);
680 #ifdef INCLUDE_FONT_ENTRIES
681 gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry),
682 pango_font_family_get_name (match_family));
683 #endif /* INCLUDE_FONT_ENTRIES */
690 compare_font_descriptions (const PangoFontDescription *a, const PangoFontDescription *b)
692 int val = strcmp (pango_font_description_get_family (a), pango_font_description_get_family (b));
696 if (pango_font_description_get_weight (a) != pango_font_description_get_weight (b))
697 return pango_font_description_get_weight (a) - pango_font_description_get_weight (b);
699 if (pango_font_description_get_style (a) != pango_font_description_get_style (b))
700 return pango_font_description_get_style (a) - pango_font_description_get_style (b);
702 if (pango_font_description_get_stretch (a) != pango_font_description_get_stretch (b))
703 return pango_font_description_get_stretch (a) - pango_font_description_get_stretch (b);
705 if (pango_font_description_get_variant (a) != pango_font_description_get_variant (b))
706 return pango_font_description_get_variant (a) - pango_font_description_get_variant (b);
712 faces_sort_func (const void *a, const void *b)
714 PangoFontDescription *desc_a = pango_font_face_describe (*(PangoFontFace **)a);
715 PangoFontDescription *desc_b = pango_font_face_describe (*(PangoFontFace **)b);
717 int ord = compare_font_descriptions (desc_a, desc_b);
719 pango_font_description_free (desc_a);
720 pango_font_description_free (desc_b);
726 font_description_style_equal (const PangoFontDescription *a,
727 const PangoFontDescription *b)
729 return (pango_font_description_get_weight (a) == pango_font_description_get_weight (b) &&
730 pango_font_description_get_style (a) == pango_font_description_get_style (b) &&
731 pango_font_description_get_stretch (a) == pango_font_description_get_stretch (b) &&
732 pango_font_description_get_variant (a) == pango_font_description_get_variant (b));
735 /* This fills the font style list with all the possible style combinations
736 for the current font family. */
738 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
741 PangoFontFace **faces;
742 PangoFontDescription *old_desc;
744 GtkTreeIter match_row;
745 PangoFontFace *match_face = NULL;
747 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list)));
750 old_desc = pango_font_face_describe (fontsel->face);
754 pango_font_family_list_faces (fontsel->family, &faces, &n_faces);
755 qsort (faces, n_faces, sizeof (PangoFontFace *), faces_sort_func);
757 gtk_list_store_clear (model);
759 for (i=0; i < n_faces; i++)
762 const gchar *str = pango_font_face_get_face_name (faces[i]);
764 gtk_list_store_append (model, &iter);
765 gtk_list_store_set (model, &iter,
766 FACE_COLUMN, faces[i],
767 FACE_NAME_COLUMN, str,
773 match_face = faces[i];
777 PangoFontDescription *tmp_desc = pango_font_face_describe (faces[i]);
779 if (font_description_style_equal (tmp_desc, old_desc))
782 match_face = faces[i];
785 pango_font_description_free (tmp_desc);
790 pango_font_description_free (old_desc);
792 fontsel->face = match_face;
795 #ifdef INCLUDE_FONT_ENTRIES
796 const gchar *str = pango_font_face_get_face_name (fontsel->face);
798 gtk_entry_set_text (GTK_ENTRY (fontsel->font_style_entry), str);
800 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_row);
806 /* This selects a style when the user selects a font. It just uses the first
807 available style at present. I was thinking of trying to maintain the
808 selected style, e.g. bold italic, when the user selects different fonts.
809 However, the interface is so easy to use now I'm not sure it's worth it.
810 Note: This will load a font. */
812 gtk_font_selection_select_best_style (GtkFontSelection *fontsel,
818 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
820 if (gtk_tree_model_get_iter_first (model, &iter))
822 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &iter);
823 scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
826 gtk_font_selection_show_available_sizes (fontsel, FALSE);
827 gtk_font_selection_select_best_size (fontsel);
831 /* This is called when a style is selected in the list. */
833 gtk_font_selection_select_style (GtkTreeSelection *selection,
836 GtkFontSelection *fontsel = GTK_FONT_SELECTION (data);
840 if (gtk_tree_selection_get_selected (selection, &model, &iter))
844 gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
845 fontsel->face = face;
847 g_object_unref (face);
850 gtk_font_selection_show_available_sizes (fontsel, FALSE);
851 gtk_font_selection_select_best_size (fontsel);
855 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel,
860 GtkTreeSelection *selection;
864 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->size_list)));
865 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
867 /* Insert the standard font sizes */
870 gtk_list_store_clear (model);
872 for (i = 0; i < G_N_ELEMENTS (font_sizes); i++)
876 gtk_list_store_append (model, &iter);
877 gtk_list_store_set (model, &iter, SIZE_COLUMN, font_sizes[i], -1);
879 if (font_sizes[i] * PANGO_SCALE == fontsel->size)
880 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
886 gboolean found = FALSE;
888 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
889 for (i = 0; i < G_N_ELEMENTS (font_sizes) && !found; i++)
891 if (font_sizes[i] * PANGO_SCALE == fontsel->size)
893 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
897 gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter);
902 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
903 gtk_tree_selection_unselect_all (selection);
907 /* Set the entry to the new size, rounding to 1 digit,
908 * trimming of trailing 0's and a trailing period
910 sprintf (buffer, "%.1f", fontsel->size / (1.0 * PANGO_SCALE));
911 if (strchr (buffer, '.'))
913 p = buffer + strlen (buffer) - 1;
921 /* Compare, to avoid moving the cursor unecessarily */
922 if (strcmp (gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry)), buffer) != 0)
923 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
927 gtk_font_selection_select_best_size (GtkFontSelection *fontsel)
929 gtk_font_selection_load_font (fontsel);
933 gtk_font_selection_set_size (GtkFontSelection *fontsel,
936 if (fontsel->size != new_size)
938 fontsel->size = new_size;
940 gtk_font_selection_show_available_sizes (fontsel, FALSE);
941 gtk_font_selection_load_font (fontsel);
945 /* If the user hits return in the font size entry, we change to the new font
948 gtk_font_selection_size_activate (GtkWidget *w,
951 GtkFontSelection *fontsel;
955 fontsel = GTK_FONT_SELECTION (data);
957 text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
958 new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);
960 gtk_font_selection_set_size (fontsel, new_size);
964 gtk_font_selection_size_focus_out (GtkWidget *w,
965 GdkEventFocus *event,
968 gtk_font_selection_size_activate (w, data);
973 /* This is called when a size is selected in the list. */
975 gtk_font_selection_select_size (GtkTreeSelection *selection,
978 GtkFontSelection *fontsel;
983 fontsel = GTK_FONT_SELECTION (data);
985 if (gtk_tree_selection_get_selected (selection, &model, &iter))
987 gtk_tree_model_get (model, &iter, SIZE_COLUMN, &new_size, -1);
988 gtk_font_selection_set_size (fontsel, new_size * PANGO_SCALE);
993 gtk_font_selection_load_font (GtkFontSelection *fontsel)
996 gdk_font_unref (fontsel->font);
997 fontsel->font = NULL;
999 gtk_font_selection_update_preview (fontsel);
1002 static PangoFontDescription *
1003 gtk_font_selection_get_font_description (GtkFontSelection *fontsel)
1005 PangoFontDescription *font_desc;
1009 font_desc = pango_font_face_describe (fontsel->face);
1010 pango_font_description_set_size (font_desc, fontsel->size);
1013 font_desc = pango_font_description_from_string ("Sans 10");
1018 /* This sets the font in the preview entry to the selected font, and tries to
1019 make sure that the preview entry is a reasonable size, i.e. so that the
1020 text can be seen with a bit of space to spare. But it tries to avoid
1021 resizing the entry every time the font changes.
1022 This also used to shrink the preview if the font size was decreased, but
1023 that made it awkward if the user wanted to resize the window themself. */
1025 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1027 GtkRcStyle *rc_style;
1029 GtkRequisition old_requisition;
1030 GtkWidget *preview_entry = fontsel->preview_entry;
1033 gtk_widget_get_child_requisition (preview_entry, &old_requisition);
1035 rc_style = gtk_rc_style_new ();
1036 rc_style->font_desc = gtk_font_selection_get_font_description (fontsel);
1038 gtk_widget_modify_style (preview_entry, rc_style);
1039 gtk_rc_style_unref (rc_style);
1041 gtk_widget_size_request (preview_entry, NULL);
1043 /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1044 new_height = CLAMP (preview_entry->requisition.height, INITIAL_PREVIEW_HEIGHT, MAX_PREVIEW_HEIGHT);
1046 if (new_height > old_requisition.height || new_height < old_requisition.height - 30)
1047 gtk_widget_set_size_request (preview_entry, -1, new_height);
1049 /* This sets the preview text, if it hasn't been set already. */
1050 text = gtk_entry_get_text (GTK_ENTRY (preview_entry));
1051 if (strlen (text) == 0)
1052 gtk_entry_set_text (GTK_ENTRY (preview_entry), _(PREVIEW_TEXT));
1053 gtk_editable_set_position (GTK_EDITABLE (preview_entry), 0);
1057 gtk_font_selection_get_font_internal (GtkFontSelection *fontsel)
1061 PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1062 fontsel->font = gdk_font_from_description_for_display (gtk_widget_get_display (GTK_WIDGET (fontsel)), font_desc);
1063 pango_font_description_free (font_desc);
1066 return fontsel->font;
1070 /*****************************************************************************
1071 * These functions are the main public interface for getting/setting the font.
1072 *****************************************************************************/
1075 gtk_font_selection_get_font (GtkFontSelection *fontsel)
1077 return gtk_font_selection_get_font_internal (fontsel);
1081 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
1085 PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1086 result = pango_font_description_to_string (font_desc);
1087 pango_font_description_free (font_desc);
1093 /* This sets the current font, selecting the appropriate list rows.
1094 First we check the fontname is valid and try to find the font family
1095 - i.e. the name in the main list. If we can't find that, then just return.
1096 Next we try to set each of the properties according to the fontname.
1097 Finally we select the font family & style in the lists. */
1099 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
1100 const gchar *fontname)
1102 PangoFontFamily *new_family = NULL;
1103 PangoFontFace *new_face = NULL;
1104 PangoFontFace *fallback_face = NULL;
1105 PangoFontDescription *new_desc;
1106 GtkTreeModel *model;
1108 GtkTreeIter match_iter;
1111 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
1113 new_desc = pango_font_description_from_string (fontname);
1115 /* Check to make sure that this is in the list of allowed fonts */
1117 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list));
1118 for (valid = gtk_tree_model_get_iter_first (model, &iter);
1120 valid = gtk_tree_model_iter_next (model, &iter))
1122 PangoFontFamily *family;
1124 gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
1126 if (g_ascii_strcasecmp (pango_font_family_get_name (family),
1127 pango_font_description_get_family (new_desc)) == 0)
1128 new_family = family;
1130 g_object_unref (family);
1139 fontsel->family = new_family;
1140 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &iter);
1141 gtk_font_selection_show_available_styles (fontsel);
1143 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
1144 for (valid = gtk_tree_model_get_iter_first (model, &iter);
1146 valid = gtk_tree_model_iter_next (model, &iter))
1148 PangoFontFace *face;
1149 PangoFontDescription *tmp_desc;
1151 gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
1152 tmp_desc = pango_font_face_describe (face);
1154 if (font_description_style_equal (tmp_desc, new_desc))
1159 fallback_face = face;
1163 pango_font_description_free (tmp_desc);
1164 g_object_unref (face);
1174 new_face = fallback_face;
1176 fontsel->face = new_face;
1177 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_iter);
1179 gtk_font_selection_set_size (fontsel, pango_font_description_get_size (new_desc));
1181 g_object_freeze_notify (G_OBJECT (fontsel));
1182 g_object_notify (G_OBJECT (fontsel), "font_name");
1183 g_object_notify (G_OBJECT (fontsel), "font");
1184 g_object_thaw_notify (G_OBJECT (fontsel));
1186 pango_font_description_free (new_desc);
1192 /* This returns the text in the preview entry. You should copy the returned
1193 text if you need it. */
1194 G_CONST_RETURN gchar*
1195 gtk_font_selection_get_preview_text (GtkFontSelection *fontsel)
1197 return gtk_entry_get_text (GTK_ENTRY (fontsel->preview_entry));
1201 /* This sets the text in the preview entry. */
1203 gtk_font_selection_set_preview_text (GtkFontSelection *fontsel,
1206 gtk_entry_set_text (GTK_ENTRY (fontsel->preview_entry), text);
1209 /*****************************************************************************
1210 * GtkFontSelectionDialog
1211 *****************************************************************************/
1214 gtk_font_selection_dialog_get_type (void)
1216 static GType font_selection_dialog_type = 0;
1218 if (!font_selection_dialog_type)
1220 static const GTypeInfo fontsel_diag_info =
1222 sizeof (GtkFontSelectionDialogClass),
1223 NULL, /* base_init */
1224 NULL, /* base_finalize */
1225 (GClassInitFunc) gtk_font_selection_dialog_class_init,
1226 NULL, /* class_finalize */
1227 NULL, /* class_data */
1228 sizeof (GtkFontSelectionDialog),
1229 0, /* n_preallocs */
1230 (GInstanceInitFunc) gtk_font_selection_dialog_init,
1233 font_selection_dialog_type =
1234 g_type_register_static (GTK_TYPE_DIALOG, "GtkFontSelectionDialog",
1235 &fontsel_diag_info, 0);
1238 return font_selection_dialog_type;
1242 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
1244 font_selection_dialog_parent_class = g_type_class_peek_parent (klass);
1248 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
1252 gtk_widget_push_composite_child ();
1254 dialog = GTK_DIALOG (fontseldiag);
1256 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag), 4);
1257 gtk_window_set_resizable (GTK_WINDOW (fontseldiag), TRUE);
1259 fontseldiag->main_vbox = dialog->vbox;
1261 fontseldiag->fontsel = gtk_font_selection_new ();
1262 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag->fontsel), 4);
1263 gtk_widget_show (fontseldiag->fontsel);
1264 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
1265 fontseldiag->fontsel, TRUE, TRUE, 0);
1267 /* Create the action area */
1268 fontseldiag->action_area = dialog->action_area;
1270 fontseldiag->cancel_button = gtk_dialog_add_button (dialog,
1272 GTK_RESPONSE_CANCEL);
1274 fontseldiag->apply_button = gtk_dialog_add_button (dialog,
1276 GTK_RESPONSE_APPLY);
1277 gtk_widget_hide (fontseldiag->apply_button);
1279 fontseldiag->ok_button = gtk_dialog_add_button (dialog,
1282 gtk_widget_grab_default (fontseldiag->ok_button);
1284 gtk_window_set_title (GTK_WINDOW (fontseldiag),
1285 _("Font Selection"));
1287 gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
1289 gtk_widget_pop_composite_child ();
1293 gtk_font_selection_dialog_new (const gchar *title)
1295 GtkFontSelectionDialog *fontseldiag;
1297 fontseldiag = g_object_new (GTK_TYPE_FONT_SELECTION_DIALOG, NULL);
1300 gtk_window_set_title (GTK_WINDOW (fontseldiag), title);
1302 return GTK_WIDGET (fontseldiag);
1306 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
1308 return gtk_font_selection_get_font_name (GTK_FONT_SELECTION (fsd->fontsel));
1312 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
1314 return gtk_font_selection_get_font (GTK_FONT_SELECTION (fsd->fontsel));
1318 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
1319 const gchar *fontname)
1321 return gtk_font_selection_set_font_name (GTK_FONT_SELECTION (fsd->fontsel), fontname);
1324 G_CONST_RETURN gchar*
1325 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
1327 return gtk_font_selection_get_preview_text (GTK_FONT_SELECTION (fsd->fontsel));
1331 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
1334 gtk_font_selection_set_preview_text (GTK_FONT_SELECTION (fsd->fontsel), text);