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_hierarchy_changed (GtkWidget *widget,
122 GtkWidget *previous_toplevel);
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 /* FontSelectionDialog */
157 static void gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass);
158 static void gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag);
160 static GtkVBoxClass *font_selection_parent_class = NULL;
161 static GtkWindowClass *font_selection_dialog_parent_class = NULL;
165 gtk_font_selection_get_type (void)
167 static GType font_selection_type = 0;
169 if (!font_selection_type)
171 static const GTypeInfo fontsel_type_info =
173 sizeof (GtkFontSelectionClass),
174 NULL, /* base_init */
175 NULL, /* base_finalize */
176 (GClassInitFunc) gtk_font_selection_class_init,
177 NULL, /* class_finalize */
178 NULL, /* class_data */
179 sizeof (GtkFontSelection),
181 (GInstanceInitFunc) gtk_font_selection_init,
184 font_selection_type =
185 g_type_register_static (GTK_TYPE_VBOX, "GtkFontSelection",
186 &fontsel_type_info, 0);
189 return font_selection_type;
193 gtk_font_selection_class_init (GtkFontSelectionClass *klass)
195 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
196 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
198 font_selection_parent_class = g_type_class_peek_parent (klass);
200 gobject_class->set_property = gtk_font_selection_set_property;
201 gobject_class->get_property = gtk_font_selection_get_property;
203 widget_class->hierarchy_changed = gtk_font_selection_hierarchy_changed;
205 g_object_class_install_property (gobject_class,
207 g_param_spec_string ("font_name",
209 _("The X string that represents this font"),
212 g_object_class_install_property (gobject_class,
214 g_param_spec_boxed ("font",
216 _("The GdkFont that is currently selected"),
219 g_object_class_install_property (gobject_class,
221 g_param_spec_string ("preview_text",
223 _("The text to display in order to demonstrate the selected font"),
226 gobject_class->finalize = gtk_font_selection_finalize;
230 gtk_font_selection_set_property (GObject *object,
235 GtkFontSelection *fontsel;
237 fontsel = GTK_FONT_SELECTION (object);
242 gtk_font_selection_set_font_name (fontsel, g_value_get_string (value));
244 case PROP_PREVIEW_TEXT:
245 gtk_font_selection_set_preview_text (fontsel, g_value_get_string (value));
248 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
253 static void gtk_font_selection_get_property (GObject *object,
258 GtkFontSelection *fontsel;
260 fontsel = GTK_FONT_SELECTION (object);
265 g_value_set_string (value, gtk_font_selection_get_font_name (fontsel));
268 g_value_set_object (value, gtk_font_selection_get_font (fontsel));
270 case PROP_PREVIEW_TEXT:
271 g_value_set_string (value, gtk_font_selection_get_preview_text (fontsel));
274 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
281 gtk_font_selection_init (GtkFontSelection *fontsel)
283 GtkWidget *scrolled_win;
284 GtkWidget *text_frame;
286 GtkWidget *table, *label;
287 GtkWidget *font_label, *style_label;
289 GtkTreeViewColumn *column;
290 GList *focus_chain = NULL;
292 gtk_widget_push_composite_child ();
294 fontsel->size = 12 * PANGO_SCALE;
296 /* Create the table of font, style & size. */
297 table = gtk_table_new (3, 3, FALSE);
298 gtk_widget_show (table);
299 gtk_table_set_col_spacings (GTK_TABLE (table), 8);
300 gtk_box_pack_start (GTK_BOX (fontsel), table, TRUE, TRUE, 0);
302 #ifdef INCLUDE_FONT_ENTRIES
303 fontsel->font_entry = gtk_entry_new ();
304 gtk_editable_set_editable (GTK_EDITABLE (fontsel->font_entry), FALSE);
305 gtk_widget_set_size_request (fontsel->font_entry, 20, -1);
306 gtk_widget_show (fontsel->font_entry);
307 gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
310 fontsel->font_style_entry = gtk_entry_new ();
311 gtk_editable_set_editable (GTK_EDITABLE (fontsel->font_style_entry), FALSE);
312 gtk_widget_set_size_request (fontsel->font_style_entry, 20, -1);
313 gtk_widget_show (fontsel->font_style_entry);
314 gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
316 #endif /* INCLUDE_FONT_ENTRIES */
318 fontsel->size_entry = gtk_entry_new ();
319 gtk_widget_set_size_request (fontsel->size_entry, 20, -1);
320 gtk_widget_show (fontsel->size_entry);
321 gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
323 g_signal_connect (fontsel->size_entry, "activate",
324 G_CALLBACK (gtk_font_selection_size_activate),
326 g_signal_connect_after (fontsel->size_entry, "focus_out_event",
327 G_CALLBACK (gtk_font_selection_size_focus_out),
330 font_label = gtk_label_new_with_mnemonic (_("_Family:"));
331 gtk_misc_set_alignment (GTK_MISC (font_label), 0.0, 0.5);
332 gtk_widget_show (font_label);
333 gtk_table_attach (GTK_TABLE (table), font_label, 0, 1, 0, 1,
336 style_label = gtk_label_new_with_mnemonic (_("_Style:"));
337 gtk_misc_set_alignment (GTK_MISC (style_label), 0.0, 0.5);
338 gtk_widget_show (style_label);
339 gtk_table_attach (GTK_TABLE (table), style_label, 1, 2, 0, 1,
342 label = gtk_label_new_with_mnemonic (_("Si_ze:"));
343 gtk_label_set_mnemonic_widget (GTK_LABEL (label),
344 fontsel->size_entry);
345 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
346 gtk_widget_show (label);
347 gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
351 /* Create the lists */
353 model = gtk_list_store_new (2,
354 G_TYPE_OBJECT, /* FAMILY_COLUMN */
355 G_TYPE_STRING); /* FAMILY_NAME_COLUMN */
356 fontsel->family_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
357 g_object_unref (model);
359 column = gtk_tree_view_column_new_with_attributes ("Family",
360 gtk_cell_renderer_text_new (),
361 "text", FAMILY_NAME_COLUMN,
363 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
364 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->family_list), column);
366 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->family_list), FALSE);
367 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)),
368 GTK_SELECTION_BROWSE);
370 gtk_label_set_mnemonic_widget (GTK_LABEL (font_label), fontsel->family_list);
372 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
373 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
374 gtk_widget_set_size_request (scrolled_win,
375 FONT_LIST_WIDTH, FONT_LIST_HEIGHT);
376 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->family_list);
377 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
378 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
379 gtk_widget_show (fontsel->family_list);
380 gtk_widget_show (scrolled_win);
382 gtk_table_attach (GTK_TABLE (table), scrolled_win, 0, 1, 1, 3,
383 GTK_EXPAND | GTK_FILL,
384 GTK_EXPAND | GTK_FILL, 0, 0);
385 focus_chain = g_list_append (focus_chain, scrolled_win);
387 model = gtk_list_store_new (2,
388 G_TYPE_OBJECT, /* FACE_COLUMN */
389 G_TYPE_STRING); /* FACE_NAME_COLUMN */
390 fontsel->face_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
391 g_object_unref (model);
393 gtk_label_set_mnemonic_widget (GTK_LABEL (style_label), fontsel->face_list);
395 column = gtk_tree_view_column_new_with_attributes ("Face",
396 gtk_cell_renderer_text_new (),
397 "text", FACE_NAME_COLUMN,
399 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
400 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->face_list), column);
402 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->face_list), FALSE);
403 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)),
404 GTK_SELECTION_BROWSE);
406 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
407 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
408 gtk_widget_set_size_request (scrolled_win,
409 FONT_STYLE_LIST_WIDTH, FONT_LIST_HEIGHT);
410 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->face_list);
411 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
412 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
413 gtk_widget_show (fontsel->face_list);
414 gtk_widget_show (scrolled_win);
415 gtk_table_attach (GTK_TABLE (table), scrolled_win, 1, 2, 1, 3,
416 GTK_EXPAND | GTK_FILL,
417 GTK_EXPAND | GTK_FILL, 0, 0);
418 focus_chain = g_list_append (focus_chain, scrolled_win);
420 focus_chain = g_list_append (focus_chain, fontsel->size_entry);
422 model = gtk_list_store_new (1, G_TYPE_INT);
423 fontsel->size_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
424 g_object_unref (model);
426 column = gtk_tree_view_column_new_with_attributes ("Size",
427 gtk_cell_renderer_text_new (),
430 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
431 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->size_list), column);
433 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->size_list), FALSE);
434 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)),
435 GTK_SELECTION_BROWSE);
437 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
438 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
439 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->size_list);
440 gtk_widget_set_size_request (scrolled_win, -1, FONT_LIST_HEIGHT);
441 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
442 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
443 gtk_widget_show (fontsel->size_list);
444 gtk_widget_show (scrolled_win);
445 gtk_table_attach (GTK_TABLE (table), scrolled_win, 2, 3, 2, 3,
446 GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
447 focus_chain = g_list_append (focus_chain, scrolled_win);
449 gtk_container_set_focus_chain (GTK_CONTAINER (table), focus_chain);
450 g_list_free (focus_chain);
452 /* Insert the fonts. */
453 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)), "changed",
454 G_CALLBACK (gtk_font_selection_select_font), fontsel);
456 g_signal_connect_after (fontsel->family_list, "map",
457 G_CALLBACK (gtk_font_selection_scroll_on_map),
460 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)), "changed",
461 G_CALLBACK (gtk_font_selection_select_style), fontsel);
463 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)), "changed",
464 G_CALLBACK (gtk_font_selection_select_size), fontsel);
466 /* create the text entry widget */
467 label = gtk_label_new_with_mnemonic (_("_Preview:"));
468 gtk_widget_show (label);
470 text_frame = gtk_frame_new (NULL);
471 gtk_frame_set_label_widget (GTK_FRAME (text_frame), label);
473 gtk_widget_show (text_frame);
474 gtk_frame_set_shadow_type (GTK_FRAME (text_frame), GTK_SHADOW_ETCHED_IN);
475 gtk_box_pack_start (GTK_BOX (fontsel), text_frame,
478 /* This is just used to get a 4-pixel space around the preview entry. */
479 text_box = gtk_hbox_new (FALSE, 0);
480 gtk_widget_show (text_box);
481 gtk_container_add (GTK_CONTAINER (text_frame), text_box);
482 gtk_container_set_border_width (GTK_CONTAINER (text_box), 4);
484 fontsel->preview_entry = gtk_entry_new ();
485 gtk_label_set_mnemonic_widget (GTK_LABEL (label), fontsel->preview_entry);
487 gtk_widget_show (fontsel->preview_entry);
488 g_signal_connect (fontsel->preview_entry, "changed",
489 G_CALLBACK (gtk_font_selection_preview_changed), fontsel);
490 gtk_widget_set_size_request (fontsel->preview_entry,
491 -1, INITIAL_PREVIEW_HEIGHT);
492 gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
495 gtk_widget_pop_composite_child();
499 gtk_font_selection_new ()
501 GtkFontSelection *fontsel;
503 fontsel = g_object_new (GTK_TYPE_FONT_SELECTION, NULL);
505 return GTK_WIDGET (fontsel);
509 gtk_font_selection_finalize (GObject *object)
511 GtkFontSelection *fontsel;
513 g_return_if_fail (GTK_IS_FONT_SELECTION (object));
515 fontsel = GTK_FONT_SELECTION (object);
518 gdk_font_unref (fontsel->font);
520 if (G_OBJECT_CLASS (font_selection_parent_class)->finalize)
521 (* G_OBJECT_CLASS (font_selection_parent_class)->finalize) (object);
525 fontsel_screen_changed (GtkFontSelection *fontsel)
527 GdkScreen *old_screen = g_object_get_data (G_OBJECT (fontsel), "gtk-font-selection-screen");
530 if (gtk_widget_has_screen (GTK_WIDGET (fontsel)))
531 screen = gtk_widget_get_screen (GTK_WIDGET (fontsel));
535 if (screen == old_screen)
540 gdk_font_unref (fontsel->font);
541 fontsel->font = NULL;
545 g_object_unref (old_screen);
549 g_object_ref (screen);
550 g_object_set_data (G_OBJECT (fontsel), "gtk-font-selection-screen", screen);
552 gtk_font_selection_show_available_fonts (fontsel);
553 gtk_font_selection_show_available_sizes (fontsel, TRUE);
554 gtk_font_selection_show_available_styles (fontsel);
557 g_object_set_data (G_OBJECT (fontsel), "gtk-font-selection-screen", NULL);
561 gtk_font_selection_hierarchy_changed (GtkWidget *widget,
562 GtkWidget *previous_toplevel)
566 if (previous_toplevel)
567 g_signal_handlers_disconnect_by_func (previous_toplevel,
568 fontsel_screen_changed,
571 toplevel = gtk_widget_get_toplevel (widget);
572 if (GTK_WIDGET_TOPLEVEL (toplevel))
573 g_signal_connect_swapped (toplevel,
575 G_CALLBACK (fontsel_screen_changed),
578 fontsel_screen_changed (GTK_FONT_SELECTION (widget));
582 gtk_font_selection_preview_changed (GtkWidget *entry,
583 GtkFontSelection *fontsel)
585 g_object_notify (G_OBJECT (fontsel), "preview_text");
589 scroll_to_selection (GtkTreeView *tree_view)
591 GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
595 if (gtk_tree_selection_get_selected (selection, &model, &iter))
597 GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
598 gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.5);
599 gtk_tree_path_free (path);
604 set_cursor_to_iter (GtkTreeView *view,
607 GtkTreeModel *model = gtk_tree_view_get_model (view);
608 GtkTreePath *path = gtk_tree_model_get_path (model, iter);
610 gtk_tree_view_set_cursor (view, path, 0, FALSE);
612 gtk_tree_path_free (path);
615 /* This is called when the list is mapped. Here we scroll to the current
616 font if necessary. */
618 gtk_font_selection_scroll_on_map (GtkWidget *widget,
621 GtkFontSelection *fontsel;
624 g_message ("In expose_list\n");
626 fontsel = GTK_FONT_SELECTION (data);
628 /* Try to scroll the font family list to the selected item */
629 scroll_to_selection (GTK_TREE_VIEW (fontsel->family_list));
631 /* Try to scroll the font family list to the selected item */
632 scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
634 /* Try to scroll the font family list to the selected item */
635 scroll_to_selection (GTK_TREE_VIEW (fontsel->size_list));
638 /* This is called when a family is selected in the list. */
640 gtk_font_selection_select_font (GtkTreeSelection *selection,
643 GtkFontSelection *fontsel;
646 const gchar *family_name;
648 fontsel = GTK_FONT_SELECTION (data);
650 if (gtk_tree_selection_get_selected (selection, &model, &iter))
652 PangoFontFamily *family;
654 gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
655 if (fontsel->family != family)
657 fontsel->family = family;
659 family_name = pango_font_family_get_name (fontsel->family);
661 #ifdef INCLUDE_FONT_ENTRIES
662 gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), family_name);
665 gtk_font_selection_show_available_styles (fontsel);
666 gtk_font_selection_select_best_style (fontsel, TRUE);
669 g_object_unref (family);
674 cmp_families (const void *a, const void *b)
676 const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a);
677 const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b);
679 return g_utf8_collate (a_name, b_name);
683 gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
686 PangoFontFamily **families;
687 PangoFontFamily *match_family = NULL;
689 GtkTreeIter match_row;
691 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list)));
693 pango_context_list_families (gtk_widget_get_pango_context (GTK_WIDGET (fontsel)),
694 &families, &n_families);
695 qsort (families, n_families, sizeof (PangoFontFamily *), cmp_families);
697 gtk_list_store_clear (model);
699 for (i=0; i<n_families; i++)
701 const gchar *name = pango_font_family_get_name (families[i]);
704 gtk_list_store_append (model, &iter);
705 gtk_list_store_set (model, &iter,
706 FAMILY_COLUMN, families[i],
707 FAMILY_NAME_COLUMN, name,
710 if (i == 0 || !g_ascii_strcasecmp (name, "sans"))
712 match_family = families[i];
717 fontsel->family = match_family;
720 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &match_row);
721 #ifdef INCLUDE_FONT_ENTRIES
722 gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry),
723 pango_font_family_get_name (match_family));
724 #endif /* INCLUDE_FONT_ENTRIES */
731 compare_font_descriptions (const PangoFontDescription *a, const PangoFontDescription *b)
733 int val = strcmp (pango_font_description_get_family (a), pango_font_description_get_family (b));
737 if (pango_font_description_get_weight (a) != pango_font_description_get_weight (b))
738 return pango_font_description_get_weight (a) - pango_font_description_get_weight (b);
740 if (pango_font_description_get_style (a) != pango_font_description_get_style (b))
741 return pango_font_description_get_style (a) - pango_font_description_get_style (b);
743 if (pango_font_description_get_stretch (a) != pango_font_description_get_stretch (b))
744 return pango_font_description_get_stretch (a) - pango_font_description_get_stretch (b);
746 if (pango_font_description_get_variant (a) != pango_font_description_get_variant (b))
747 return pango_font_description_get_variant (a) - pango_font_description_get_variant (b);
753 faces_sort_func (const void *a, const void *b)
755 PangoFontDescription *desc_a = pango_font_face_describe (*(PangoFontFace **)a);
756 PangoFontDescription *desc_b = pango_font_face_describe (*(PangoFontFace **)b);
758 int ord = compare_font_descriptions (desc_a, desc_b);
760 pango_font_description_free (desc_a);
761 pango_font_description_free (desc_b);
767 font_description_style_equal (const PangoFontDescription *a,
768 const PangoFontDescription *b)
770 return (pango_font_description_get_weight (a) == pango_font_description_get_weight (b) &&
771 pango_font_description_get_style (a) == pango_font_description_get_style (b) &&
772 pango_font_description_get_stretch (a) == pango_font_description_get_stretch (b) &&
773 pango_font_description_get_variant (a) == pango_font_description_get_variant (b));
776 /* This fills the font style list with all the possible style combinations
777 for the current font family. */
779 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
782 PangoFontFace **faces;
783 PangoFontDescription *old_desc;
785 GtkTreeIter match_row;
786 PangoFontFace *match_face = NULL;
788 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list)));
791 old_desc = pango_font_face_describe (fontsel->face);
795 pango_font_family_list_faces (fontsel->family, &faces, &n_faces);
796 qsort (faces, n_faces, sizeof (PangoFontFace *), faces_sort_func);
798 gtk_list_store_clear (model);
800 for (i=0; i < n_faces; i++)
803 const gchar *str = pango_font_face_get_face_name (faces[i]);
805 gtk_list_store_append (model, &iter);
806 gtk_list_store_set (model, &iter,
807 FACE_COLUMN, faces[i],
808 FACE_NAME_COLUMN, str,
814 match_face = faces[i];
818 PangoFontDescription *tmp_desc = pango_font_face_describe (faces[i]);
820 if (font_description_style_equal (tmp_desc, old_desc))
823 match_face = faces[i];
826 pango_font_description_free (tmp_desc);
831 pango_font_description_free (old_desc);
833 fontsel->face = match_face;
836 #ifdef INCLUDE_FONT_ENTRIES
837 const gchar *str = pango_font_face_get_face_name (fontsel->face);
839 gtk_entry_set_text (GTK_ENTRY (fontsel->font_style_entry), str);
841 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_row);
847 /* This selects a style when the user selects a font. It just uses the first
848 available style at present. I was thinking of trying to maintain the
849 selected style, e.g. bold italic, when the user selects different fonts.
850 However, the interface is so easy to use now I'm not sure it's worth it.
851 Note: This will load a font. */
853 gtk_font_selection_select_best_style (GtkFontSelection *fontsel,
859 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
861 if (gtk_tree_model_get_iter_first (model, &iter))
863 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &iter);
864 scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
867 gtk_font_selection_show_available_sizes (fontsel, FALSE);
868 gtk_font_selection_select_best_size (fontsel);
872 /* This is called when a style is selected in the list. */
874 gtk_font_selection_select_style (GtkTreeSelection *selection,
877 GtkFontSelection *fontsel = GTK_FONT_SELECTION (data);
881 if (gtk_tree_selection_get_selected (selection, &model, &iter))
885 gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
886 fontsel->face = face;
888 g_object_unref (face);
891 gtk_font_selection_show_available_sizes (fontsel, FALSE);
892 gtk_font_selection_select_best_size (fontsel);
896 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel,
901 GtkTreeSelection *selection;
905 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->size_list)));
906 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
908 /* Insert the standard font sizes */
911 gtk_list_store_clear (model);
913 for (i = 0; i < G_N_ELEMENTS (font_sizes); i++)
917 gtk_list_store_append (model, &iter);
918 gtk_list_store_set (model, &iter, SIZE_COLUMN, font_sizes[i], -1);
920 if (font_sizes[i] * PANGO_SCALE == fontsel->size)
921 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
927 gboolean found = FALSE;
929 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
930 for (i = 0; i < G_N_ELEMENTS (font_sizes) && !found; i++)
932 if (font_sizes[i] * PANGO_SCALE == fontsel->size)
934 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
938 gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter);
943 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
944 gtk_tree_selection_unselect_all (selection);
948 /* Set the entry to the new size, rounding to 1 digit,
949 * trimming of trailing 0's and a trailing period
951 sprintf (buffer, "%.1f", fontsel->size / (1.0 * PANGO_SCALE));
952 if (strchr (buffer, '.'))
954 p = buffer + strlen (buffer) - 1;
962 /* Compare, to avoid moving the cursor unecessarily */
963 if (strcmp (gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry)), buffer) != 0)
964 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
968 gtk_font_selection_select_best_size (GtkFontSelection *fontsel)
970 gtk_font_selection_load_font (fontsel);
974 gtk_font_selection_set_size (GtkFontSelection *fontsel,
977 if (fontsel->size != new_size)
979 fontsel->size = new_size;
981 gtk_font_selection_show_available_sizes (fontsel, FALSE);
982 gtk_font_selection_load_font (fontsel);
986 /* If the user hits return in the font size entry, we change to the new font
989 gtk_font_selection_size_activate (GtkWidget *w,
992 GtkFontSelection *fontsel;
996 fontsel = GTK_FONT_SELECTION (data);
998 text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
999 new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);
1001 gtk_font_selection_set_size (fontsel, new_size);
1005 gtk_font_selection_size_focus_out (GtkWidget *w,
1006 GdkEventFocus *event,
1009 gtk_font_selection_size_activate (w, data);
1014 /* This is called when a size is selected in the list. */
1016 gtk_font_selection_select_size (GtkTreeSelection *selection,
1019 GtkFontSelection *fontsel;
1020 GtkTreeModel *model;
1024 fontsel = GTK_FONT_SELECTION (data);
1026 if (gtk_tree_selection_get_selected (selection, &model, &iter))
1028 gtk_tree_model_get (model, &iter, SIZE_COLUMN, &new_size, -1);
1029 gtk_font_selection_set_size (fontsel, new_size * PANGO_SCALE);
1034 gtk_font_selection_load_font (GtkFontSelection *fontsel)
1037 gdk_font_unref (fontsel->font);
1038 fontsel->font = NULL;
1040 gtk_font_selection_update_preview (fontsel);
1043 static PangoFontDescription *
1044 gtk_font_selection_get_font_description (GtkFontSelection *fontsel)
1046 PangoFontDescription *font_desc = pango_font_face_describe (fontsel->face);
1047 pango_font_description_set_size (font_desc, fontsel->size);
1052 /* This sets the font in the preview entry to the selected font, and tries to
1053 make sure that the preview entry is a reasonable size, i.e. so that the
1054 text can be seen with a bit of space to spare. But it tries to avoid
1055 resizing the entry every time the font changes.
1056 This also used to shrink the preview if the font size was decreased, but
1057 that made it awkward if the user wanted to resize the window themself. */
1059 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1061 GtkRcStyle *rc_style;
1063 GtkRequisition old_requisition;
1064 GtkWidget *preview_entry = fontsel->preview_entry;
1067 gtk_widget_get_child_requisition (preview_entry, &old_requisition);
1069 rc_style = gtk_rc_style_new ();
1070 rc_style->font_desc = gtk_font_selection_get_font_description (fontsel);
1072 gtk_widget_modify_style (preview_entry, rc_style);
1073 gtk_rc_style_unref (rc_style);
1075 gtk_widget_size_request (preview_entry, NULL);
1077 /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1078 new_height = CLAMP (preview_entry->requisition.height, INITIAL_PREVIEW_HEIGHT, MAX_PREVIEW_HEIGHT);
1080 if (new_height > old_requisition.height || new_height < old_requisition.height - 30)
1081 gtk_widget_set_size_request (preview_entry, -1, new_height);
1083 /* This sets the preview text, if it hasn't been set already. */
1084 text = gtk_entry_get_text (GTK_ENTRY (preview_entry));
1085 if (strlen (text) == 0)
1086 gtk_entry_set_text (GTK_ENTRY (preview_entry), _(PREVIEW_TEXT));
1087 gtk_editable_set_position (GTK_EDITABLE (preview_entry), 0);
1090 /*****************************************************************************
1091 * These functions are the main public interface for getting/setting the font.
1092 *****************************************************************************/
1095 gtk_font_selection_get_font (GtkFontSelection *fontsel)
1099 PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1100 fontsel->font = gdk_font_from_description_for_display (gtk_widget_get_display (GTK_WIDGET (fontsel)), font_desc);
1101 pango_font_description_free (font_desc);
1104 return fontsel->font;
1109 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
1113 PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1114 result = pango_font_description_to_string (font_desc);
1115 pango_font_description_free (font_desc);
1121 /* This sets the current font, selecting the appropriate list rows.
1122 First we check the fontname is valid and try to find the font family
1123 - i.e. the name in the main list. If we can't find that, then just return.
1124 Next we try to set each of the properties according to the fontname.
1125 Finally we select the font family & style in the lists. */
1127 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
1128 const gchar *fontname)
1130 PangoFontFamily *new_family = NULL;
1131 PangoFontFace *new_face = NULL;
1132 PangoFontFace *fallback_face = NULL;
1133 PangoFontDescription *new_desc;
1134 GtkTreeModel *model;
1136 GtkTreeIter match_iter;
1139 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
1141 new_desc = pango_font_description_from_string (fontname);
1143 /* Check to make sure that this is in the list of allowed fonts */
1145 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list));
1146 for (valid = gtk_tree_model_get_iter_first (model, &iter);
1148 valid = gtk_tree_model_iter_next (model, &iter))
1150 PangoFontFamily *family;
1152 gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
1154 if (g_ascii_strcasecmp (pango_font_family_get_name (family),
1155 pango_font_description_get_family (new_desc)) == 0)
1156 new_family = family;
1158 g_object_unref (family);
1167 fontsel->family = new_family;
1168 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &iter);
1169 gtk_font_selection_show_available_styles (fontsel);
1171 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
1172 for (valid = gtk_tree_model_get_iter_first (model, &iter);
1174 valid = gtk_tree_model_iter_next (model, &iter))
1176 PangoFontFace *face;
1177 PangoFontDescription *tmp_desc;
1179 gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
1180 tmp_desc = pango_font_face_describe (face);
1182 if (font_description_style_equal (tmp_desc, new_desc))
1187 fallback_face = face;
1191 pango_font_description_free (tmp_desc);
1192 g_object_unref (face);
1202 new_face = fallback_face;
1204 fontsel->face = new_face;
1205 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_iter);
1207 gtk_font_selection_set_size (fontsel, pango_font_description_get_size (new_desc));
1209 g_object_freeze_notify (G_OBJECT (fontsel));
1210 g_object_notify (G_OBJECT (fontsel), "font_name");
1211 g_object_notify (G_OBJECT (fontsel), "font");
1212 g_object_thaw_notify (G_OBJECT (fontsel));
1214 pango_font_description_free (new_desc);
1220 /* This returns the text in the preview entry. You should copy the returned
1221 text if you need it. */
1222 G_CONST_RETURN gchar*
1223 gtk_font_selection_get_preview_text (GtkFontSelection *fontsel)
1225 return gtk_entry_get_text (GTK_ENTRY (fontsel->preview_entry));
1229 /* This sets the text in the preview entry. */
1231 gtk_font_selection_set_preview_text (GtkFontSelection *fontsel,
1234 gtk_entry_set_text (GTK_ENTRY (fontsel->preview_entry), text);
1237 /*****************************************************************************
1238 * GtkFontSelectionDialog
1239 *****************************************************************************/
1242 gtk_font_selection_dialog_get_type (void)
1244 static GType font_selection_dialog_type = 0;
1246 if (!font_selection_dialog_type)
1248 static const GTypeInfo fontsel_diag_info =
1250 sizeof (GtkFontSelectionDialogClass),
1251 NULL, /* base_init */
1252 NULL, /* base_finalize */
1253 (GClassInitFunc) gtk_font_selection_dialog_class_init,
1254 NULL, /* class_finalize */
1255 NULL, /* class_data */
1256 sizeof (GtkFontSelectionDialog),
1257 0, /* n_preallocs */
1258 (GInstanceInitFunc) gtk_font_selection_dialog_init,
1261 font_selection_dialog_type =
1262 g_type_register_static (GTK_TYPE_DIALOG, "GtkFontSelectionDialog",
1263 &fontsel_diag_info, 0);
1266 return font_selection_dialog_type;
1270 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
1272 font_selection_dialog_parent_class = g_type_class_peek_parent (klass);
1276 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
1280 gtk_widget_push_composite_child ();
1282 dialog = GTK_DIALOG (fontseldiag);
1284 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag), 4);
1285 gtk_window_set_resizable (GTK_WINDOW (fontseldiag), TRUE);
1287 fontseldiag->main_vbox = dialog->vbox;
1289 fontseldiag->fontsel = gtk_font_selection_new ();
1290 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag->fontsel), 4);
1291 gtk_widget_show (fontseldiag->fontsel);
1292 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
1293 fontseldiag->fontsel, TRUE, TRUE, 0);
1295 /* Create the action area */
1296 fontseldiag->action_area = dialog->action_area;
1298 fontseldiag->cancel_button = gtk_dialog_add_button (dialog,
1300 GTK_RESPONSE_CANCEL);
1302 fontseldiag->apply_button = gtk_dialog_add_button (dialog,
1304 GTK_RESPONSE_APPLY);
1305 gtk_widget_hide (fontseldiag->apply_button);
1307 fontseldiag->ok_button = gtk_dialog_add_button (dialog,
1310 gtk_widget_grab_default (fontseldiag->ok_button);
1312 gtk_window_set_title (GTK_WINDOW (fontseldiag),
1313 _("Font Selection"));
1315 gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
1317 gtk_widget_pop_composite_child ();
1321 gtk_font_selection_dialog_new (const gchar *title)
1323 GtkFontSelectionDialog *fontseldiag;
1325 fontseldiag = g_object_new (GTK_TYPE_FONT_SELECTION_DIALOG, NULL);
1328 gtk_window_set_title (GTK_WINDOW (fontseldiag), title);
1330 return GTK_WIDGET (fontseldiag);
1334 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
1336 return gtk_font_selection_get_font_name (GTK_FONT_SELECTION (fsd->fontsel));
1340 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
1342 return gtk_font_selection_get_font (GTK_FONT_SELECTION (fsd->fontsel));
1346 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
1347 const gchar *fontname)
1349 return gtk_font_selection_set_font_name (GTK_FONT_SELECTION (fsd->fontsel), fontname);
1352 G_CONST_RETURN gchar*
1353 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
1355 return gtk_font_selection_get_preview_text (GTK_FONT_SELECTION (fsd->fontsel));
1359 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
1362 gtk_font_selection_set_preview_text (GTK_FONT_SELECTION (fsd->fontsel), text);