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);
282 /* Handles key press events on the lists, so that we can trap Enter to
283 * activate the default button on our own.
286 list_row_activated (GtkWidget *widget)
290 window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget)));
291 if (!GTK_WIDGET_TOPLEVEL (window))
295 && widget != window->default_widget
296 && !(widget == window->focus_widget &&
297 (!window->default_widget || !GTK_WIDGET_SENSITIVE (window->default_widget))))
299 gtk_window_activate_default (window);
306 gtk_font_selection_init (GtkFontSelection *fontsel)
308 GtkWidget *scrolled_win;
309 GtkWidget *text_frame;
311 GtkWidget *table, *label;
312 GtkWidget *font_label, *style_label;
314 GtkTreeViewColumn *column;
315 GList *focus_chain = NULL;
317 gtk_widget_push_composite_child ();
319 fontsel->size = 12 * PANGO_SCALE;
321 /* Create the table of font, style & size. */
322 table = gtk_table_new (3, 3, FALSE);
323 gtk_widget_show (table);
324 gtk_table_set_col_spacings (GTK_TABLE (table), 8);
325 gtk_box_pack_start (GTK_BOX (fontsel), table, TRUE, TRUE, 0);
327 #ifdef INCLUDE_FONT_ENTRIES
328 fontsel->font_entry = gtk_entry_new ();
329 gtk_editable_set_editable (GTK_EDITABLE (fontsel->font_entry), FALSE);
330 gtk_widget_set_size_request (fontsel->font_entry, 20, -1);
331 gtk_widget_show (fontsel->font_entry);
332 gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
335 fontsel->font_style_entry = gtk_entry_new ();
336 gtk_editable_set_editable (GTK_EDITABLE (fontsel->font_style_entry), FALSE);
337 gtk_widget_set_size_request (fontsel->font_style_entry, 20, -1);
338 gtk_widget_show (fontsel->font_style_entry);
339 gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
341 #endif /* INCLUDE_FONT_ENTRIES */
343 fontsel->size_entry = gtk_entry_new ();
344 gtk_widget_set_size_request (fontsel->size_entry, 20, -1);
345 gtk_widget_show (fontsel->size_entry);
346 gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
348 g_signal_connect (fontsel->size_entry, "activate",
349 G_CALLBACK (gtk_font_selection_size_activate),
351 g_signal_connect_after (fontsel->size_entry, "focus_out_event",
352 G_CALLBACK (gtk_font_selection_size_focus_out),
355 font_label = gtk_label_new_with_mnemonic (_("_Family:"));
356 gtk_misc_set_alignment (GTK_MISC (font_label), 0.0, 0.5);
357 gtk_widget_show (font_label);
358 gtk_table_attach (GTK_TABLE (table), font_label, 0, 1, 0, 1,
361 style_label = gtk_label_new_with_mnemonic (_("_Style:"));
362 gtk_misc_set_alignment (GTK_MISC (style_label), 0.0, 0.5);
363 gtk_widget_show (style_label);
364 gtk_table_attach (GTK_TABLE (table), style_label, 1, 2, 0, 1,
367 label = gtk_label_new_with_mnemonic (_("Si_ze:"));
368 gtk_label_set_mnemonic_widget (GTK_LABEL (label),
369 fontsel->size_entry);
370 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
371 gtk_widget_show (label);
372 gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
376 /* Create the lists */
378 model = gtk_list_store_new (2,
379 G_TYPE_OBJECT, /* FAMILY_COLUMN */
380 G_TYPE_STRING); /* FAMILY_NAME_COLUMN */
381 fontsel->family_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
382 g_object_unref (model);
384 g_signal_connect (fontsel->family_list, "row-activated",
385 G_CALLBACK (list_row_activated), fontsel);
387 column = gtk_tree_view_column_new_with_attributes ("Family",
388 gtk_cell_renderer_text_new (),
389 "text", FAMILY_NAME_COLUMN,
391 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
392 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->family_list), column);
394 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->family_list), FALSE);
395 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)),
396 GTK_SELECTION_BROWSE);
398 gtk_label_set_mnemonic_widget (GTK_LABEL (font_label), fontsel->family_list);
400 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
401 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
402 gtk_widget_set_size_request (scrolled_win,
403 FONT_LIST_WIDTH, FONT_LIST_HEIGHT);
404 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->family_list);
405 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
406 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
407 gtk_widget_show (fontsel->family_list);
408 gtk_widget_show (scrolled_win);
410 gtk_table_attach (GTK_TABLE (table), scrolled_win, 0, 1, 1, 3,
411 GTK_EXPAND | GTK_FILL,
412 GTK_EXPAND | GTK_FILL, 0, 0);
413 focus_chain = g_list_append (focus_chain, scrolled_win);
415 model = gtk_list_store_new (2,
416 G_TYPE_OBJECT, /* FACE_COLUMN */
417 G_TYPE_STRING); /* FACE_NAME_COLUMN */
418 fontsel->face_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
419 g_object_unref (model);
420 g_signal_connect (fontsel->face_list, "row-activated",
421 G_CALLBACK (list_row_activated), fontsel);
423 gtk_label_set_mnemonic_widget (GTK_LABEL (style_label), fontsel->face_list);
425 column = gtk_tree_view_column_new_with_attributes ("Face",
426 gtk_cell_renderer_text_new (),
427 "text", FACE_NAME_COLUMN,
429 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
430 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->face_list), column);
432 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->face_list), FALSE);
433 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)),
434 GTK_SELECTION_BROWSE);
436 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
437 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
438 gtk_widget_set_size_request (scrolled_win,
439 FONT_STYLE_LIST_WIDTH, FONT_LIST_HEIGHT);
440 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->face_list);
441 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
442 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
443 gtk_widget_show (fontsel->face_list);
444 gtk_widget_show (scrolled_win);
445 gtk_table_attach (GTK_TABLE (table), scrolled_win, 1, 2, 1, 3,
446 GTK_EXPAND | GTK_FILL,
447 GTK_EXPAND | GTK_FILL, 0, 0);
448 focus_chain = g_list_append (focus_chain, scrolled_win);
450 focus_chain = g_list_append (focus_chain, fontsel->size_entry);
452 model = gtk_list_store_new (1, G_TYPE_INT);
453 fontsel->size_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
454 g_object_unref (model);
455 g_signal_connect (fontsel->size_list, "row-activated",
456 G_CALLBACK (list_row_activated), fontsel);
458 column = gtk_tree_view_column_new_with_attributes ("Size",
459 gtk_cell_renderer_text_new (),
462 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
463 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->size_list), column);
465 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->size_list), FALSE);
466 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)),
467 GTK_SELECTION_BROWSE);
469 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
470 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
471 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->size_list);
472 gtk_widget_set_size_request (scrolled_win, -1, FONT_LIST_HEIGHT);
473 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
474 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
475 gtk_widget_show (fontsel->size_list);
476 gtk_widget_show (scrolled_win);
477 gtk_table_attach (GTK_TABLE (table), scrolled_win, 2, 3, 2, 3,
478 GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
479 focus_chain = g_list_append (focus_chain, scrolled_win);
481 gtk_container_set_focus_chain (GTK_CONTAINER (table), focus_chain);
482 g_list_free (focus_chain);
484 /* Insert the fonts. */
485 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)), "changed",
486 G_CALLBACK (gtk_font_selection_select_font), fontsel);
488 g_signal_connect_after (fontsel->family_list, "map",
489 G_CALLBACK (gtk_font_selection_scroll_on_map),
492 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)), "changed",
493 G_CALLBACK (gtk_font_selection_select_style), fontsel);
495 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)), "changed",
496 G_CALLBACK (gtk_font_selection_select_size), fontsel);
498 /* create the text entry widget */
499 label = gtk_label_new_with_mnemonic (_("_Preview:"));
500 gtk_widget_show (label);
502 text_frame = gtk_frame_new (NULL);
503 gtk_frame_set_label_widget (GTK_FRAME (text_frame), label);
505 gtk_widget_show (text_frame);
506 gtk_frame_set_shadow_type (GTK_FRAME (text_frame), GTK_SHADOW_ETCHED_IN);
507 gtk_box_pack_start (GTK_BOX (fontsel), text_frame,
510 /* This is just used to get a 4-pixel space around the preview entry. */
511 text_box = gtk_hbox_new (FALSE, 0);
512 gtk_widget_show (text_box);
513 gtk_container_add (GTK_CONTAINER (text_frame), text_box);
514 gtk_container_set_border_width (GTK_CONTAINER (text_box), 4);
516 fontsel->preview_entry = gtk_entry_new ();
517 gtk_label_set_mnemonic_widget (GTK_LABEL (label), fontsel->preview_entry);
519 gtk_widget_show (fontsel->preview_entry);
520 g_signal_connect (fontsel->preview_entry, "changed",
521 G_CALLBACK (gtk_font_selection_preview_changed), fontsel);
522 gtk_widget_set_size_request (fontsel->preview_entry,
523 -1, INITIAL_PREVIEW_HEIGHT);
524 gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
527 gtk_widget_pop_composite_child();
531 gtk_font_selection_new ()
533 GtkFontSelection *fontsel;
535 fontsel = g_object_new (GTK_TYPE_FONT_SELECTION, NULL);
537 return GTK_WIDGET (fontsel);
541 gtk_font_selection_finalize (GObject *object)
543 GtkFontSelection *fontsel;
545 g_return_if_fail (GTK_IS_FONT_SELECTION (object));
547 fontsel = GTK_FONT_SELECTION (object);
550 gdk_font_unref (fontsel->font);
552 if (G_OBJECT_CLASS (font_selection_parent_class)->finalize)
553 (* G_OBJECT_CLASS (font_selection_parent_class)->finalize) (object);
557 gtk_font_selection_screen_changed (GtkWidget *widget,
558 GdkScreen *previous_screen)
560 GtkFontSelection *fontsel = GTK_FONT_SELECTION (widget);
562 if (gtk_widget_has_screen (GTK_WIDGET (fontsel)))
564 gtk_font_selection_show_available_fonts (fontsel);
565 gtk_font_selection_show_available_sizes (fontsel, TRUE);
566 gtk_font_selection_show_available_styles (fontsel);
571 gtk_font_selection_preview_changed (GtkWidget *entry,
572 GtkFontSelection *fontsel)
574 g_object_notify (G_OBJECT (fontsel), "preview_text");
578 scroll_to_selection (GtkTreeView *tree_view)
580 GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
584 if (gtk_tree_selection_get_selected (selection, &model, &iter))
586 GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
587 gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.5);
588 gtk_tree_path_free (path);
593 set_cursor_to_iter (GtkTreeView *view,
596 GtkTreeModel *model = gtk_tree_view_get_model (view);
597 GtkTreePath *path = gtk_tree_model_get_path (model, iter);
599 gtk_tree_view_set_cursor (view, path, 0, FALSE);
601 gtk_tree_path_free (path);
604 /* This is called when the list is mapped. Here we scroll to the current
605 font if necessary. */
607 gtk_font_selection_scroll_on_map (GtkWidget *widget,
610 GtkFontSelection *fontsel;
613 g_message ("In expose_list\n");
615 fontsel = GTK_FONT_SELECTION (data);
617 /* Try to scroll the font family list to the selected item */
618 scroll_to_selection (GTK_TREE_VIEW (fontsel->family_list));
620 /* Try to scroll the font family list to the selected item */
621 scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
623 /* Try to scroll the font family list to the selected item */
624 scroll_to_selection (GTK_TREE_VIEW (fontsel->size_list));
627 /* This is called when a family is selected in the list. */
629 gtk_font_selection_select_font (GtkTreeSelection *selection,
632 GtkFontSelection *fontsel;
635 const gchar *family_name;
637 fontsel = GTK_FONT_SELECTION (data);
639 if (gtk_tree_selection_get_selected (selection, &model, &iter))
641 PangoFontFamily *family;
643 gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
644 if (fontsel->family != family)
646 fontsel->family = family;
648 family_name = pango_font_family_get_name (fontsel->family);
650 #ifdef INCLUDE_FONT_ENTRIES
651 gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), family_name);
654 gtk_font_selection_show_available_styles (fontsel);
655 gtk_font_selection_select_best_style (fontsel, TRUE);
658 g_object_unref (family);
663 cmp_families (const void *a, const void *b)
665 const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a);
666 const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b);
668 return g_utf8_collate (a_name, b_name);
672 gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
675 PangoFontFamily **families;
676 PangoFontFamily *match_family = NULL;
678 GtkTreeIter match_row;
680 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list)));
682 pango_context_list_families (gtk_widget_get_pango_context (GTK_WIDGET (fontsel)),
683 &families, &n_families);
684 qsort (families, n_families, sizeof (PangoFontFamily *), cmp_families);
686 gtk_list_store_clear (model);
688 for (i=0; i<n_families; i++)
690 const gchar *name = pango_font_family_get_name (families[i]);
693 gtk_list_store_append (model, &iter);
694 gtk_list_store_set (model, &iter,
695 FAMILY_COLUMN, families[i],
696 FAMILY_NAME_COLUMN, name,
699 if (i == 0 || !g_ascii_strcasecmp (name, "sans"))
701 match_family = families[i];
706 fontsel->family = match_family;
709 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &match_row);
710 #ifdef INCLUDE_FONT_ENTRIES
711 gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry),
712 pango_font_family_get_name (match_family));
713 #endif /* INCLUDE_FONT_ENTRIES */
720 compare_font_descriptions (const PangoFontDescription *a, const PangoFontDescription *b)
722 int val = strcmp (pango_font_description_get_family (a), pango_font_description_get_family (b));
726 if (pango_font_description_get_weight (a) != pango_font_description_get_weight (b))
727 return pango_font_description_get_weight (a) - pango_font_description_get_weight (b);
729 if (pango_font_description_get_style (a) != pango_font_description_get_style (b))
730 return pango_font_description_get_style (a) - pango_font_description_get_style (b);
732 if (pango_font_description_get_stretch (a) != pango_font_description_get_stretch (b))
733 return pango_font_description_get_stretch (a) - pango_font_description_get_stretch (b);
735 if (pango_font_description_get_variant (a) != pango_font_description_get_variant (b))
736 return pango_font_description_get_variant (a) - pango_font_description_get_variant (b);
742 faces_sort_func (const void *a, const void *b)
744 PangoFontDescription *desc_a = pango_font_face_describe (*(PangoFontFace **)a);
745 PangoFontDescription *desc_b = pango_font_face_describe (*(PangoFontFace **)b);
747 int ord = compare_font_descriptions (desc_a, desc_b);
749 pango_font_description_free (desc_a);
750 pango_font_description_free (desc_b);
756 font_description_style_equal (const PangoFontDescription *a,
757 const PangoFontDescription *b)
759 return (pango_font_description_get_weight (a) == pango_font_description_get_weight (b) &&
760 pango_font_description_get_style (a) == pango_font_description_get_style (b) &&
761 pango_font_description_get_stretch (a) == pango_font_description_get_stretch (b) &&
762 pango_font_description_get_variant (a) == pango_font_description_get_variant (b));
765 /* This fills the font style list with all the possible style combinations
766 for the current font family. */
768 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
771 PangoFontFace **faces;
772 PangoFontDescription *old_desc;
774 GtkTreeIter match_row;
775 PangoFontFace *match_face = NULL;
777 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list)));
780 old_desc = pango_font_face_describe (fontsel->face);
784 pango_font_family_list_faces (fontsel->family, &faces, &n_faces);
785 qsort (faces, n_faces, sizeof (PangoFontFace *), faces_sort_func);
787 gtk_list_store_clear (model);
789 for (i=0; i < n_faces; i++)
792 const gchar *str = pango_font_face_get_face_name (faces[i]);
794 gtk_list_store_append (model, &iter);
795 gtk_list_store_set (model, &iter,
796 FACE_COLUMN, faces[i],
797 FACE_NAME_COLUMN, str,
803 match_face = faces[i];
807 PangoFontDescription *tmp_desc = pango_font_face_describe (faces[i]);
809 if (font_description_style_equal (tmp_desc, old_desc))
812 match_face = faces[i];
815 pango_font_description_free (tmp_desc);
820 pango_font_description_free (old_desc);
822 fontsel->face = match_face;
825 #ifdef INCLUDE_FONT_ENTRIES
826 const gchar *str = pango_font_face_get_face_name (fontsel->face);
828 gtk_entry_set_text (GTK_ENTRY (fontsel->font_style_entry), str);
830 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_row);
836 /* This selects a style when the user selects a font. It just uses the first
837 available style at present. I was thinking of trying to maintain the
838 selected style, e.g. bold italic, when the user selects different fonts.
839 However, the interface is so easy to use now I'm not sure it's worth it.
840 Note: This will load a font. */
842 gtk_font_selection_select_best_style (GtkFontSelection *fontsel,
848 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
850 if (gtk_tree_model_get_iter_first (model, &iter))
852 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &iter);
853 scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
856 gtk_font_selection_show_available_sizes (fontsel, FALSE);
857 gtk_font_selection_select_best_size (fontsel);
861 /* This is called when a style is selected in the list. */
863 gtk_font_selection_select_style (GtkTreeSelection *selection,
866 GtkFontSelection *fontsel = GTK_FONT_SELECTION (data);
870 if (gtk_tree_selection_get_selected (selection, &model, &iter))
874 gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
875 fontsel->face = face;
877 g_object_unref (face);
880 gtk_font_selection_show_available_sizes (fontsel, FALSE);
881 gtk_font_selection_select_best_size (fontsel);
885 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel,
890 GtkTreeSelection *selection;
894 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->size_list)));
895 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
897 /* Insert the standard font sizes */
900 gtk_list_store_clear (model);
902 for (i = 0; i < G_N_ELEMENTS (font_sizes); i++)
906 gtk_list_store_append (model, &iter);
907 gtk_list_store_set (model, &iter, SIZE_COLUMN, font_sizes[i], -1);
909 if (font_sizes[i] * PANGO_SCALE == fontsel->size)
910 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
916 gboolean found = FALSE;
918 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
919 for (i = 0; i < G_N_ELEMENTS (font_sizes) && !found; i++)
921 if (font_sizes[i] * PANGO_SCALE == fontsel->size)
923 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
927 gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter);
932 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
933 gtk_tree_selection_unselect_all (selection);
937 /* Set the entry to the new size, rounding to 1 digit,
938 * trimming of trailing 0's and a trailing period
940 g_snprintf (buffer, sizeof (buffer), "%.1f", fontsel->size / (1.0 * PANGO_SCALE));
941 if (strchr (buffer, '.'))
943 p = buffer + strlen (buffer) - 1;
951 /* Compare, to avoid moving the cursor unecessarily */
952 if (strcmp (gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry)), buffer) != 0)
953 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
957 gtk_font_selection_select_best_size (GtkFontSelection *fontsel)
959 gtk_font_selection_load_font (fontsel);
963 gtk_font_selection_set_size (GtkFontSelection *fontsel,
966 if (fontsel->size != new_size)
968 fontsel->size = new_size;
970 gtk_font_selection_show_available_sizes (fontsel, FALSE);
971 gtk_font_selection_load_font (fontsel);
975 /* If the user hits return in the font size entry, we change to the new font
978 gtk_font_selection_size_activate (GtkWidget *w,
981 GtkFontSelection *fontsel;
985 fontsel = GTK_FONT_SELECTION (data);
987 text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
988 new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);
990 if (fontsel->size != new_size)
991 gtk_font_selection_set_size (fontsel, new_size);
993 list_row_activated (w);
997 gtk_font_selection_size_focus_out (GtkWidget *w,
998 GdkEventFocus *event,
1001 gtk_font_selection_size_activate (w, data);
1006 /* This is called when a size is selected in the list. */
1008 gtk_font_selection_select_size (GtkTreeSelection *selection,
1011 GtkFontSelection *fontsel;
1012 GtkTreeModel *model;
1016 fontsel = GTK_FONT_SELECTION (data);
1018 if (gtk_tree_selection_get_selected (selection, &model, &iter))
1020 gtk_tree_model_get (model, &iter, SIZE_COLUMN, &new_size, -1);
1021 gtk_font_selection_set_size (fontsel, new_size * PANGO_SCALE);
1026 gtk_font_selection_load_font (GtkFontSelection *fontsel)
1029 gdk_font_unref (fontsel->font);
1030 fontsel->font = NULL;
1032 gtk_font_selection_update_preview (fontsel);
1035 static PangoFontDescription *
1036 gtk_font_selection_get_font_description (GtkFontSelection *fontsel)
1038 PangoFontDescription *font_desc;
1042 font_desc = pango_font_face_describe (fontsel->face);
1043 pango_font_description_set_size (font_desc, fontsel->size);
1046 font_desc = pango_font_description_from_string ("Sans 10");
1051 /* This sets the font in the preview entry to the selected font, and tries to
1052 make sure that the preview entry is a reasonable size, i.e. so that the
1053 text can be seen with a bit of space to spare. But it tries to avoid
1054 resizing the entry every time the font changes.
1055 This also used to shrink the preview if the font size was decreased, but
1056 that made it awkward if the user wanted to resize the window themself. */
1058 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1060 GtkRcStyle *rc_style;
1062 GtkRequisition old_requisition;
1063 GtkWidget *preview_entry = fontsel->preview_entry;
1066 gtk_widget_get_child_requisition (preview_entry, &old_requisition);
1068 rc_style = gtk_rc_style_new ();
1069 rc_style->font_desc = gtk_font_selection_get_font_description (fontsel);
1071 gtk_widget_modify_style (preview_entry, rc_style);
1072 gtk_rc_style_unref (rc_style);
1074 gtk_widget_size_request (preview_entry, NULL);
1076 /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1077 new_height = CLAMP (preview_entry->requisition.height, INITIAL_PREVIEW_HEIGHT, MAX_PREVIEW_HEIGHT);
1079 if (new_height > old_requisition.height || new_height < old_requisition.height - 30)
1080 gtk_widget_set_size_request (preview_entry, -1, new_height);
1082 /* This sets the preview text, if it hasn't been set already. */
1083 text = gtk_entry_get_text (GTK_ENTRY (preview_entry));
1084 if (strlen (text) == 0)
1085 gtk_entry_set_text (GTK_ENTRY (preview_entry), _(PREVIEW_TEXT));
1086 gtk_editable_set_position (GTK_EDITABLE (preview_entry), 0);
1090 gtk_font_selection_get_font_internal (GtkFontSelection *fontsel)
1094 PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1095 fontsel->font = gdk_font_from_description_for_display (gtk_widget_get_display (GTK_WIDGET (fontsel)), font_desc);
1096 pango_font_description_free (font_desc);
1099 return fontsel->font;
1103 /*****************************************************************************
1104 * These functions are the main public interface for getting/setting the font.
1105 *****************************************************************************/
1108 gtk_font_selection_get_font (GtkFontSelection *fontsel)
1110 return gtk_font_selection_get_font_internal (fontsel);
1114 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
1118 PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1119 result = pango_font_description_to_string (font_desc);
1120 pango_font_description_free (font_desc);
1126 /* This sets the current font, selecting the appropriate list rows.
1127 First we check the fontname is valid and try to find the font family
1128 - i.e. the name in the main list. If we can't find that, then just return.
1129 Next we try to set each of the properties according to the fontname.
1130 Finally we select the font family & style in the lists. */
1132 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
1133 const gchar *fontname)
1135 PangoFontFamily *new_family = NULL;
1136 PangoFontFace *new_face = NULL;
1137 PangoFontFace *fallback_face = NULL;
1138 PangoFontDescription *new_desc;
1139 GtkTreeModel *model;
1141 GtkTreeIter match_iter;
1144 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
1146 new_desc = pango_font_description_from_string (fontname);
1148 /* Check to make sure that this is in the list of allowed fonts */
1150 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list));
1151 for (valid = gtk_tree_model_get_iter_first (model, &iter);
1153 valid = gtk_tree_model_iter_next (model, &iter))
1155 PangoFontFamily *family;
1157 gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
1159 if (g_ascii_strcasecmp (pango_font_family_get_name (family),
1160 pango_font_description_get_family (new_desc)) == 0)
1161 new_family = family;
1163 g_object_unref (family);
1172 fontsel->family = new_family;
1173 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &iter);
1174 gtk_font_selection_show_available_styles (fontsel);
1176 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
1177 for (valid = gtk_tree_model_get_iter_first (model, &iter);
1179 valid = gtk_tree_model_iter_next (model, &iter))
1181 PangoFontFace *face;
1182 PangoFontDescription *tmp_desc;
1184 gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
1185 tmp_desc = pango_font_face_describe (face);
1187 if (font_description_style_equal (tmp_desc, new_desc))
1192 fallback_face = face;
1196 pango_font_description_free (tmp_desc);
1197 g_object_unref (face);
1207 new_face = fallback_face;
1209 fontsel->face = new_face;
1210 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_iter);
1212 gtk_font_selection_set_size (fontsel, pango_font_description_get_size (new_desc));
1214 g_object_freeze_notify (G_OBJECT (fontsel));
1215 g_object_notify (G_OBJECT (fontsel), "font_name");
1216 g_object_notify (G_OBJECT (fontsel), "font");
1217 g_object_thaw_notify (G_OBJECT (fontsel));
1219 pango_font_description_free (new_desc);
1225 /* This returns the text in the preview entry. You should copy the returned
1226 text if you need it. */
1227 G_CONST_RETURN gchar*
1228 gtk_font_selection_get_preview_text (GtkFontSelection *fontsel)
1230 return gtk_entry_get_text (GTK_ENTRY (fontsel->preview_entry));
1234 /* This sets the text in the preview entry. */
1236 gtk_font_selection_set_preview_text (GtkFontSelection *fontsel,
1239 gtk_entry_set_text (GTK_ENTRY (fontsel->preview_entry), text);
1242 /*****************************************************************************
1243 * GtkFontSelectionDialog
1244 *****************************************************************************/
1247 gtk_font_selection_dialog_get_type (void)
1249 static GType font_selection_dialog_type = 0;
1251 if (!font_selection_dialog_type)
1253 static const GTypeInfo fontsel_diag_info =
1255 sizeof (GtkFontSelectionDialogClass),
1256 NULL, /* base_init */
1257 NULL, /* base_finalize */
1258 (GClassInitFunc) gtk_font_selection_dialog_class_init,
1259 NULL, /* class_finalize */
1260 NULL, /* class_data */
1261 sizeof (GtkFontSelectionDialog),
1262 0, /* n_preallocs */
1263 (GInstanceInitFunc) gtk_font_selection_dialog_init,
1266 font_selection_dialog_type =
1267 g_type_register_static (GTK_TYPE_DIALOG, "GtkFontSelectionDialog",
1268 &fontsel_diag_info, 0);
1271 return font_selection_dialog_type;
1275 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
1277 font_selection_dialog_parent_class = g_type_class_peek_parent (klass);
1281 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
1285 gtk_widget_push_composite_child ();
1287 dialog = GTK_DIALOG (fontseldiag);
1289 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag), 4);
1290 gtk_window_set_resizable (GTK_WINDOW (fontseldiag), TRUE);
1292 fontseldiag->main_vbox = dialog->vbox;
1294 fontseldiag->fontsel = gtk_font_selection_new ();
1295 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag->fontsel), 4);
1296 gtk_widget_show (fontseldiag->fontsel);
1297 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
1298 fontseldiag->fontsel, TRUE, TRUE, 0);
1300 /* Create the action area */
1301 fontseldiag->action_area = dialog->action_area;
1303 fontseldiag->cancel_button = gtk_dialog_add_button (dialog,
1305 GTK_RESPONSE_CANCEL);
1307 fontseldiag->apply_button = gtk_dialog_add_button (dialog,
1309 GTK_RESPONSE_APPLY);
1310 gtk_widget_hide (fontseldiag->apply_button);
1312 fontseldiag->ok_button = gtk_dialog_add_button (dialog,
1315 gtk_widget_grab_default (fontseldiag->ok_button);
1317 gtk_window_set_title (GTK_WINDOW (fontseldiag),
1318 _("Font Selection"));
1320 gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
1322 gtk_widget_pop_composite_child ();
1326 gtk_font_selection_dialog_new (const gchar *title)
1328 GtkFontSelectionDialog *fontseldiag;
1330 fontseldiag = g_object_new (GTK_TYPE_FONT_SELECTION_DIALOG, NULL);
1333 gtk_window_set_title (GTK_WINDOW (fontseldiag), title);
1335 return GTK_WIDGET (fontseldiag);
1339 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
1341 return gtk_font_selection_get_font_name (GTK_FONT_SELECTION (fsd->fontsel));
1345 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
1347 return gtk_font_selection_get_font (GTK_FONT_SELECTION (fsd->fontsel));
1351 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
1352 const gchar *fontname)
1354 return gtk_font_selection_set_font_name (GTK_FONT_SELECTION (fsd->fontsel), fontname);
1357 G_CONST_RETURN gchar*
1358 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
1360 return gtk_font_selection_get_preview_text (GTK_FONT_SELECTION (fsd->fontsel));
1364 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
1367 gtk_font_selection_set_preview_text (GTK_FONT_SELECTION (fsd->fontsel), text);