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>
40 #include "gdk/gdkkeysyms.h"
43 #include "gtkfontsel.h"
45 #include "gtkbutton.h"
46 #include "gtkcellrenderertext.h"
52 #include "gtkliststore.h"
56 #include "gtktreeselection.h"
57 #include "gtktreeview.h"
59 #include "gtkscrolledwindow.h"
61 #include "gtkaccessible.h"
63 /* We don't enable the font and style entries because they don't add
64 * much in terms of visible effect and have a weird effect on keynav.
65 * the Windows font selector has entries similarly positioned but they
66 * act in conjunction with the associated lists to form a single focus
69 #undef INCLUDE_FONT_ENTRIES
71 /* This is the default text shown in the preview entry, though the user
72 can set it. Remember that some fonts only have capital letters. */
73 #define PREVIEW_TEXT N_("abcdefghijk ABCDEFGHIJK")
75 /* This is the initial and maximum height of the preview entry (it expands
76 when large font sizes are selected). Initial height is also the minimum. */
77 #define INITIAL_PREVIEW_HEIGHT 44
78 #define MAX_PREVIEW_HEIGHT 300
80 /* These are the sizes of the font, style & size lists. */
81 #define FONT_LIST_HEIGHT 136
82 #define FONT_LIST_WIDTH 190
83 #define FONT_STYLE_LIST_WIDTH 170
84 #define FONT_SIZE_LIST_WIDTH 60
86 /* These are what we use as the standard font sizes, for the size list.
88 static const guint16 font_sizes[] = {
89 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28,
90 32, 36, 40, 48, 56, 64, 72
115 static void gtk_font_selection_class_init (GtkFontSelectionClass *klass);
116 static void gtk_font_selection_set_property (GObject *object,
120 static void gtk_font_selection_get_property (GObject *object,
124 static void gtk_font_selection_init (GtkFontSelection *fontsel);
125 static void gtk_font_selection_finalize (GObject *object);
126 static void gtk_font_selection_screen_changed (GtkWidget *widget,
127 GdkScreen *previous_screen);
129 /* These are the callbacks & related functions. */
130 static void gtk_font_selection_select_font (GtkTreeSelection *selection,
132 static void gtk_font_selection_show_available_fonts (GtkFontSelection *fs);
134 static void gtk_font_selection_show_available_styles (GtkFontSelection *fs);
135 static void gtk_font_selection_select_best_style (GtkFontSelection *fs,
137 static void gtk_font_selection_select_style (GtkTreeSelection *selection,
140 static void gtk_font_selection_select_best_size (GtkFontSelection *fs);
141 static void gtk_font_selection_show_available_sizes (GtkFontSelection *fs,
142 gboolean first_time);
143 static void gtk_font_selection_size_activate (GtkWidget *w,
145 static gboolean gtk_font_selection_size_focus_out (GtkWidget *w,
146 GdkEventFocus *event,
148 static void gtk_font_selection_select_size (GtkTreeSelection *selection,
151 static void gtk_font_selection_scroll_on_map (GtkWidget *w,
154 static void gtk_font_selection_preview_changed (GtkWidget *entry,
155 GtkFontSelection *fontsel);
157 /* Misc. utility functions. */
158 static void gtk_font_selection_load_font (GtkFontSelection *fs);
159 static void gtk_font_selection_update_preview (GtkFontSelection *fs);
161 static GdkFont* gtk_font_selection_get_font_internal (GtkFontSelection *fontsel);
163 /* FontSelectionDialog */
164 static void gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass);
165 static void gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag);
167 static GtkVBoxClass *font_selection_parent_class = NULL;
168 static GtkWindowClass *font_selection_dialog_parent_class = NULL;
172 gtk_font_selection_get_type (void)
174 static GType font_selection_type = 0;
176 if (!font_selection_type)
178 static const GTypeInfo fontsel_type_info =
180 sizeof (GtkFontSelectionClass),
181 NULL, /* base_init */
182 NULL, /* base_finalize */
183 (GClassInitFunc) gtk_font_selection_class_init,
184 NULL, /* class_finalize */
185 NULL, /* class_data */
186 sizeof (GtkFontSelection),
188 (GInstanceInitFunc) gtk_font_selection_init,
191 font_selection_type =
192 g_type_register_static (GTK_TYPE_VBOX, "GtkFontSelection",
193 &fontsel_type_info, 0);
196 return font_selection_type;
200 gtk_font_selection_class_init (GtkFontSelectionClass *klass)
202 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
203 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
205 font_selection_parent_class = g_type_class_peek_parent (klass);
207 gobject_class->set_property = gtk_font_selection_set_property;
208 gobject_class->get_property = gtk_font_selection_get_property;
210 widget_class->screen_changed = gtk_font_selection_screen_changed;
212 g_object_class_install_property (gobject_class,
214 g_param_spec_string ("font_name",
216 P_("The X string that represents this font"),
219 g_object_class_install_property (gobject_class,
221 g_param_spec_boxed ("font",
223 P_("The GdkFont that is currently selected"),
226 g_object_class_install_property (gobject_class,
228 g_param_spec_string ("preview_text",
230 P_("The text to display in order to demonstrate the selected font"),
233 gobject_class->finalize = gtk_font_selection_finalize;
237 gtk_font_selection_set_property (GObject *object,
242 GtkFontSelection *fontsel;
244 fontsel = GTK_FONT_SELECTION (object);
249 gtk_font_selection_set_font_name (fontsel, g_value_get_string (value));
251 case PROP_PREVIEW_TEXT:
252 gtk_font_selection_set_preview_text (fontsel, g_value_get_string (value));
255 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
260 static void gtk_font_selection_get_property (GObject *object,
265 GtkFontSelection *fontsel;
267 fontsel = GTK_FONT_SELECTION (object);
272 g_value_set_string (value, gtk_font_selection_get_font_name (fontsel));
275 g_value_set_object (value, gtk_font_selection_get_font_internal (fontsel));
277 case PROP_PREVIEW_TEXT:
278 g_value_set_string (value, gtk_font_selection_get_preview_text (fontsel));
281 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
286 /* Handles key press events on the lists, so that we can trap Enter to
287 * activate the default button on our own.
290 list_row_activated (GtkWidget *widget)
294 window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget)));
295 if (!GTK_WIDGET_TOPLEVEL (window))
299 && widget != window->default_widget
300 && !(widget == window->focus_widget &&
301 (!window->default_widget || !GTK_WIDGET_SENSITIVE (window->default_widget))))
303 gtk_window_activate_default (window);
310 gtk_font_selection_init (GtkFontSelection *fontsel)
312 GtkWidget *scrolled_win;
313 GtkWidget *text_frame;
315 GtkWidget *table, *label;
316 GtkWidget *font_label, *style_label;
318 GtkTreeViewColumn *column;
319 GList *focus_chain = NULL;
322 gtk_widget_push_composite_child ();
324 fontsel->size = 12 * PANGO_SCALE;
326 /* Create the table of font, style & size. */
327 table = gtk_table_new (3, 3, FALSE);
328 gtk_widget_show (table);
329 gtk_table_set_col_spacings (GTK_TABLE (table), 8);
330 gtk_box_pack_start (GTK_BOX (fontsel), table, TRUE, TRUE, 0);
332 #ifdef INCLUDE_FONT_ENTRIES
333 fontsel->font_entry = gtk_entry_new ();
334 gtk_editable_set_editable (GTK_EDITABLE (fontsel->font_entry), FALSE);
335 gtk_widget_set_size_request (fontsel->font_entry, 20, -1);
336 gtk_widget_show (fontsel->font_entry);
337 gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
340 fontsel->font_style_entry = gtk_entry_new ();
341 gtk_editable_set_editable (GTK_EDITABLE (fontsel->font_style_entry), FALSE);
342 gtk_widget_set_size_request (fontsel->font_style_entry, 20, -1);
343 gtk_widget_show (fontsel->font_style_entry);
344 gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
346 #endif /* INCLUDE_FONT_ENTRIES */
348 fontsel->size_entry = gtk_entry_new ();
349 gtk_widget_set_size_request (fontsel->size_entry, 20, -1);
350 gtk_widget_show (fontsel->size_entry);
351 gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
353 g_signal_connect (fontsel->size_entry, "activate",
354 G_CALLBACK (gtk_font_selection_size_activate),
356 g_signal_connect_after (fontsel->size_entry, "focus_out_event",
357 G_CALLBACK (gtk_font_selection_size_focus_out),
360 font_label = gtk_label_new_with_mnemonic (_("_Family:"));
361 gtk_misc_set_alignment (GTK_MISC (font_label), 0.0, 0.5);
362 gtk_widget_show (font_label);
363 gtk_table_attach (GTK_TABLE (table), font_label, 0, 1, 0, 1,
366 style_label = gtk_label_new_with_mnemonic (_("_Style:"));
367 gtk_misc_set_alignment (GTK_MISC (style_label), 0.0, 0.5);
368 gtk_widget_show (style_label);
369 gtk_table_attach (GTK_TABLE (table), style_label, 1, 2, 0, 1,
372 label = gtk_label_new_with_mnemonic (_("Si_ze:"));
373 gtk_label_set_mnemonic_widget (GTK_LABEL (label),
374 fontsel->size_entry);
375 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
376 gtk_widget_show (label);
377 gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
381 /* Create the lists */
383 model = gtk_list_store_new (2,
384 G_TYPE_OBJECT, /* FAMILY_COLUMN */
385 G_TYPE_STRING); /* FAMILY_NAME_COLUMN */
386 fontsel->family_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
387 g_object_unref (model);
389 g_signal_connect (fontsel->family_list, "row-activated",
390 G_CALLBACK (list_row_activated), fontsel);
392 column = gtk_tree_view_column_new_with_attributes ("Family",
393 gtk_cell_renderer_text_new (),
394 "text", FAMILY_NAME_COLUMN,
396 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
397 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->family_list), column);
399 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->family_list), FALSE);
400 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)),
401 GTK_SELECTION_BROWSE);
403 gtk_label_set_mnemonic_widget (GTK_LABEL (font_label), fontsel->family_list);
405 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
406 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
407 gtk_widget_set_size_request (scrolled_win,
408 FONT_LIST_WIDTH, FONT_LIST_HEIGHT);
409 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->family_list);
410 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
411 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
412 gtk_widget_show (fontsel->family_list);
413 gtk_widget_show (scrolled_win);
415 gtk_table_attach (GTK_TABLE (table), scrolled_win, 0, 1, 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 model = gtk_list_store_new (2,
421 G_TYPE_OBJECT, /* FACE_COLUMN */
422 G_TYPE_STRING); /* FACE_NAME_COLUMN */
423 fontsel->face_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
424 g_object_unref (model);
425 g_signal_connect (fontsel->face_list, "row-activated",
426 G_CALLBACK (list_row_activated), fontsel);
428 gtk_label_set_mnemonic_widget (GTK_LABEL (style_label), fontsel->face_list);
430 column = gtk_tree_view_column_new_with_attributes ("Face",
431 gtk_cell_renderer_text_new (),
432 "text", FACE_NAME_COLUMN,
434 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
435 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->face_list), column);
437 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->face_list), FALSE);
438 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)),
439 GTK_SELECTION_BROWSE);
441 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
442 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
443 gtk_widget_set_size_request (scrolled_win,
444 FONT_STYLE_LIST_WIDTH, FONT_LIST_HEIGHT);
445 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->face_list);
446 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
447 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
448 gtk_widget_show (fontsel->face_list);
449 gtk_widget_show (scrolled_win);
450 gtk_table_attach (GTK_TABLE (table), scrolled_win, 1, 2, 1, 3,
451 GTK_EXPAND | GTK_FILL,
452 GTK_EXPAND | GTK_FILL, 0, 0);
453 focus_chain = g_list_append (focus_chain, scrolled_win);
455 focus_chain = g_list_append (focus_chain, fontsel->size_entry);
457 model = gtk_list_store_new (1, G_TYPE_INT);
458 fontsel->size_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
459 g_object_unref (model);
460 g_signal_connect (fontsel->size_list, "row-activated",
461 G_CALLBACK (list_row_activated), fontsel);
463 column = gtk_tree_view_column_new_with_attributes ("Size",
464 gtk_cell_renderer_text_new (),
467 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
468 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->size_list), column);
470 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->size_list), FALSE);
471 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)),
472 GTK_SELECTION_BROWSE);
474 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
475 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
476 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->size_list);
477 gtk_widget_set_size_request (scrolled_win, -1, FONT_LIST_HEIGHT);
478 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
479 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
480 gtk_widget_show (fontsel->size_list);
481 gtk_widget_show (scrolled_win);
482 gtk_table_attach (GTK_TABLE (table), scrolled_win, 2, 3, 2, 3,
483 GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
484 focus_chain = g_list_append (focus_chain, scrolled_win);
486 gtk_container_set_focus_chain (GTK_CONTAINER (table), focus_chain);
487 g_list_free (focus_chain);
489 /* Insert the fonts. */
490 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)), "changed",
491 G_CALLBACK (gtk_font_selection_select_font), fontsel);
493 g_signal_connect_after (fontsel->family_list, "map",
494 G_CALLBACK (gtk_font_selection_scroll_on_map),
497 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)), "changed",
498 G_CALLBACK (gtk_font_selection_select_style), fontsel);
500 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)), "changed",
501 G_CALLBACK (gtk_font_selection_select_size), fontsel);
502 atk_obj = gtk_widget_get_accessible (fontsel->size_list);
503 if (GTK_IS_ACCESSIBLE (atk_obj))
505 /* Accessibility support is enabled.
506 * Make the label ATK_RELATON_LABEL_FOR for the size list as well.
508 AtkObject *atk_label;
509 AtkRelationSet *relation_set;
510 AtkRelation *relation;
511 AtkObject *obj_array[1];
514 atk_label = gtk_widget_get_accessible (label);
515 relation_set = atk_object_ref_relation_set (atk_obj);
516 relation = atk_relation_set_get_relation_by_type (relation_set, ATK_RELATION_LABELLED_BY);
519 array = atk_relation_get_target (relation);
520 g_ptr_array_add (array, atk_label);
524 obj_array[0] = atk_label;
525 relation = atk_relation_new (obj_array, 1, ATK_RELATION_LABELLED_BY);
526 atk_relation_set_add (relation_set, relation);
528 g_object_unref (relation_set);
530 relation_set = atk_object_ref_relation_set (atk_label);
531 relation = atk_relation_set_get_relation_by_type (relation_set, ATK_RELATION_LABEL_FOR);
534 array = atk_relation_get_target (relation);
535 g_ptr_array_add (array, atk_obj);
539 obj_array[0] = atk_obj;
540 relation = atk_relation_new (obj_array, 1, ATK_RELATION_LABEL_FOR);
541 atk_relation_set_add (relation_set, relation);
543 g_object_unref (relation_set);
547 /* create the text entry widget */
548 label = gtk_label_new_with_mnemonic (_("_Preview:"));
549 gtk_widget_show (label);
551 text_frame = gtk_frame_new (NULL);
552 gtk_frame_set_label_widget (GTK_FRAME (text_frame), label);
554 gtk_widget_show (text_frame);
555 gtk_frame_set_shadow_type (GTK_FRAME (text_frame), GTK_SHADOW_ETCHED_IN);
556 gtk_box_pack_start (GTK_BOX (fontsel), text_frame,
559 /* This is just used to get a 4-pixel space around the preview entry. */
560 text_box = gtk_hbox_new (FALSE, 0);
561 gtk_widget_show (text_box);
562 gtk_container_add (GTK_CONTAINER (text_frame), text_box);
563 gtk_container_set_border_width (GTK_CONTAINER (text_box), 4);
565 fontsel->preview_entry = gtk_entry_new ();
566 gtk_label_set_mnemonic_widget (GTK_LABEL (label), fontsel->preview_entry);
568 gtk_widget_show (fontsel->preview_entry);
569 g_signal_connect (fontsel->preview_entry, "changed",
570 G_CALLBACK (gtk_font_selection_preview_changed), fontsel);
571 gtk_widget_set_size_request (fontsel->preview_entry,
572 -1, INITIAL_PREVIEW_HEIGHT);
573 gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
576 gtk_widget_pop_composite_child();
580 gtk_font_selection_new ()
582 GtkFontSelection *fontsel;
584 fontsel = g_object_new (GTK_TYPE_FONT_SELECTION, NULL);
586 return GTK_WIDGET (fontsel);
590 gtk_font_selection_finalize (GObject *object)
592 GtkFontSelection *fontsel;
594 g_return_if_fail (GTK_IS_FONT_SELECTION (object));
596 fontsel = GTK_FONT_SELECTION (object);
599 gdk_font_unref (fontsel->font);
601 (* G_OBJECT_CLASS (font_selection_parent_class)->finalize) (object);
605 gtk_font_selection_screen_changed (GtkWidget *widget,
606 GdkScreen *previous_screen)
608 GtkFontSelection *fontsel = GTK_FONT_SELECTION (widget);
610 if (gtk_widget_has_screen (GTK_WIDGET (fontsel)))
612 gtk_font_selection_show_available_fonts (fontsel);
613 gtk_font_selection_show_available_sizes (fontsel, TRUE);
614 gtk_font_selection_show_available_styles (fontsel);
619 gtk_font_selection_preview_changed (GtkWidget *entry,
620 GtkFontSelection *fontsel)
622 g_object_notify (G_OBJECT (fontsel), "preview_text");
626 scroll_to_selection (GtkTreeView *tree_view)
628 GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
632 if (gtk_tree_selection_get_selected (selection, &model, &iter))
634 GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
635 gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.5);
636 gtk_tree_path_free (path);
641 set_cursor_to_iter (GtkTreeView *view,
644 GtkTreeModel *model = gtk_tree_view_get_model (view);
645 GtkTreePath *path = gtk_tree_model_get_path (model, iter);
647 gtk_tree_view_set_cursor (view, path, 0, FALSE);
649 gtk_tree_path_free (path);
652 /* This is called when the list is mapped. Here we scroll to the current
653 font if necessary. */
655 gtk_font_selection_scroll_on_map (GtkWidget *widget,
658 GtkFontSelection *fontsel;
661 g_message ("In expose_list\n");
663 fontsel = GTK_FONT_SELECTION (data);
665 /* Try to scroll the font family list to the selected item */
666 scroll_to_selection (GTK_TREE_VIEW (fontsel->family_list));
668 /* Try to scroll the font family list to the selected item */
669 scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
671 /* Try to scroll the font family list to the selected item */
672 scroll_to_selection (GTK_TREE_VIEW (fontsel->size_list));
675 /* This is called when a family is selected in the list. */
677 gtk_font_selection_select_font (GtkTreeSelection *selection,
680 GtkFontSelection *fontsel;
683 const gchar *family_name;
685 fontsel = GTK_FONT_SELECTION (data);
687 if (gtk_tree_selection_get_selected (selection, &model, &iter))
689 PangoFontFamily *family;
691 gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
692 if (fontsel->family != family)
694 fontsel->family = family;
696 family_name = pango_font_family_get_name (fontsel->family);
698 #ifdef INCLUDE_FONT_ENTRIES
699 gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), family_name);
702 gtk_font_selection_show_available_styles (fontsel);
703 gtk_font_selection_select_best_style (fontsel, TRUE);
706 g_object_unref (family);
711 cmp_families (const void *a, const void *b)
713 const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a);
714 const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b);
716 return g_utf8_collate (a_name, b_name);
720 gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
723 PangoFontFamily **families;
724 PangoFontFamily *match_family = NULL;
726 GtkTreeIter match_row;
728 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list)));
730 pango_context_list_families (gtk_widget_get_pango_context (GTK_WIDGET (fontsel)),
731 &families, &n_families);
732 qsort (families, n_families, sizeof (PangoFontFamily *), cmp_families);
734 gtk_list_store_clear (model);
736 for (i=0; i<n_families; i++)
738 const gchar *name = pango_font_family_get_name (families[i]);
741 gtk_list_store_append (model, &iter);
742 gtk_list_store_set (model, &iter,
743 FAMILY_COLUMN, families[i],
744 FAMILY_NAME_COLUMN, name,
747 if (i == 0 || !g_ascii_strcasecmp (name, "sans"))
749 match_family = families[i];
754 fontsel->family = match_family;
757 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &match_row);
758 #ifdef INCLUDE_FONT_ENTRIES
759 gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry),
760 pango_font_family_get_name (match_family));
761 #endif /* INCLUDE_FONT_ENTRIES */
768 compare_font_descriptions (const PangoFontDescription *a, const PangoFontDescription *b)
770 int val = strcmp (pango_font_description_get_family (a), pango_font_description_get_family (b));
774 if (pango_font_description_get_weight (a) != pango_font_description_get_weight (b))
775 return pango_font_description_get_weight (a) - pango_font_description_get_weight (b);
777 if (pango_font_description_get_style (a) != pango_font_description_get_style (b))
778 return pango_font_description_get_style (a) - pango_font_description_get_style (b);
780 if (pango_font_description_get_stretch (a) != pango_font_description_get_stretch (b))
781 return pango_font_description_get_stretch (a) - pango_font_description_get_stretch (b);
783 if (pango_font_description_get_variant (a) != pango_font_description_get_variant (b))
784 return pango_font_description_get_variant (a) - pango_font_description_get_variant (b);
790 faces_sort_func (const void *a, const void *b)
792 PangoFontDescription *desc_a = pango_font_face_describe (*(PangoFontFace **)a);
793 PangoFontDescription *desc_b = pango_font_face_describe (*(PangoFontFace **)b);
795 int ord = compare_font_descriptions (desc_a, desc_b);
797 pango_font_description_free (desc_a);
798 pango_font_description_free (desc_b);
804 font_description_style_equal (const PangoFontDescription *a,
805 const PangoFontDescription *b)
807 return (pango_font_description_get_weight (a) == pango_font_description_get_weight (b) &&
808 pango_font_description_get_style (a) == pango_font_description_get_style (b) &&
809 pango_font_description_get_stretch (a) == pango_font_description_get_stretch (b) &&
810 pango_font_description_get_variant (a) == pango_font_description_get_variant (b));
813 /* This fills the font style list with all the possible style combinations
814 for the current font family. */
816 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
819 PangoFontFace **faces;
820 PangoFontDescription *old_desc;
822 GtkTreeIter match_row;
823 PangoFontFace *match_face = NULL;
825 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list)));
828 old_desc = pango_font_face_describe (fontsel->face);
832 pango_font_family_list_faces (fontsel->family, &faces, &n_faces);
833 qsort (faces, n_faces, sizeof (PangoFontFace *), faces_sort_func);
835 gtk_list_store_clear (model);
837 for (i=0; i < n_faces; i++)
840 const gchar *str = pango_font_face_get_face_name (faces[i]);
842 gtk_list_store_append (model, &iter);
843 gtk_list_store_set (model, &iter,
844 FACE_COLUMN, faces[i],
845 FACE_NAME_COLUMN, str,
851 match_face = faces[i];
855 PangoFontDescription *tmp_desc = pango_font_face_describe (faces[i]);
857 if (font_description_style_equal (tmp_desc, old_desc))
860 match_face = faces[i];
863 pango_font_description_free (tmp_desc);
868 pango_font_description_free (old_desc);
870 fontsel->face = match_face;
873 #ifdef INCLUDE_FONT_ENTRIES
874 const gchar *str = pango_font_face_get_face_name (fontsel->face);
876 gtk_entry_set_text (GTK_ENTRY (fontsel->font_style_entry), str);
878 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_row);
884 /* This selects a style when the user selects a font. It just uses the first
885 available style at present. I was thinking of trying to maintain the
886 selected style, e.g. bold italic, when the user selects different fonts.
887 However, the interface is so easy to use now I'm not sure it's worth it.
888 Note: This will load a font. */
890 gtk_font_selection_select_best_style (GtkFontSelection *fontsel,
896 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
898 if (gtk_tree_model_get_iter_first (model, &iter))
900 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &iter);
901 scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
904 gtk_font_selection_show_available_sizes (fontsel, FALSE);
905 gtk_font_selection_select_best_size (fontsel);
909 /* This is called when a style is selected in the list. */
911 gtk_font_selection_select_style (GtkTreeSelection *selection,
914 GtkFontSelection *fontsel = GTK_FONT_SELECTION (data);
918 if (gtk_tree_selection_get_selected (selection, &model, &iter))
922 gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
923 fontsel->face = face;
925 g_object_unref (face);
928 gtk_font_selection_show_available_sizes (fontsel, FALSE);
929 gtk_font_selection_select_best_size (fontsel);
933 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel,
938 GtkTreeSelection *selection;
942 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->size_list)));
943 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
945 /* Insert the standard font sizes */
948 gtk_list_store_clear (model);
950 for (i = 0; i < G_N_ELEMENTS (font_sizes); i++)
954 gtk_list_store_append (model, &iter);
955 gtk_list_store_set (model, &iter, SIZE_COLUMN, font_sizes[i], -1);
957 if (font_sizes[i] * PANGO_SCALE == fontsel->size)
958 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
964 gboolean found = FALSE;
966 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
967 for (i = 0; i < G_N_ELEMENTS (font_sizes) && !found; i++)
969 if (font_sizes[i] * PANGO_SCALE == fontsel->size)
971 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
975 gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter);
980 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
981 gtk_tree_selection_unselect_all (selection);
985 /* Set the entry to the new size, rounding to 1 digit,
986 * trimming of trailing 0's and a trailing period
988 g_snprintf (buffer, sizeof (buffer), "%.1f", fontsel->size / (1.0 * PANGO_SCALE));
989 if (strchr (buffer, '.'))
991 p = buffer + strlen (buffer) - 1;
999 /* Compare, to avoid moving the cursor unecessarily */
1000 if (strcmp (gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry)), buffer) != 0)
1001 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
1005 gtk_font_selection_select_best_size (GtkFontSelection *fontsel)
1007 gtk_font_selection_load_font (fontsel);
1011 gtk_font_selection_set_size (GtkFontSelection *fontsel,
1014 if (fontsel->size != new_size)
1016 fontsel->size = new_size;
1018 gtk_font_selection_show_available_sizes (fontsel, FALSE);
1019 gtk_font_selection_load_font (fontsel);
1023 /* If the user hits return in the font size entry, we change to the new font
1026 gtk_font_selection_size_activate (GtkWidget *w,
1029 GtkFontSelection *fontsel;
1033 fontsel = GTK_FONT_SELECTION (data);
1035 text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1036 new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);
1038 if (fontsel->size != new_size)
1039 gtk_font_selection_set_size (fontsel, new_size);
1041 list_row_activated (w);
1045 gtk_font_selection_size_focus_out (GtkWidget *w,
1046 GdkEventFocus *event,
1049 GtkFontSelection *fontsel;
1053 fontsel = GTK_FONT_SELECTION (data);
1055 text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1056 new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);
1058 gtk_font_selection_set_size (fontsel, new_size);
1063 /* This is called when a size is selected in the list. */
1065 gtk_font_selection_select_size (GtkTreeSelection *selection,
1068 GtkFontSelection *fontsel;
1069 GtkTreeModel *model;
1073 fontsel = GTK_FONT_SELECTION (data);
1075 if (gtk_tree_selection_get_selected (selection, &model, &iter))
1077 gtk_tree_model_get (model, &iter, SIZE_COLUMN, &new_size, -1);
1078 gtk_font_selection_set_size (fontsel, new_size * PANGO_SCALE);
1083 gtk_font_selection_load_font (GtkFontSelection *fontsel)
1086 gdk_font_unref (fontsel->font);
1087 fontsel->font = NULL;
1089 gtk_font_selection_update_preview (fontsel);
1092 static PangoFontDescription *
1093 gtk_font_selection_get_font_description (GtkFontSelection *fontsel)
1095 PangoFontDescription *font_desc;
1099 font_desc = pango_font_face_describe (fontsel->face);
1100 pango_font_description_set_size (font_desc, fontsel->size);
1103 font_desc = pango_font_description_from_string ("Sans 10");
1108 /* This sets the font in the preview entry to the selected font, and tries to
1109 make sure that the preview entry is a reasonable size, i.e. so that the
1110 text can be seen with a bit of space to spare. But it tries to avoid
1111 resizing the entry every time the font changes.
1112 This also used to shrink the preview if the font size was decreased, but
1113 that made it awkward if the user wanted to resize the window themself. */
1115 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1117 GtkRcStyle *rc_style;
1119 GtkRequisition old_requisition;
1120 GtkWidget *preview_entry = fontsel->preview_entry;
1123 gtk_widget_get_child_requisition (preview_entry, &old_requisition);
1125 rc_style = gtk_rc_style_new ();
1126 rc_style->font_desc = gtk_font_selection_get_font_description (fontsel);
1128 gtk_widget_modify_style (preview_entry, rc_style);
1129 gtk_rc_style_unref (rc_style);
1131 gtk_widget_size_request (preview_entry, NULL);
1133 /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1134 new_height = CLAMP (preview_entry->requisition.height, INITIAL_PREVIEW_HEIGHT, MAX_PREVIEW_HEIGHT);
1136 if (new_height > old_requisition.height || new_height < old_requisition.height - 30)
1137 gtk_widget_set_size_request (preview_entry, -1, new_height);
1139 /* This sets the preview text, if it hasn't been set already. */
1140 text = gtk_entry_get_text (GTK_ENTRY (preview_entry));
1141 if (strlen (text) == 0)
1142 gtk_entry_set_text (GTK_ENTRY (preview_entry), _(PREVIEW_TEXT));
1143 gtk_editable_set_position (GTK_EDITABLE (preview_entry), 0);
1147 gtk_font_selection_get_font_internal (GtkFontSelection *fontsel)
1151 PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1152 fontsel->font = gdk_font_from_description_for_display (gtk_widget_get_display (GTK_WIDGET (fontsel)), font_desc);
1153 pango_font_description_free (font_desc);
1156 return fontsel->font;
1160 /*****************************************************************************
1161 * These functions are the main public interface for getting/setting the font.
1162 *****************************************************************************/
1165 gtk_font_selection_get_font (GtkFontSelection *fontsel)
1167 return gtk_font_selection_get_font_internal (fontsel);
1171 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
1175 PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1176 result = pango_font_description_to_string (font_desc);
1177 pango_font_description_free (font_desc);
1183 /* This sets the current font, selecting the appropriate list rows.
1184 First we check the fontname is valid and try to find the font family
1185 - i.e. the name in the main list. If we can't find that, then just return.
1186 Next we try to set each of the properties according to the fontname.
1187 Finally we select the font family & style in the lists. */
1189 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
1190 const gchar *fontname)
1192 PangoFontFamily *new_family = NULL;
1193 PangoFontFace *new_face = NULL;
1194 PangoFontFace *fallback_face = NULL;
1195 PangoFontDescription *new_desc;
1196 GtkTreeModel *model;
1198 GtkTreeIter match_iter;
1201 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
1203 new_desc = pango_font_description_from_string (fontname);
1205 /* Check to make sure that this is in the list of allowed fonts */
1207 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list));
1208 for (valid = gtk_tree_model_get_iter_first (model, &iter);
1210 valid = gtk_tree_model_iter_next (model, &iter))
1212 PangoFontFamily *family;
1214 gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
1216 if (g_ascii_strcasecmp (pango_font_family_get_name (family),
1217 pango_font_description_get_family (new_desc)) == 0)
1218 new_family = family;
1220 g_object_unref (family);
1229 fontsel->family = new_family;
1230 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &iter);
1231 gtk_font_selection_show_available_styles (fontsel);
1233 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
1234 for (valid = gtk_tree_model_get_iter_first (model, &iter);
1236 valid = gtk_tree_model_iter_next (model, &iter))
1238 PangoFontFace *face;
1239 PangoFontDescription *tmp_desc;
1241 gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
1242 tmp_desc = pango_font_face_describe (face);
1244 if (font_description_style_equal (tmp_desc, new_desc))
1249 fallback_face = face;
1253 pango_font_description_free (tmp_desc);
1254 g_object_unref (face);
1264 new_face = fallback_face;
1266 fontsel->face = new_face;
1267 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_iter);
1269 gtk_font_selection_set_size (fontsel, pango_font_description_get_size (new_desc));
1271 g_object_freeze_notify (G_OBJECT (fontsel));
1272 g_object_notify (G_OBJECT (fontsel), "font_name");
1273 g_object_notify (G_OBJECT (fontsel), "font");
1274 g_object_thaw_notify (G_OBJECT (fontsel));
1276 pango_font_description_free (new_desc);
1282 /* This returns the text in the preview entry. You should copy the returned
1283 text if you need it. */
1284 G_CONST_RETURN gchar*
1285 gtk_font_selection_get_preview_text (GtkFontSelection *fontsel)
1287 return gtk_entry_get_text (GTK_ENTRY (fontsel->preview_entry));
1291 /* This sets the text in the preview entry. */
1293 gtk_font_selection_set_preview_text (GtkFontSelection *fontsel,
1296 gtk_entry_set_text (GTK_ENTRY (fontsel->preview_entry), text);
1299 /*****************************************************************************
1300 * GtkFontSelectionDialog
1301 *****************************************************************************/
1304 gtk_font_selection_dialog_get_type (void)
1306 static GType font_selection_dialog_type = 0;
1308 if (!font_selection_dialog_type)
1310 static const GTypeInfo fontsel_diag_info =
1312 sizeof (GtkFontSelectionDialogClass),
1313 NULL, /* base_init */
1314 NULL, /* base_finalize */
1315 (GClassInitFunc) gtk_font_selection_dialog_class_init,
1316 NULL, /* class_finalize */
1317 NULL, /* class_data */
1318 sizeof (GtkFontSelectionDialog),
1319 0, /* n_preallocs */
1320 (GInstanceInitFunc) gtk_font_selection_dialog_init,
1323 font_selection_dialog_type =
1324 g_type_register_static (GTK_TYPE_DIALOG, "GtkFontSelectionDialog",
1325 &fontsel_diag_info, 0);
1328 return font_selection_dialog_type;
1332 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
1334 font_selection_dialog_parent_class = g_type_class_peek_parent (klass);
1338 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
1342 gtk_widget_push_composite_child ();
1344 dialog = GTK_DIALOG (fontseldiag);
1346 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag), 4);
1347 gtk_window_set_resizable (GTK_WINDOW (fontseldiag), TRUE);
1349 fontseldiag->main_vbox = dialog->vbox;
1351 fontseldiag->fontsel = gtk_font_selection_new ();
1352 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag->fontsel), 4);
1353 gtk_widget_show (fontseldiag->fontsel);
1354 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
1355 fontseldiag->fontsel, TRUE, TRUE, 0);
1357 /* Create the action area */
1358 fontseldiag->action_area = dialog->action_area;
1360 fontseldiag->cancel_button = gtk_dialog_add_button (dialog,
1362 GTK_RESPONSE_CANCEL);
1364 fontseldiag->apply_button = gtk_dialog_add_button (dialog,
1366 GTK_RESPONSE_APPLY);
1367 gtk_widget_hide (fontseldiag->apply_button);
1369 fontseldiag->ok_button = gtk_dialog_add_button (dialog,
1372 gtk_widget_grab_default (fontseldiag->ok_button);
1374 gtk_window_set_title (GTK_WINDOW (fontseldiag),
1375 _("Font Selection"));
1377 gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
1379 gtk_widget_pop_composite_child ();
1383 gtk_font_selection_dialog_new (const gchar *title)
1385 GtkFontSelectionDialog *fontseldiag;
1387 fontseldiag = g_object_new (GTK_TYPE_FONT_SELECTION_DIALOG, NULL);
1390 gtk_window_set_title (GTK_WINDOW (fontseldiag), title);
1392 return GTK_WIDGET (fontseldiag);
1396 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
1398 return gtk_font_selection_get_font_name (GTK_FONT_SELECTION (fsd->fontsel));
1402 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
1404 return gtk_font_selection_get_font (GTK_FONT_SELECTION (fsd->fontsel));
1408 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
1409 const gchar *fontname)
1411 return gtk_font_selection_set_font_name (GTK_FONT_SELECTION (fsd->fontsel), fontname);
1414 G_CONST_RETURN gchar*
1415 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
1417 return gtk_font_selection_get_preview_text (GTK_FONT_SELECTION (fsd->fontsel));
1421 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
1424 gtk_font_selection_set_preview_text (GTK_FONT_SELECTION (fsd->fontsel), text);