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"
42 #include "gtkfontsel.h"
44 #include "gtkbutton.h"
45 #include "gtkcellrenderertext.h"
51 #include "gtkliststore.h"
55 #include "gtktreeselection.h"
56 #include "gtktreeview.h"
58 #include "gtkscrolledwindow.h"
60 #include "gtkaccessible.h"
61 #include "gtkprivate.h"
62 #include "gtkbuildable.h"
65 /* We don't enable the font and style entries because they don't add
66 * much in terms of visible effect and have a weird effect on keynav.
67 * the Windows font selector has entries similarly positioned but they
68 * act in conjunction with the associated lists to form a single focus
71 #undef INCLUDE_FONT_ENTRIES
73 /* This is the default text shown in the preview entry, though the user
74 can set it. Remember that some fonts only have capital letters. */
75 #define PREVIEW_TEXT N_("abcdefghijk ABCDEFGHIJK")
77 #define DEFAULT_FONT_NAME "Sans 10"
79 /* This is the initial and maximum height of the preview entry (it expands
80 when large font sizes are selected). Initial height is also the minimum. */
81 #define INITIAL_PREVIEW_HEIGHT 44
82 #define MAX_PREVIEW_HEIGHT 300
84 /* These are the sizes of the font, style & size lists. */
85 #define FONT_LIST_HEIGHT 136
86 #define FONT_LIST_WIDTH 190
87 #define FONT_STYLE_LIST_WIDTH 170
88 #define FONT_SIZE_LIST_WIDTH 60
90 /* These are what we use as the standard font sizes, for the size list.
92 static const guint16 font_sizes[] = {
93 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28,
94 32, 36, 40, 48, 56, 64, 72
119 static void gtk_font_selection_set_property (GObject *object,
123 static void gtk_font_selection_get_property (GObject *object,
127 static void gtk_font_selection_finalize (GObject *object);
128 static void gtk_font_selection_screen_changed (GtkWidget *widget,
129 GdkScreen *previous_screen);
131 /* These are the callbacks & related functions. */
132 static void gtk_font_selection_select_font (GtkTreeSelection *selection,
134 static void gtk_font_selection_show_available_fonts (GtkFontSelection *fs);
136 static void gtk_font_selection_show_available_styles (GtkFontSelection *fs);
137 static void gtk_font_selection_select_best_style (GtkFontSelection *fs,
139 static void gtk_font_selection_select_style (GtkTreeSelection *selection,
142 static void gtk_font_selection_select_best_size (GtkFontSelection *fs);
143 static void gtk_font_selection_show_available_sizes (GtkFontSelection *fs,
144 gboolean first_time);
145 static void gtk_font_selection_size_activate (GtkWidget *w,
147 static gboolean gtk_font_selection_size_focus_out (GtkWidget *w,
148 GdkEventFocus *event,
150 static void gtk_font_selection_select_size (GtkTreeSelection *selection,
153 static void gtk_font_selection_scroll_on_map (GtkWidget *w,
156 static void gtk_font_selection_preview_changed (GtkWidget *entry,
157 GtkFontSelection *fontsel);
159 /* Misc. utility functions. */
160 static void gtk_font_selection_load_font (GtkFontSelection *fs);
161 static void gtk_font_selection_update_preview (GtkFontSelection *fs);
163 static GdkFont* gtk_font_selection_get_font_internal (GtkFontSelection *fontsel);
165 G_DEFINE_TYPE (GtkFontSelection, gtk_font_selection, GTK_TYPE_VBOX)
168 gtk_font_selection_class_init (GtkFontSelectionClass *klass)
170 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
171 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
173 gobject_class->set_property = gtk_font_selection_set_property;
174 gobject_class->get_property = gtk_font_selection_get_property;
176 widget_class->screen_changed = gtk_font_selection_screen_changed;
178 g_object_class_install_property (gobject_class,
180 g_param_spec_string ("font-name",
182 P_("The string that represents this font"),
184 GTK_PARAM_READWRITE));
185 g_object_class_install_property (gobject_class,
187 g_param_spec_boxed ("font",
189 P_("The GdkFont that is currently selected"),
191 GTK_PARAM_READABLE));
192 g_object_class_install_property (gobject_class,
194 g_param_spec_string ("preview-text",
196 P_("The text to display in order to demonstrate the selected font"),
198 GTK_PARAM_READWRITE));
199 gobject_class->finalize = gtk_font_selection_finalize;
203 gtk_font_selection_set_property (GObject *object,
208 GtkFontSelection *fontsel;
210 fontsel = GTK_FONT_SELECTION (object);
215 gtk_font_selection_set_font_name (fontsel, g_value_get_string (value));
217 case PROP_PREVIEW_TEXT:
218 gtk_font_selection_set_preview_text (fontsel, g_value_get_string (value));
221 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
226 static void gtk_font_selection_get_property (GObject *object,
231 GtkFontSelection *fontsel;
233 fontsel = GTK_FONT_SELECTION (object);
238 g_value_take_string (value, gtk_font_selection_get_font_name (fontsel));
241 g_value_set_boxed (value, gtk_font_selection_get_font_internal (fontsel));
243 case PROP_PREVIEW_TEXT:
244 g_value_set_string (value, gtk_font_selection_get_preview_text (fontsel));
247 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
252 /* Handles key press events on the lists, so that we can trap Enter to
253 * activate the default button on our own.
256 list_row_activated (GtkWidget *widget)
260 window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget)));
261 if (!GTK_WIDGET_TOPLEVEL (window))
265 && widget != window->default_widget
266 && !(widget == window->focus_widget &&
267 (!window->default_widget || !GTK_WIDGET_SENSITIVE (window->default_widget))))
269 gtk_window_activate_default (window);
276 gtk_font_selection_init (GtkFontSelection *fontsel)
278 GtkWidget *scrolled_win;
280 GtkWidget *table, *label;
281 GtkWidget *font_label, *style_label;
284 GtkTreeViewColumn *column;
285 GList *focus_chain = NULL;
288 gtk_widget_push_composite_child ();
290 gtk_box_set_spacing (GTK_BOX (fontsel), 12);
291 fontsel->size = 12 * PANGO_SCALE;
293 /* Create the table of font, style & size. */
294 table = gtk_table_new (3, 3, FALSE);
295 gtk_widget_show (table);
296 gtk_table_set_row_spacings (GTK_TABLE (table), 6);
297 gtk_table_set_col_spacings (GTK_TABLE (table), 12);
298 gtk_box_pack_start (GTK_BOX (fontsel), table, TRUE, TRUE, 0);
300 #ifdef INCLUDE_FONT_ENTRIES
301 fontsel->font_entry = gtk_entry_new ();
302 gtk_editable_set_editable (GTK_EDITABLE (fontsel->font_entry), FALSE);
303 gtk_widget_set_size_request (fontsel->font_entry, 20, -1);
304 gtk_widget_show (fontsel->font_entry);
305 gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
308 fontsel->font_style_entry = gtk_entry_new ();
309 gtk_editable_set_editable (GTK_EDITABLE (fontsel->font_style_entry), FALSE);
310 gtk_widget_set_size_request (fontsel->font_style_entry, 20, -1);
311 gtk_widget_show (fontsel->font_style_entry);
312 gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
314 #endif /* INCLUDE_FONT_ENTRIES */
316 fontsel->size_entry = gtk_entry_new ();
317 gtk_widget_set_size_request (fontsel->size_entry, 20, -1);
318 gtk_widget_show (fontsel->size_entry);
319 gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
321 g_signal_connect (fontsel->size_entry, "activate",
322 G_CALLBACK (gtk_font_selection_size_activate),
324 g_signal_connect_after (fontsel->size_entry, "focus_out_event",
325 G_CALLBACK (gtk_font_selection_size_focus_out),
328 font_label = gtk_label_new_with_mnemonic (_("_Family:"));
329 gtk_misc_set_alignment (GTK_MISC (font_label), 0.0, 0.5);
330 gtk_widget_show (font_label);
331 gtk_table_attach (GTK_TABLE (table), font_label, 0, 1, 0, 1,
334 style_label = gtk_label_new_with_mnemonic (_("_Style:"));
335 gtk_misc_set_alignment (GTK_MISC (style_label), 0.0, 0.5);
336 gtk_widget_show (style_label);
337 gtk_table_attach (GTK_TABLE (table), style_label, 1, 2, 0, 1,
340 label = gtk_label_new_with_mnemonic (_("Si_ze:"));
341 gtk_label_set_mnemonic_widget (GTK_LABEL (label),
342 fontsel->size_entry);
343 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
344 gtk_widget_show (label);
345 gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
349 /* Create the lists */
351 model = gtk_list_store_new (2,
352 G_TYPE_OBJECT, /* FAMILY_COLUMN */
353 G_TYPE_STRING); /* FAMILY_NAME_COLUMN */
354 fontsel->family_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
355 g_object_unref (model);
357 g_signal_connect (fontsel->family_list, "row_activated",
358 G_CALLBACK (list_row_activated), fontsel);
360 column = gtk_tree_view_column_new_with_attributes ("Family",
361 gtk_cell_renderer_text_new (),
362 "text", FAMILY_NAME_COLUMN,
364 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
365 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->family_list), column);
367 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->family_list), FALSE);
368 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)),
369 GTK_SELECTION_BROWSE);
371 gtk_label_set_mnemonic_widget (GTK_LABEL (font_label), fontsel->family_list);
373 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
374 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
375 gtk_widget_set_size_request (scrolled_win,
376 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);
393 g_signal_connect (fontsel->face_list, "row-activated",
394 G_CALLBACK (list_row_activated), fontsel);
396 gtk_label_set_mnemonic_widget (GTK_LABEL (style_label), fontsel->face_list);
398 column = gtk_tree_view_column_new_with_attributes ("Face",
399 gtk_cell_renderer_text_new (),
400 "text", FACE_NAME_COLUMN,
402 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
403 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->face_list), column);
405 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->face_list), FALSE);
406 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)),
407 GTK_SELECTION_BROWSE);
409 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
410 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
411 gtk_widget_set_size_request (scrolled_win,
412 FONT_STYLE_LIST_WIDTH, FONT_LIST_HEIGHT);
413 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->face_list);
414 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
415 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
416 gtk_widget_show (fontsel->face_list);
417 gtk_widget_show (scrolled_win);
418 gtk_table_attach (GTK_TABLE (table), scrolled_win, 1, 2, 1, 3,
419 GTK_EXPAND | GTK_FILL,
420 GTK_EXPAND | GTK_FILL, 0, 0);
421 focus_chain = g_list_append (focus_chain, scrolled_win);
423 focus_chain = g_list_append (focus_chain, fontsel->size_entry);
425 model = gtk_list_store_new (1, G_TYPE_INT);
426 fontsel->size_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
427 g_object_unref (model);
428 g_signal_connect (fontsel->size_list, "row-activated",
429 G_CALLBACK (list_row_activated), fontsel);
431 column = gtk_tree_view_column_new_with_attributes ("Size",
432 gtk_cell_renderer_text_new (),
435 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
436 gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->size_list), column);
438 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->size_list), FALSE);
439 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)),
440 GTK_SELECTION_BROWSE);
442 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
443 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
444 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->size_list);
445 gtk_widget_set_size_request (scrolled_win, -1, FONT_LIST_HEIGHT);
446 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
447 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
448 gtk_widget_show (fontsel->size_list);
449 gtk_widget_show (scrolled_win);
450 gtk_table_attach (GTK_TABLE (table), scrolled_win, 2, 3, 2, 3,
451 GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
452 focus_chain = g_list_append (focus_chain, scrolled_win);
454 gtk_container_set_focus_chain (GTK_CONTAINER (table), focus_chain);
455 g_list_free (focus_chain);
457 /* Insert the fonts. */
458 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)), "changed",
459 G_CALLBACK (gtk_font_selection_select_font), fontsel);
461 g_signal_connect_after (fontsel->family_list, "map",
462 G_CALLBACK (gtk_font_selection_scroll_on_map),
465 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)), "changed",
466 G_CALLBACK (gtk_font_selection_select_style), fontsel);
468 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)), "changed",
469 G_CALLBACK (gtk_font_selection_select_size), fontsel);
470 atk_obj = gtk_widget_get_accessible (fontsel->size_list);
471 if (GTK_IS_ACCESSIBLE (atk_obj))
473 /* Accessibility support is enabled.
474 * Make the label ATK_RELATON_LABEL_FOR for the size list as well.
476 AtkObject *atk_label;
477 AtkRelationSet *relation_set;
478 AtkRelation *relation;
479 AtkObject *obj_array[1];
481 atk_label = gtk_widget_get_accessible (label);
482 relation_set = atk_object_ref_relation_set (atk_obj);
483 relation = atk_relation_set_get_relation_by_type (relation_set, ATK_RELATION_LABELLED_BY);
486 atk_relation_add_target (relation, atk_label);
490 obj_array[0] = atk_label;
491 relation = atk_relation_new (obj_array, 1, ATK_RELATION_LABELLED_BY);
492 atk_relation_set_add (relation_set, relation);
494 g_object_unref (relation_set);
496 relation_set = atk_object_ref_relation_set (atk_label);
497 relation = atk_relation_set_get_relation_by_type (relation_set, ATK_RELATION_LABEL_FOR);
500 atk_relation_add_target (relation, atk_obj);
504 obj_array[0] = atk_obj;
505 relation = atk_relation_new (obj_array, 1, ATK_RELATION_LABEL_FOR);
506 atk_relation_set_add (relation_set, relation);
508 g_object_unref (relation_set);
512 vbox = gtk_vbox_new (FALSE, 6);
513 gtk_widget_show (vbox);
514 gtk_box_pack_start (GTK_BOX (fontsel), vbox, FALSE, TRUE, 0);
516 /* create the text entry widget */
517 label = gtk_label_new_with_mnemonic (_("_Preview:"));
518 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
519 gtk_widget_show (label);
520 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0);
522 text_box = gtk_hbox_new (FALSE, 0);
523 gtk_widget_show (text_box);
524 gtk_box_pack_start (GTK_BOX (vbox), text_box, FALSE, TRUE, 0);
526 fontsel->preview_entry = gtk_entry_new ();
527 gtk_label_set_mnemonic_widget (GTK_LABEL (label), fontsel->preview_entry);
528 gtk_entry_set_text (GTK_ENTRY (fontsel->preview_entry), _(PREVIEW_TEXT));
530 gtk_widget_show (fontsel->preview_entry);
531 g_signal_connect (fontsel->preview_entry, "changed",
532 G_CALLBACK (gtk_font_selection_preview_changed), fontsel);
533 gtk_widget_set_size_request (fontsel->preview_entry,
534 -1, INITIAL_PREVIEW_HEIGHT);
535 gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
538 gtk_widget_pop_composite_child();
542 gtk_font_selection_new (void)
544 GtkFontSelection *fontsel;
546 fontsel = g_object_new (GTK_TYPE_FONT_SELECTION, NULL);
548 return GTK_WIDGET (fontsel);
552 gtk_font_selection_finalize (GObject *object)
554 GtkFontSelection *fontsel;
556 g_return_if_fail (GTK_IS_FONT_SELECTION (object));
558 fontsel = GTK_FONT_SELECTION (object);
561 gdk_font_unref (fontsel->font);
563 (* G_OBJECT_CLASS (gtk_font_selection_parent_class)->finalize) (object);
567 gtk_font_selection_screen_changed (GtkWidget *widget,
568 GdkScreen *previous_screen)
570 GtkFontSelection *fontsel = GTK_FONT_SELECTION (widget);
572 if (gtk_widget_has_screen (GTK_WIDGET (fontsel)))
574 gtk_font_selection_show_available_fonts (fontsel);
575 gtk_font_selection_show_available_sizes (fontsel, TRUE);
576 gtk_font_selection_show_available_styles (fontsel);
581 gtk_font_selection_preview_changed (GtkWidget *entry,
582 GtkFontSelection *fontsel)
584 g_object_notify (G_OBJECT (fontsel), "preview-text");
588 scroll_to_selection (GtkTreeView *tree_view)
590 GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
594 if (gtk_tree_selection_get_selected (selection, &model, &iter))
596 GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
597 gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.5);
598 gtk_tree_path_free (path);
603 set_cursor_to_iter (GtkTreeView *view,
606 GtkTreeModel *model = gtk_tree_view_get_model (view);
607 GtkTreePath *path = gtk_tree_model_get_path (model, iter);
609 gtk_tree_view_set_cursor (view, path, NULL, FALSE);
611 gtk_tree_path_free (path);
614 /* This is called when the list is mapped. Here we scroll to the current
615 font if necessary. */
617 gtk_font_selection_scroll_on_map (GtkWidget *widget,
620 GtkFontSelection *fontsel;
623 g_message ("In expose_list\n");
625 fontsel = GTK_FONT_SELECTION (data);
627 /* Try to scroll the font family list to the selected item */
628 scroll_to_selection (GTK_TREE_VIEW (fontsel->family_list));
630 /* Try to scroll the font family list to the selected item */
631 scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
633 /* Try to scroll the font family list to the selected item */
634 scroll_to_selection (GTK_TREE_VIEW (fontsel->size_list));
637 /* This is called when a family is selected in the list. */
639 gtk_font_selection_select_font (GtkTreeSelection *selection,
642 GtkFontSelection *fontsel;
645 #ifdef INCLUDE_FONT_ENTRIES
646 const gchar *family_name;
649 fontsel = GTK_FONT_SELECTION (data);
651 if (gtk_tree_selection_get_selected (selection, &model, &iter))
653 PangoFontFamily *family;
655 gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
656 if (fontsel->family != family)
658 fontsel->family = family;
660 #ifdef INCLUDE_FONT_ENTRIES
661 family_name = pango_font_family_get_name (fontsel->family);
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,
904 model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->size_list)));
906 /* Insert the standard font sizes */
909 gtk_list_store_clear (model);
911 for (i = 0; i < G_N_ELEMENTS (font_sizes); i++)
915 gtk_list_store_append (model, &iter);
916 gtk_list_store_set (model, &iter, SIZE_COLUMN, font_sizes[i], -1);
918 if (font_sizes[i] * PANGO_SCALE == fontsel->size)
919 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
925 gboolean found = FALSE;
927 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
928 for (i = 0; i < G_N_ELEMENTS (font_sizes) && !found; i++)
930 if (font_sizes[i] * PANGO_SCALE == fontsel->size)
932 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
936 gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter);
941 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
942 gtk_tree_selection_unselect_all (selection);
946 /* Set the entry to the new size, rounding to 1 digit,
947 * trimming of trailing 0's and a trailing period
949 g_snprintf (buffer, sizeof (buffer), "%.1f", fontsel->size / (1.0 * PANGO_SCALE));
950 if (strchr (buffer, '.'))
952 p = buffer + strlen (buffer) - 1;
960 /* Compare, to avoid moving the cursor unecessarily */
961 if (strcmp (gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry)), buffer) != 0)
962 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
966 gtk_font_selection_select_best_size (GtkFontSelection *fontsel)
968 gtk_font_selection_load_font (fontsel);
972 gtk_font_selection_set_size (GtkFontSelection *fontsel,
975 if (fontsel->size != new_size)
977 fontsel->size = new_size;
979 gtk_font_selection_show_available_sizes (fontsel, FALSE);
980 gtk_font_selection_load_font (fontsel);
984 /* If the user hits return in the font size entry, we change to the new font
987 gtk_font_selection_size_activate (GtkWidget *w,
990 GtkFontSelection *fontsel;
994 fontsel = GTK_FONT_SELECTION (data);
996 text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
997 new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);
999 if (fontsel->size != new_size)
1000 gtk_font_selection_set_size (fontsel, new_size);
1002 list_row_activated (w);
1006 gtk_font_selection_size_focus_out (GtkWidget *w,
1007 GdkEventFocus *event,
1010 GtkFontSelection *fontsel;
1014 fontsel = GTK_FONT_SELECTION (data);
1016 text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1017 new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);
1019 gtk_font_selection_set_size (fontsel, new_size);
1024 /* This is called when a size is selected in the list. */
1026 gtk_font_selection_select_size (GtkTreeSelection *selection,
1029 GtkFontSelection *fontsel;
1030 GtkTreeModel *model;
1034 fontsel = GTK_FONT_SELECTION (data);
1036 if (gtk_tree_selection_get_selected (selection, &model, &iter))
1038 gtk_tree_model_get (model, &iter, SIZE_COLUMN, &new_size, -1);
1039 gtk_font_selection_set_size (fontsel, new_size * PANGO_SCALE);
1044 gtk_font_selection_load_font (GtkFontSelection *fontsel)
1047 gdk_font_unref (fontsel->font);
1048 fontsel->font = NULL;
1050 gtk_font_selection_update_preview (fontsel);
1053 static PangoFontDescription *
1054 gtk_font_selection_get_font_description (GtkFontSelection *fontsel)
1056 PangoFontDescription *font_desc;
1060 font_desc = pango_font_face_describe (fontsel->face);
1061 pango_font_description_set_size (font_desc, fontsel->size);
1064 font_desc = pango_font_description_from_string (DEFAULT_FONT_NAME);
1069 /* This sets the font in the preview entry to the selected font, and tries to
1070 make sure that the preview entry is a reasonable size, i.e. so that the
1071 text can be seen with a bit of space to spare. But it tries to avoid
1072 resizing the entry every time the font changes.
1073 This also used to shrink the preview if the font size was decreased, but
1074 that made it awkward if the user wanted to resize the window themself. */
1076 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1078 GtkRcStyle *rc_style;
1080 GtkRequisition old_requisition;
1081 GtkWidget *preview_entry = fontsel->preview_entry;
1084 gtk_widget_get_child_requisition (preview_entry, &old_requisition);
1086 rc_style = gtk_rc_style_new ();
1087 rc_style->font_desc = gtk_font_selection_get_font_description (fontsel);
1089 gtk_widget_modify_style (preview_entry, rc_style);
1090 gtk_rc_style_unref (rc_style);
1092 gtk_widget_size_request (preview_entry, NULL);
1094 /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1095 new_height = CLAMP (preview_entry->requisition.height, INITIAL_PREVIEW_HEIGHT, MAX_PREVIEW_HEIGHT);
1097 if (new_height > old_requisition.height || new_height < old_requisition.height - 30)
1098 gtk_widget_set_size_request (preview_entry, -1, new_height);
1100 /* This sets the preview text, if it hasn't been set already. */
1101 text = gtk_entry_get_text (GTK_ENTRY (preview_entry));
1102 if (strlen (text) == 0)
1103 gtk_entry_set_text (GTK_ENTRY (preview_entry), _(PREVIEW_TEXT));
1104 gtk_editable_set_position (GTK_EDITABLE (preview_entry), 0);
1108 gtk_font_selection_get_font_internal (GtkFontSelection *fontsel)
1112 PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1113 fontsel->font = gdk_font_from_description_for_display (gtk_widget_get_display (GTK_WIDGET (fontsel)), font_desc);
1114 pango_font_description_free (font_desc);
1117 return fontsel->font;
1121 /*****************************************************************************
1122 * These functions are the main public interface for getting/setting the font.
1123 *****************************************************************************/
1126 gtk_font_selection_get_font (GtkFontSelection *fontsel)
1128 return gtk_font_selection_get_font_internal (fontsel);
1132 * gtk_font_selection_get_font_name:
1133 * @fontsel: a #GtkFontSelection
1135 * Gets the currently-selected font name. Note that this can be a different
1136 * string than what you set with gtk_font_selection_set_font_name(), as
1137 * the font selection widget may normalize font names and thus return a string
1138 * with a different structure. For example, "Helvetica Italic Bold 12" could be
1139 * normalized to "Helvetica Bold Italic 12". Use pango_font_description_equal()
1140 * if you want to compare two font descriptions.
1142 * Return value: A string with the name of the current font, or #NULL if no font
1143 * is selected. You must free this string with g_free().
1146 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
1150 PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1151 result = pango_font_description_to_string (font_desc);
1152 pango_font_description_free (font_desc);
1158 /* This sets the current font, selecting the appropriate list rows.
1159 First we check the fontname is valid and try to find the font family
1160 - i.e. the name in the main list. If we can't find that, then just return.
1161 Next we try to set each of the properties according to the fontname.
1162 Finally we select the font family & style in the lists. */
1165 * gtk_font_selection_set_font_name:
1166 * @fontsel: a #GtkFontSelection
1167 * @fontname: a font name like "Helvetica 12" or "Times Bold 18"
1169 * Sets the currently-selected font. Note that the @fontsel needs to know the
1170 * screen in which it will appear for this to work; this can be guaranteed by
1171 * simply making sure that the @fontsel is inserted in a toplevel window before
1172 * you call this function.
1174 * Return value: #TRUE if the font could be set successfully; #FALSE if no such
1175 * font exists or if the @fontsel doesn't belong to a particular screen yet.
1178 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
1179 const gchar *fontname)
1181 PangoFontFamily *new_family = NULL;
1182 PangoFontFace *new_face = NULL;
1183 PangoFontFace *fallback_face = NULL;
1184 PangoFontDescription *new_desc;
1185 GtkTreeModel *model;
1187 GtkTreeIter match_iter;
1189 const gchar *new_family_name;
1191 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
1192 g_return_val_if_fail (gtk_widget_has_screen (GTK_WIDGET (fontsel)), FALSE);
1194 new_desc = pango_font_description_from_string (fontname);
1195 new_family_name = pango_font_description_get_family (new_desc);
1197 if (!new_family_name)
1200 /* Check to make sure that this is in the list of allowed fonts
1202 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list));
1203 for (valid = gtk_tree_model_get_iter_first (model, &iter);
1205 valid = gtk_tree_model_iter_next (model, &iter))
1207 PangoFontFamily *family;
1209 gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
1211 if (g_ascii_strcasecmp (pango_font_family_get_name (family),
1212 new_family_name) == 0)
1213 new_family = family;
1215 g_object_unref (family);
1224 fontsel->family = new_family;
1225 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &iter);
1226 gtk_font_selection_show_available_styles (fontsel);
1228 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
1229 for (valid = gtk_tree_model_get_iter_first (model, &iter);
1231 valid = gtk_tree_model_iter_next (model, &iter))
1233 PangoFontFace *face;
1234 PangoFontDescription *tmp_desc;
1236 gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
1237 tmp_desc = pango_font_face_describe (face);
1239 if (font_description_style_equal (tmp_desc, new_desc))
1244 fallback_face = face;
1248 pango_font_description_free (tmp_desc);
1249 g_object_unref (face);
1259 new_face = fallback_face;
1261 fontsel->face = new_face;
1262 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_iter);
1264 gtk_font_selection_set_size (fontsel, pango_font_description_get_size (new_desc));
1266 g_object_freeze_notify (G_OBJECT (fontsel));
1267 g_object_notify (G_OBJECT (fontsel), "font-name");
1268 g_object_notify (G_OBJECT (fontsel), "font");
1269 g_object_thaw_notify (G_OBJECT (fontsel));
1271 pango_font_description_free (new_desc);
1277 /* This returns the text in the preview entry. You should copy the returned
1278 text if you need it. */
1279 G_CONST_RETURN gchar*
1280 gtk_font_selection_get_preview_text (GtkFontSelection *fontsel)
1282 return gtk_entry_get_text (GTK_ENTRY (fontsel->preview_entry));
1286 /* This sets the text in the preview entry. */
1288 gtk_font_selection_set_preview_text (GtkFontSelection *fontsel,
1291 gtk_entry_set_text (GTK_ENTRY (fontsel->preview_entry), text);
1294 /*****************************************************************************
1295 * GtkFontSelectionDialog
1296 *****************************************************************************/
1298 static void gtk_font_selection_dialog_buildable_interface_init (GtkBuildableIface *iface);
1299 static GObject * gtk_font_selection_dialog_buildable_get_internal_child (GtkBuildable *buildable,
1300 GtkBuilder *builder,
1301 const gchar *childname);
1303 G_DEFINE_TYPE_WITH_CODE (GtkFontSelectionDialog, gtk_font_selection_dialog,
1305 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
1306 gtk_font_selection_dialog_buildable_interface_init))
1308 static GtkBuildableIface *parent_buildable_iface;
1311 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
1316 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
1318 GtkDialog *dialog = GTK_DIALOG (fontseldiag);
1320 gtk_dialog_set_has_separator (dialog, FALSE);
1321 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
1322 gtk_box_set_spacing (GTK_BOX (dialog->vbox), 2); /* 2 * 5 + 2 = 12 */
1323 gtk_container_set_border_width (GTK_CONTAINER (dialog->action_area), 5);
1324 gtk_box_set_spacing (GTK_BOX (dialog->action_area), 6);
1326 gtk_widget_push_composite_child ();
1328 gtk_window_set_resizable (GTK_WINDOW (fontseldiag), TRUE);
1330 fontseldiag->main_vbox = dialog->vbox;
1332 fontseldiag->fontsel = gtk_font_selection_new ();
1333 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag->fontsel), 5);
1334 gtk_widget_show (fontseldiag->fontsel);
1335 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
1336 fontseldiag->fontsel, TRUE, TRUE, 0);
1338 /* Create the action area */
1339 fontseldiag->action_area = dialog->action_area;
1341 fontseldiag->cancel_button = gtk_dialog_add_button (dialog,
1343 GTK_RESPONSE_CANCEL);
1345 fontseldiag->apply_button = gtk_dialog_add_button (dialog,
1347 GTK_RESPONSE_APPLY);
1348 gtk_widget_hide (fontseldiag->apply_button);
1350 fontseldiag->ok_button = gtk_dialog_add_button (dialog,
1353 gtk_widget_grab_default (fontseldiag->ok_button);
1355 gtk_dialog_set_alternative_button_order (GTK_DIALOG (fontseldiag),
1358 GTK_RESPONSE_CANCEL,
1361 gtk_window_set_title (GTK_WINDOW (fontseldiag),
1362 _("Font Selection"));
1364 gtk_widget_pop_composite_child ();
1366 _gtk_dialog_set_ignore_separator (dialog, TRUE);
1370 gtk_font_selection_dialog_new (const gchar *title)
1372 GtkFontSelectionDialog *fontseldiag;
1374 fontseldiag = g_object_new (GTK_TYPE_FONT_SELECTION_DIALOG, NULL);
1377 gtk_window_set_title (GTK_WINDOW (fontseldiag), title);
1379 return GTK_WIDGET (fontseldiag);
1383 gtk_font_selection_dialog_buildable_interface_init (GtkBuildableIface *iface)
1385 parent_buildable_iface = g_type_interface_peek_parent (iface);
1386 iface->get_internal_child = gtk_font_selection_dialog_buildable_get_internal_child;
1390 gtk_font_selection_dialog_buildable_get_internal_child (GtkBuildable *buildable,
1391 GtkBuilder *builder,
1392 const gchar *childname)
1394 if (strcmp(childname, "ok_button") == 0)
1395 return G_OBJECT (GTK_FONT_SELECTION_DIALOG(buildable)->ok_button);
1396 else if (strcmp(childname, "cancel_button") == 0)
1397 return G_OBJECT (GTK_FONT_SELECTION_DIALOG (buildable)->cancel_button);
1398 else if (strcmp(childname, "apply_button") == 0)
1399 return G_OBJECT (GTK_FONT_SELECTION_DIALOG(buildable)->apply_button);
1400 else if (strcmp(childname, "font_selection") == 0)
1401 return G_OBJECT (GTK_FONT_SELECTION_DIALOG(buildable)->fontsel);
1403 return parent_buildable_iface->get_internal_child (buildable, builder, childname);
1407 * gtk_font_selection_dialog_get_font_name:
1408 * @fsd: a #GtkFontSelectionDialog
1410 * Gets the currently-selected font name. Note that this can be a different
1411 * string than what you set with gtk_font_selection_dialog_set_font_name(), as
1412 * the font selection widget may normalize font names and thus return a string
1413 * with a different structure. For example, "Helvetica Italic Bold 12" could be
1414 * normalized to "Helvetica Bold Italic 12". Use pango_font_description_equal()
1415 * if you want to compare two font descriptions.
1417 * Return value: A string with the name of the current font, or #NULL if no font
1418 * is selected. You must free this string with g_free().
1421 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
1423 return gtk_font_selection_get_font_name (GTK_FONT_SELECTION (fsd->fontsel));
1427 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
1429 return gtk_font_selection_get_font (GTK_FONT_SELECTION (fsd->fontsel));
1433 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
1434 const gchar *fontname)
1436 return gtk_font_selection_set_font_name (GTK_FONT_SELECTION (fsd->fontsel), fontname);
1439 G_CONST_RETURN gchar*
1440 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
1442 return gtk_font_selection_get_preview_text (GTK_FONT_SELECTION (fsd->fontsel));
1446 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
1449 gtk_font_selection_set_preview_text (GTK_FONT_SELECTION (fsd->fontsel), text);
1452 #define __GTK_FONTSEL_C__
1453 #include "gtkaliasdef.c"