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"
50 #include "gtksignal.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_hierarchy_changed (GtkWidget *widget,
123 GtkWidget *previous_toplevel);
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 /* FontSelectionDialog */
158 static void gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass);
159 static void gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag);
161 static gint gtk_font_selection_dialog_on_configure (GtkWidget *widget,
162 GdkEventConfigure *event,
163 GtkFontSelectionDialog *fsd);
165 static GtkWindowClass *font_selection_parent_class = NULL;
166 static GtkVBoxClass *font_selection_dialog_parent_class = NULL;
169 gtk_font_selection_get_type ()
171 static GtkType font_selection_type = 0;
173 if (!font_selection_type)
175 static const GtkTypeInfo fontsel_type_info =
178 sizeof (GtkFontSelection),
179 sizeof (GtkFontSelectionClass),
180 (GtkClassInitFunc) gtk_font_selection_class_init,
181 (GtkObjectInitFunc) gtk_font_selection_init,
182 /* reserved_1 */ NULL,
183 /* reserved_2 */ NULL,
184 (GtkClassInitFunc) NULL,
187 font_selection_type = gtk_type_unique (GTK_TYPE_VBOX,
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 = gtk_type_class (GTK_TYPE_VBOX);
202 gobject_class->set_property = gtk_font_selection_set_property;
203 gobject_class->get_property = gtk_font_selection_get_property;
205 widget_class->hierarchy_changed = gtk_font_selection_hierarchy_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 (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_entry_set_editable (GTK_ENTRY (fontsel->font_entry), FALSE);
307 gtk_widget_set_usize (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_entry_set_editable (GTK_ENTRY (fontsel->font_style_entry), FALSE);
314 gtk_widget_set_usize (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_usize (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 gtk_signal_connect (GTK_OBJECT (fontsel->size_entry), "activate",
326 (GtkSignalFunc) gtk_font_selection_size_activate,
328 gtk_signal_connect_after (GTK_OBJECT (fontsel->size_entry), "focus_out_event",
329 (GtkSignalFunc) 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_usize (scrolled_win, FONT_LIST_WIDTH, FONT_LIST_HEIGHT);
377 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->family_list);
378 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
379 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
380 gtk_widget_show (fontsel->family_list);
381 gtk_widget_show (scrolled_win);
383 gtk_table_attach (GTK_TABLE (table), scrolled_win, 0, 1, 1, 3,
384 GTK_EXPAND | GTK_FILL,
385 GTK_EXPAND | GTK_FILL, 0, 0);
386 focus_chain = g_list_append (focus_chain, scrolled_win);
388 model = gtk_list_store_new (2,
389 G_TYPE_OBJECT, /* FACE_COLUMN */
390 G_TYPE_STRING); /* FACE_NAME_COLUMN */
391 fontsel->face_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
392 g_object_unref (model);
394 gtk_label_set_mnemonic_widget (GTK_LABEL (style_label), fontsel->face_list);
396 column = gtk_tree_view_column_new_with_attributes ("Face",
397 gtk_cell_renderer_text_new (),
398 "text", FACE_NAME_COLUMN,
400 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
401 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->face_list), column);
403 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->face_list), FALSE);
404 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)),
405 GTK_SELECTION_BROWSE);
407 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
408 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
409 gtk_widget_set_usize (scrolled_win, 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_usize (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 gtk_signal_connect_after (GTK_OBJECT (fontsel->family_list), "map",
457 GTK_SIGNAL_FUNC (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 gtk_signal_connect (GTK_OBJECT (fontsel->preview_entry), "changed",
489 (GtkSignalFunc) gtk_font_selection_preview_changed,
491 gtk_widget_set_usize (fontsel->preview_entry, -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 = gtk_type_new (GTK_TYPE_FONT_SELECTION);
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 (gpointer) 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_usize (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_entry_set_position (GTK_ENTRY (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 GtkType font_selection_dialog_type = 0;
1246 if (!font_selection_dialog_type)
1248 GtkTypeInfo fontsel_diag_info =
1250 "GtkFontSelectionDialog",
1251 sizeof (GtkFontSelectionDialog),
1252 sizeof (GtkFontSelectionDialogClass),
1253 (GtkClassInitFunc) gtk_font_selection_dialog_class_init,
1254 (GtkObjectInitFunc) gtk_font_selection_dialog_init,
1255 /* reserved_1 */ NULL,
1256 /* reserved_2 */ NULL,
1257 (GtkClassInitFunc) NULL,
1260 font_selection_dialog_type = gtk_type_unique (GTK_TYPE_DIALOG,
1261 &fontsel_diag_info);
1264 return font_selection_dialog_type;
1268 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
1270 GtkObjectClass *object_class;
1272 object_class = (GtkObjectClass*) klass;
1274 font_selection_dialog_parent_class = gtk_type_class (GTK_TYPE_DIALOG);
1278 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
1282 gtk_widget_push_composite_child ();
1284 dialog = GTK_DIALOG (fontseldiag);
1286 fontseldiag->dialog_width = -1;
1287 fontseldiag->auto_resize = TRUE;
1289 gtk_widget_set_events (GTK_WIDGET (fontseldiag), GDK_STRUCTURE_MASK);
1290 gtk_signal_connect (GTK_OBJECT (fontseldiag), "configure_event",
1291 (GtkSignalFunc) gtk_font_selection_dialog_on_configure,
1294 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag), 4);
1295 gtk_window_set_policy (GTK_WINDOW (fontseldiag), FALSE, TRUE, TRUE);
1297 fontseldiag->main_vbox = dialog->vbox;
1299 fontseldiag->fontsel = gtk_font_selection_new ();
1300 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag->fontsel), 4);
1301 gtk_widget_show (fontseldiag->fontsel);
1302 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
1303 fontseldiag->fontsel, TRUE, TRUE, 0);
1305 /* Create the action area */
1306 fontseldiag->action_area = dialog->action_area;
1308 fontseldiag->cancel_button = gtk_dialog_add_button (dialog,
1310 GTK_RESPONSE_CANCEL);
1312 fontseldiag->apply_button = gtk_dialog_add_button (dialog,
1314 GTK_RESPONSE_APPLY);
1315 gtk_widget_hide (fontseldiag->apply_button);
1317 fontseldiag->ok_button = gtk_dialog_add_button (dialog,
1320 gtk_widget_grab_default (fontseldiag->ok_button);
1322 gtk_window_set_title (GTK_WINDOW (fontseldiag),
1323 _("Font Selection"));
1325 gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
1327 gtk_widget_pop_composite_child ();
1331 gtk_font_selection_dialog_new (const gchar *title)
1333 GtkFontSelectionDialog *fontseldiag;
1335 fontseldiag = gtk_type_new (GTK_TYPE_FONT_SELECTION_DIALOG);
1338 gtk_window_set_title (GTK_WINDOW (fontseldiag), title);
1340 return GTK_WIDGET (fontseldiag);
1344 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
1346 return gtk_font_selection_get_font_name (GTK_FONT_SELECTION (fsd->fontsel));
1350 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
1352 return gtk_font_selection_get_font (GTK_FONT_SELECTION (fsd->fontsel));
1356 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
1357 const gchar *fontname)
1359 return gtk_font_selection_set_font_name (GTK_FONT_SELECTION (fsd->fontsel), fontname);
1362 G_CONST_RETURN gchar*
1363 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
1365 return gtk_font_selection_get_preview_text (GTK_FONT_SELECTION (fsd->fontsel));
1369 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
1372 gtk_font_selection_set_preview_text (GTK_FONT_SELECTION (fsd->fontsel), text);
1376 /* This turns auto-shrink off if the user resizes the width of the dialog.
1377 It also turns it back on again if the user resizes it back to its normal
1380 gtk_font_selection_dialog_on_configure (GtkWidget *widget,
1381 GdkEventConfigure *event,
1382 GtkFontSelectionDialog *fsd)
1384 /* This sets the initial width. */
1385 if (fsd->dialog_width == -1)
1386 fsd->dialog_width = event->width;
1387 else if (fsd->auto_resize && fsd->dialog_width != event->width)
1389 fsd->auto_resize = FALSE;
1390 gtk_window_set_policy (GTK_WINDOW (fsd), FALSE, TRUE, FALSE);
1392 else if (!fsd->auto_resize && fsd->dialog_width == event->width)
1394 fsd->auto_resize = TRUE;
1395 gtk_window_set_policy (GTK_WINDOW (fsd), FALSE, TRUE, TRUE);