]> Pileus Git - ~andy/gtk/blob - gtk/gtkfontsel.c
Plug a mem leak. Bug #506096.
[~andy/gtk] / gtk / gtkfontsel.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
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.
8  *
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.
13  *
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.
18  *
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.
23  */
24
25 /*
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/. 
30  */
31
32 #include <config.h>
33 #include <stdlib.h>
34 #include <glib/gprintf.h>
35 #include <string.h>
36
37 #include <atk/atk.h>
38
39 #include "gdk/gdk.h"
40 #include "gdk/gdkkeysyms.h"
41
42 #include "gtkfontsel.h"
43
44 #include "gtkbutton.h"
45 #include "gtkcellrenderertext.h"
46 #include "gtkentry.h"
47 #include "gtkframe.h"
48 #include "gtkhbbox.h"
49 #include "gtkhbox.h"
50 #include "gtklabel.h"
51 #include "gtkliststore.h"
52 #include "gtkrc.h"
53 #include "gtkstock.h"
54 #include "gtktable.h"
55 #include "gtktreeselection.h"
56 #include "gtktreeview.h"
57 #include "gtkvbox.h"
58 #include "gtkscrolledwindow.h"
59 #include "gtkintl.h"
60 #include "gtkaccessible.h"
61 #include "gtkprivate.h"
62 #include "gtkbuildable.h"
63 #include "gtkalias.h"
64
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
69  * location.
70  */
71 #undef INCLUDE_FONT_ENTRIES
72
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")
76
77 #define DEFAULT_FONT_NAME "Sans 10"
78
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
83
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
89
90 /* These are what we use as the standard font sizes, for the size list.
91  */
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
95 };
96
97 enum {
98    PROP_0,
99    PROP_FONT_NAME,
100    PROP_FONT,
101    PROP_PREVIEW_TEXT
102 };
103
104
105 enum {
106   FAMILY_COLUMN,
107   FAMILY_NAME_COLUMN
108 };
109
110 enum {
111   FACE_COLUMN,
112   FACE_NAME_COLUMN
113 };
114
115 enum {
116   SIZE_COLUMN
117 };
118
119 static void    gtk_font_selection_set_property       (GObject         *object,
120                                                       guint            prop_id,
121                                                       const GValue    *value,
122                                                       GParamSpec      *pspec);
123 static void    gtk_font_selection_get_property       (GObject         *object,
124                                                       guint            prop_id,
125                                                       GValue          *value,
126                                                       GParamSpec      *pspec);
127 static void    gtk_font_selection_finalize           (GObject               *object);
128 static void    gtk_font_selection_screen_changed     (GtkWidget             *widget,
129                                                       GdkScreen             *previous_screen);
130
131 /* These are the callbacks & related functions. */
132 static void     gtk_font_selection_select_font           (GtkTreeSelection *selection,
133                                                           gpointer          data);
134 static void     gtk_font_selection_show_available_fonts  (GtkFontSelection *fs);
135
136 static void     gtk_font_selection_show_available_styles (GtkFontSelection *fs);
137 static void     gtk_font_selection_select_best_style     (GtkFontSelection *fs,
138                                                           gboolean          use_first);
139 static void     gtk_font_selection_select_style          (GtkTreeSelection *selection,
140                                                           gpointer          data);
141
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,
146                                                           gpointer          data);
147 static gboolean gtk_font_selection_size_focus_out        (GtkWidget        *w,
148                                                           GdkEventFocus    *event,
149                                                           gpointer          data);
150 static void     gtk_font_selection_select_size           (GtkTreeSelection *selection,
151                                                           gpointer          data);
152
153 static void     gtk_font_selection_scroll_on_map         (GtkWidget        *w,
154                                                           gpointer          data);
155
156 static void     gtk_font_selection_preview_changed       (GtkWidget        *entry,
157                                                           GtkFontSelection *fontsel);
158
159 /* Misc. utility functions. */
160 static void    gtk_font_selection_load_font          (GtkFontSelection *fs);
161 static void    gtk_font_selection_update_preview     (GtkFontSelection *fs);
162
163 static GdkFont* gtk_font_selection_get_font_internal (GtkFontSelection *fontsel);
164
165 G_DEFINE_TYPE (GtkFontSelection, gtk_font_selection, GTK_TYPE_VBOX)
166
167 static void
168 gtk_font_selection_class_init (GtkFontSelectionClass *klass)
169 {
170   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
171   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
172   
173   gobject_class->set_property = gtk_font_selection_set_property;
174   gobject_class->get_property = gtk_font_selection_get_property;
175
176   widget_class->screen_changed = gtk_font_selection_screen_changed;
177    
178   g_object_class_install_property (gobject_class,
179                                    PROP_FONT_NAME,
180                                    g_param_spec_string ("font-name",
181                                                         P_("Font name"),
182                                                         P_("The string that represents this font"),
183                                                         DEFAULT_FONT_NAME,
184                                                         GTK_PARAM_READWRITE));
185   g_object_class_install_property (gobject_class,
186                                    PROP_FONT,
187                                    g_param_spec_boxed ("font",
188                                                        P_("Font"),
189                                                        P_("The GdkFont that is currently selected"),
190                                                        GDK_TYPE_FONT,
191                                                        GTK_PARAM_READABLE));
192   g_object_class_install_property (gobject_class,
193                                    PROP_PREVIEW_TEXT,
194                                    g_param_spec_string ("preview-text",
195                                                         P_("Preview text"),
196                                                         P_("The text to display in order to demonstrate the selected font"),
197                                                         _(PREVIEW_TEXT),
198                                                         GTK_PARAM_READWRITE));
199   gobject_class->finalize = gtk_font_selection_finalize;
200 }
201
202 static void 
203 gtk_font_selection_set_property (GObject         *object,
204                                  guint            prop_id,
205                                  const GValue    *value,
206                                  GParamSpec      *pspec)
207 {
208   GtkFontSelection *fontsel;
209
210   fontsel = GTK_FONT_SELECTION (object);
211
212   switch (prop_id)
213     {
214     case PROP_FONT_NAME:
215       gtk_font_selection_set_font_name (fontsel, g_value_get_string (value));
216       break;
217     case PROP_PREVIEW_TEXT:
218       gtk_font_selection_set_preview_text (fontsel, g_value_get_string (value));
219       break;
220     default:
221       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
222       break;
223     }
224 }
225
226 static void gtk_font_selection_get_property (GObject         *object,
227                                              guint            prop_id,
228                                              GValue          *value,
229                                              GParamSpec      *pspec)
230 {
231   GtkFontSelection *fontsel;
232
233   fontsel = GTK_FONT_SELECTION (object);
234
235   switch (prop_id)
236     {
237     case PROP_FONT_NAME:
238       g_value_take_string (value, gtk_font_selection_get_font_name (fontsel));
239       break;
240     case PROP_FONT:
241       g_value_set_boxed (value, gtk_font_selection_get_font_internal (fontsel));
242       break;
243     case PROP_PREVIEW_TEXT:
244       g_value_set_string (value, gtk_font_selection_get_preview_text (fontsel));
245       break;
246     default:
247       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
248       break;
249     }
250 }
251
252 /* Handles key press events on the lists, so that we can trap Enter to
253  * activate the default button on our own.
254  */
255 static gboolean
256 list_row_activated (GtkWidget *widget)
257 {
258   GtkWindow *window;
259   
260   window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget)));
261   if (!GTK_WIDGET_TOPLEVEL (window))
262     window = NULL;
263   
264   if (window
265       && widget != window->default_widget
266       && !(widget == window->focus_widget &&
267            (!window->default_widget || !GTK_WIDGET_SENSITIVE (window->default_widget))))
268     {
269       gtk_window_activate_default (window);
270     }
271   
272   return TRUE;
273 }
274
275 static void
276 gtk_font_selection_init (GtkFontSelection *fontsel)
277 {
278   GtkWidget *scrolled_win;
279   GtkWidget *text_box;
280   GtkWidget *table, *label;
281   GtkWidget *font_label, *style_label;
282   GtkWidget *vbox;
283   GtkListStore *model;
284   GtkTreeViewColumn *column;
285   GList *focus_chain = NULL;
286   AtkObject *atk_obj;
287
288   gtk_widget_push_composite_child ();
289
290   gtk_box_set_spacing (GTK_BOX (fontsel), 12);
291   fontsel->size = 12 * PANGO_SCALE;
292   
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);
299
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,
306                     GTK_FILL, 0, 0, 0);
307   
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,
313                     GTK_FILL, 0, 0, 0);
314 #endif /* INCLUDE_FONT_ENTRIES */
315   
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,
320                     GTK_FILL, 0, 0, 0);
321   g_signal_connect (fontsel->size_entry, "activate",
322                     G_CALLBACK (gtk_font_selection_size_activate),
323                     fontsel);
324   g_signal_connect_after (fontsel->size_entry, "focus_out_event",
325                           G_CALLBACK (gtk_font_selection_size_focus_out),
326                           fontsel);
327   
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,
332                     GTK_FILL, 0, 0, 0);  
333
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,
338                     GTK_FILL, 0, 0, 0);
339   
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,
346                     GTK_FILL, 0, 0, 0);
347   
348   
349   /* Create the lists  */
350
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);
356
357   g_signal_connect (fontsel->family_list, "row_activated",
358                     G_CALLBACK (list_row_activated), fontsel);
359
360   column = gtk_tree_view_column_new_with_attributes ("Family",
361                                                      gtk_cell_renderer_text_new (),
362                                                      "text", FAMILY_NAME_COLUMN,
363                                                      NULL);
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);
366
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);
370   
371   gtk_label_set_mnemonic_widget (GTK_LABEL (font_label), fontsel->family_list);
372
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);
382
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);
387   
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);
395
396   gtk_label_set_mnemonic_widget (GTK_LABEL (style_label), fontsel->face_list);
397
398   column = gtk_tree_view_column_new_with_attributes ("Face",
399                                                      gtk_cell_renderer_text_new (),
400                                                      "text", FACE_NAME_COLUMN,
401                                                      NULL);
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);
404
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);
408   
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);
422   
423   focus_chain = g_list_append (focus_chain, fontsel->size_entry);
424
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);
430
431   column = gtk_tree_view_column_new_with_attributes ("Size",
432                                                      gtk_cell_renderer_text_new (),
433                                                      "text", SIZE_COLUMN,
434                                                      NULL);
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);
437
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);
441   
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);
453
454   gtk_container_set_focus_chain (GTK_CONTAINER (table), focus_chain);
455   g_list_free (focus_chain);
456   
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);
460
461   g_signal_connect_after (fontsel->family_list, "map",
462                           G_CALLBACK (gtk_font_selection_scroll_on_map),
463                           fontsel);
464   
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);
467
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))
472     {
473       /* Accessibility support is enabled.
474        * Make the label ATK_RELATON_LABEL_FOR for the size list as well.
475        */
476       AtkObject *atk_label;
477       AtkRelationSet *relation_set;
478       AtkRelation *relation;
479       AtkObject *obj_array[1];
480
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);
484       if (relation)
485         {
486           atk_relation_add_target (relation, atk_label);
487         }
488       else 
489         {
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);
493         }
494       g_object_unref (relation_set);
495
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);
498       if (relation)
499         {
500           atk_relation_add_target (relation, atk_obj);
501         }
502       else 
503         {
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);
507         }
508       g_object_unref (relation_set);
509     }    
510       
511
512   vbox = gtk_vbox_new (FALSE, 6);
513   gtk_widget_show (vbox);
514   gtk_box_pack_start (GTK_BOX (fontsel), vbox, FALSE, TRUE, 0);
515   
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);
521   
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);
525   
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));
529   
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,
536                       TRUE, TRUE, 0);
537
538   gtk_widget_pop_composite_child();
539 }
540
541 GtkWidget *
542 gtk_font_selection_new (void)
543 {
544   GtkFontSelection *fontsel;
545   
546   fontsel = g_object_new (GTK_TYPE_FONT_SELECTION, NULL);
547   
548   return GTK_WIDGET (fontsel);
549 }
550
551 static void
552 gtk_font_selection_finalize (GObject *object)
553 {
554   GtkFontSelection *fontsel;
555   
556   g_return_if_fail (GTK_IS_FONT_SELECTION (object));
557   
558   fontsel = GTK_FONT_SELECTION (object);
559
560   if (fontsel->font)
561     gdk_font_unref (fontsel->font);
562   
563   (* G_OBJECT_CLASS (gtk_font_selection_parent_class)->finalize) (object);
564 }
565
566 static void
567 gtk_font_selection_screen_changed (GtkWidget *widget,
568                                    GdkScreen *previous_screen)
569 {
570   GtkFontSelection *fontsel = GTK_FONT_SELECTION (widget);
571
572   if (gtk_widget_has_screen (GTK_WIDGET (fontsel)))
573     {
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);
577     }
578 }
579
580 static void
581 gtk_font_selection_preview_changed (GtkWidget        *entry,
582                                     GtkFontSelection *fontsel)
583 {
584   g_object_notify (G_OBJECT (fontsel), "preview-text");
585 }
586
587 static void
588 scroll_to_selection (GtkTreeView *tree_view)
589 {
590   GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
591   GtkTreeModel *model;
592   GtkTreeIter iter;
593
594   if (gtk_tree_selection_get_selected (selection, &model, &iter))
595     {
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);
599     }
600 }
601
602 static void
603 set_cursor_to_iter (GtkTreeView *view,
604                     GtkTreeIter *iter)
605 {
606   GtkTreeModel *model = gtk_tree_view_get_model (view);
607   GtkTreePath *path = gtk_tree_model_get_path (model, iter);
608   
609   gtk_tree_view_set_cursor (view, path, NULL, FALSE);
610
611   gtk_tree_path_free (path);
612 }
613
614 /* This is called when the list is mapped. Here we scroll to the current
615    font if necessary. */
616 static void
617 gtk_font_selection_scroll_on_map (GtkWidget             *widget,
618                                   gpointer               data)
619 {
620   GtkFontSelection *fontsel;
621   
622 #ifdef FONTSEL_DEBUG
623   g_message ("In expose_list\n");
624 #endif
625   fontsel = GTK_FONT_SELECTION (data);
626   
627   /* Try to scroll the font family list to the selected item */
628   scroll_to_selection (GTK_TREE_VIEW (fontsel->family_list));
629       
630   /* Try to scroll the font family list to the selected item */
631   scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
632       
633   /* Try to scroll the font family list to the selected item */
634   scroll_to_selection (GTK_TREE_VIEW (fontsel->size_list));
635 }
636
637 /* This is called when a family is selected in the list. */
638 static void
639 gtk_font_selection_select_font (GtkTreeSelection *selection,
640                                 gpointer          data)
641 {
642   GtkFontSelection *fontsel;
643   GtkTreeModel *model;
644   GtkTreeIter iter;
645 #ifdef INCLUDE_FONT_ENTRIES
646   const gchar *family_name;
647 #endif
648
649   fontsel = GTK_FONT_SELECTION (data);
650
651   if (gtk_tree_selection_get_selected (selection, &model, &iter))
652     {
653       PangoFontFamily *family;
654       
655       gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
656       if (fontsel->family != family)
657         {
658           fontsel->family = family;
659           
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);
663 #endif
664           
665           gtk_font_selection_show_available_styles (fontsel);
666           gtk_font_selection_select_best_style (fontsel, TRUE);
667         }
668
669       g_object_unref (family);
670     }
671 }
672
673 static int
674 cmp_families (const void *a, const void *b)
675 {
676   const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a);
677   const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b);
678   
679   return g_utf8_collate (a_name, b_name);
680 }
681
682 static void
683 gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
684 {
685   GtkListStore *model;
686   PangoFontFamily **families;
687   PangoFontFamily *match_family = NULL;
688   gint n_families, i;
689   GtkTreeIter match_row;
690   
691   model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list)));
692   
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);
696
697   gtk_list_store_clear (model);
698
699   for (i=0; i<n_families; i++)
700     {
701       const gchar *name = pango_font_family_get_name (families[i]);
702       GtkTreeIter iter;
703
704       gtk_list_store_append (model, &iter);
705       gtk_list_store_set (model, &iter,
706                           FAMILY_COLUMN, families[i],
707                           FAMILY_NAME_COLUMN, name,
708                           -1);
709       
710       if (i == 0 || !g_ascii_strcasecmp (name, "sans"))
711         {
712           match_family = families[i];
713           match_row = iter;
714         }
715     }
716
717   fontsel->family = match_family;
718   if (match_family)
719     {
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 */
725     }
726
727   g_free (families);
728 }
729
730 static int
731 compare_font_descriptions (const PangoFontDescription *a, const PangoFontDescription *b)
732 {
733   int val = strcmp (pango_font_description_get_family (a), pango_font_description_get_family (b));
734   if (val != 0)
735     return val;
736
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);
739
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);
742   
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);
745
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);
748
749   return 0;
750 }
751
752 static int
753 faces_sort_func (const void *a, const void *b)
754 {
755   PangoFontDescription *desc_a = pango_font_face_describe (*(PangoFontFace **)a);
756   PangoFontDescription *desc_b = pango_font_face_describe (*(PangoFontFace **)b);
757   
758   int ord = compare_font_descriptions (desc_a, desc_b);
759
760   pango_font_description_free (desc_a);
761   pango_font_description_free (desc_b);
762
763   return ord;
764 }
765
766 static gboolean
767 font_description_style_equal (const PangoFontDescription *a,
768                               const PangoFontDescription *b)
769 {
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));
774 }
775
776 /* This fills the font style list with all the possible style combinations
777    for the current font family. */
778 static void
779 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
780 {
781   gint n_faces, i;
782   PangoFontFace **faces;
783   PangoFontDescription *old_desc;
784   GtkListStore *model;
785   GtkTreeIter match_row;
786   PangoFontFace *match_face = NULL;
787   
788   model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list)));
789   
790   if (fontsel->face)
791     old_desc = pango_font_face_describe (fontsel->face);
792   else
793     old_desc= NULL;
794
795   pango_font_family_list_faces (fontsel->family, &faces, &n_faces);
796   qsort (faces, n_faces, sizeof (PangoFontFace *), faces_sort_func);
797
798   gtk_list_store_clear (model);
799
800   for (i=0; i < n_faces; i++)
801     {
802       GtkTreeIter iter;
803       const gchar *str = pango_font_face_get_face_name (faces[i]);
804
805       gtk_list_store_append (model, &iter);
806       gtk_list_store_set (model, &iter,
807                           FACE_COLUMN, faces[i],
808                           FACE_NAME_COLUMN, str,
809                           -1);
810
811       if (i == 0)
812         {
813           match_row = iter;
814           match_face = faces[i];
815         }
816       else if (old_desc)
817         {
818           PangoFontDescription *tmp_desc = pango_font_face_describe (faces[i]);
819           
820           if (font_description_style_equal (tmp_desc, old_desc))
821             {
822               match_row = iter;
823               match_face = faces[i];
824             }
825       
826           pango_font_description_free (tmp_desc);
827         }
828     }
829
830   if (old_desc)
831     pango_font_description_free (old_desc);
832
833   fontsel->face = match_face;
834   if (match_face)
835     {
836 #ifdef INCLUDE_FONT_ENTRIES
837       const gchar *str = pango_font_face_get_face_name (fontsel->face);
838
839       gtk_entry_set_text (GTK_ENTRY (fontsel->font_style_entry), str);
840 #endif      
841       set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_row);
842     }
843
844   g_free (faces);
845 }
846
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. */
852 static void
853 gtk_font_selection_select_best_style (GtkFontSelection *fontsel,
854                                       gboolean          use_first)
855 {
856   GtkTreeIter iter;
857   GtkTreeModel *model;
858
859   model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
860
861   if (gtk_tree_model_get_iter_first (model, &iter))
862     {
863       set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &iter);
864       scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
865     }
866
867   gtk_font_selection_show_available_sizes (fontsel, FALSE);
868   gtk_font_selection_select_best_size (fontsel);
869 }
870
871
872 /* This is called when a style is selected in the list. */
873 static void
874 gtk_font_selection_select_style (GtkTreeSelection *selection,
875                                  gpointer          data)
876 {
877   GtkFontSelection *fontsel = GTK_FONT_SELECTION (data);
878   GtkTreeModel *model;
879   GtkTreeIter iter;
880   
881   if (gtk_tree_selection_get_selected (selection, &model, &iter))
882     {
883       PangoFontFace *face;
884       
885       gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
886       fontsel->face = face;
887
888       g_object_unref (face);
889     }
890
891   gtk_font_selection_show_available_sizes (fontsel, FALSE);
892   gtk_font_selection_select_best_size (fontsel);
893 }
894
895 static void
896 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel,
897                                          gboolean          first_time)
898 {
899   gint i;
900   GtkListStore *model;
901   gchar buffer[128];
902   gchar *p;
903       
904   model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->size_list)));
905
906   /* Insert the standard font sizes */
907   if (first_time)
908     {
909       gtk_list_store_clear (model);
910
911       for (i = 0; i < G_N_ELEMENTS (font_sizes); i++)
912         {
913           GtkTreeIter iter;
914           
915           gtk_list_store_append (model, &iter);
916           gtk_list_store_set (model, &iter, SIZE_COLUMN, font_sizes[i], -1);
917           
918           if (font_sizes[i] * PANGO_SCALE == fontsel->size)
919             set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
920         }
921     }
922   else
923     {
924       GtkTreeIter iter;
925       gboolean found = FALSE;
926       
927       gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
928       for (i = 0; i < G_N_ELEMENTS (font_sizes) && !found; i++)
929         {
930           if (font_sizes[i] * PANGO_SCALE == fontsel->size)
931             {
932               set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
933               found = TRUE;
934             }
935
936           gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter);
937         }
938
939       if (!found)
940         {
941           GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
942           gtk_tree_selection_unselect_all (selection);
943         }
944     }
945
946   /* Set the entry to the new size, rounding to 1 digit,
947    * trimming of trailing 0's and a trailing period
948    */
949   g_snprintf (buffer, sizeof (buffer), "%.1f", fontsel->size / (1.0 * PANGO_SCALE));
950   if (strchr (buffer, '.'))
951     {
952       p = buffer + strlen (buffer) - 1;
953       while (*p == '0')
954         p--;
955       if (*p == '.')
956         p--;
957       p[1] = '\0';
958     }
959
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);
963 }
964
965 static void
966 gtk_font_selection_select_best_size (GtkFontSelection *fontsel)
967 {
968   gtk_font_selection_load_font (fontsel);  
969 }
970
971 static void
972 gtk_font_selection_set_size (GtkFontSelection *fontsel,
973                              gint              new_size)
974 {
975   if (fontsel->size != new_size)
976     {
977       fontsel->size = new_size;
978
979       gtk_font_selection_show_available_sizes (fontsel, FALSE);      
980       gtk_font_selection_load_font (fontsel);
981     }
982 }
983
984 /* If the user hits return in the font size entry, we change to the new font
985    size. */
986 static void
987 gtk_font_selection_size_activate (GtkWidget   *w,
988                                   gpointer     data)
989 {
990   GtkFontSelection *fontsel;
991   gint new_size;
992   const gchar *text;
993   
994   fontsel = GTK_FONT_SELECTION (data);
995
996   text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
997   new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);
998
999   if (fontsel->size != new_size)
1000     gtk_font_selection_set_size (fontsel, new_size);
1001   else 
1002     list_row_activated (w);
1003 }
1004
1005 static gboolean
1006 gtk_font_selection_size_focus_out (GtkWidget     *w,
1007                                    GdkEventFocus *event,
1008                                    gpointer       data)
1009 {
1010   GtkFontSelection *fontsel;
1011   gint new_size;
1012   const gchar *text;
1013   
1014   fontsel = GTK_FONT_SELECTION (data);
1015
1016   text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1017   new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);
1018
1019   gtk_font_selection_set_size (fontsel, new_size);
1020   
1021   return TRUE;
1022 }
1023
1024 /* This is called when a size is selected in the list. */
1025 static void
1026 gtk_font_selection_select_size (GtkTreeSelection *selection,
1027                                 gpointer          data)
1028 {
1029   GtkFontSelection *fontsel;
1030   GtkTreeModel *model;
1031   GtkTreeIter iter;
1032   gint new_size;
1033   
1034   fontsel = GTK_FONT_SELECTION (data);
1035   
1036   if (gtk_tree_selection_get_selected (selection, &model, &iter))
1037     {
1038       gtk_tree_model_get (model, &iter, SIZE_COLUMN, &new_size, -1);
1039       gtk_font_selection_set_size (fontsel, new_size * PANGO_SCALE);
1040     }
1041 }
1042
1043 static void
1044 gtk_font_selection_load_font (GtkFontSelection *fontsel)
1045 {
1046   if (fontsel->font)
1047     gdk_font_unref (fontsel->font);
1048   fontsel->font = NULL;
1049
1050   gtk_font_selection_update_preview (fontsel);
1051 }
1052
1053 static PangoFontDescription *
1054 gtk_font_selection_get_font_description (GtkFontSelection *fontsel)
1055 {
1056   PangoFontDescription *font_desc;
1057
1058   if (fontsel->face)
1059     {
1060       font_desc = pango_font_face_describe (fontsel->face);
1061       pango_font_description_set_size (font_desc, fontsel->size);
1062     }
1063   else
1064     font_desc = pango_font_description_from_string (DEFAULT_FONT_NAME);
1065
1066   return font_desc;
1067 }
1068
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. */
1075 static void
1076 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1077 {
1078   GtkRcStyle *rc_style;
1079   gint new_height;
1080   GtkRequisition old_requisition;
1081   GtkWidget *preview_entry = fontsel->preview_entry;
1082   const gchar *text;
1083
1084   gtk_widget_get_child_requisition (preview_entry, &old_requisition);
1085   
1086   rc_style = gtk_rc_style_new ();
1087   rc_style->font_desc = gtk_font_selection_get_font_description (fontsel);
1088   
1089   gtk_widget_modify_style (preview_entry, rc_style);
1090   gtk_rc_style_unref (rc_style);
1091
1092   gtk_widget_size_request (preview_entry, NULL);
1093   
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);
1096
1097   if (new_height > old_requisition.height || new_height < old_requisition.height - 30)
1098     gtk_widget_set_size_request (preview_entry, -1, new_height);
1099   
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);
1105 }
1106
1107 static GdkFont*
1108 gtk_font_selection_get_font_internal (GtkFontSelection *fontsel)
1109 {
1110   if (!fontsel->font)
1111     {
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);
1115     }
1116   
1117   return fontsel->font;
1118 }
1119
1120
1121 /*****************************************************************************
1122  * These functions are the main public interface for getting/setting the font.
1123  *****************************************************************************/
1124
1125 GdkFont*
1126 gtk_font_selection_get_font (GtkFontSelection *fontsel)
1127 {
1128   return gtk_font_selection_get_font_internal (fontsel);
1129 }
1130
1131 /**
1132  * gtk_font_selection_get_font_name:
1133  * @fontsel: a #GtkFontSelection
1134  * 
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.
1141  * 
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().
1144  **/
1145 gchar *
1146 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
1147 {
1148   gchar *result;
1149   
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);
1153
1154   return result;
1155 }
1156
1157
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. */
1163
1164 /**
1165  * gtk_font_selection_set_font_name:
1166  * @fontsel: a #GtkFontSelection
1167  * @fontname: a font name like "Helvetica 12" or "Times Bold 18"
1168  * 
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.
1173  * 
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.
1176  **/
1177 gboolean
1178 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
1179                                   const gchar      *fontname)
1180 {
1181   PangoFontFamily *new_family = NULL;
1182   PangoFontFace *new_face = NULL;
1183   PangoFontFace *fallback_face = NULL;
1184   PangoFontDescription *new_desc;
1185   GtkTreeModel *model;
1186   GtkTreeIter iter;
1187   GtkTreeIter match_iter;
1188   gboolean valid;
1189   const gchar *new_family_name;
1190   
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);
1193   
1194   new_desc = pango_font_description_from_string (fontname);
1195   new_family_name = pango_font_description_get_family (new_desc);
1196
1197   if (!new_family_name)
1198     return FALSE;
1199
1200   /* Check to make sure that this is in the list of allowed fonts 
1201    */
1202   model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list));
1203   for (valid = gtk_tree_model_get_iter_first (model, &iter);
1204        valid;
1205        valid = gtk_tree_model_iter_next (model, &iter))
1206     {
1207       PangoFontFamily *family;
1208       
1209       gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
1210       
1211       if (g_ascii_strcasecmp (pango_font_family_get_name (family),
1212                               new_family_name) == 0)
1213         new_family = family;
1214       
1215       g_object_unref (family);
1216       
1217       if (new_family)
1218         break;
1219     }
1220
1221   if (!new_family)
1222     return FALSE;
1223
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);
1227
1228   model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
1229   for (valid = gtk_tree_model_get_iter_first (model, &iter);
1230        valid;
1231        valid = gtk_tree_model_iter_next (model, &iter))
1232     {
1233       PangoFontFace *face;
1234       PangoFontDescription *tmp_desc;
1235       
1236       gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
1237       tmp_desc = pango_font_face_describe (face);
1238       
1239       if (font_description_style_equal (tmp_desc, new_desc))
1240         new_face = face;
1241       
1242       if (!fallback_face)
1243         {
1244           fallback_face = face;
1245           match_iter = iter;
1246         }
1247       
1248       pango_font_description_free (tmp_desc);
1249       g_object_unref (face);
1250       
1251       if (new_face)
1252         {
1253           match_iter = iter;
1254           break;
1255         }
1256     }
1257
1258   if (!new_face)
1259     new_face = fallback_face;
1260
1261   fontsel->face = new_face;
1262   set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_iter);  
1263
1264   gtk_font_selection_set_size (fontsel, pango_font_description_get_size (new_desc));
1265   
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));
1270
1271   pango_font_description_free (new_desc);
1272
1273   return TRUE;
1274 }
1275
1276
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)
1281 {
1282   return gtk_entry_get_text (GTK_ENTRY (fontsel->preview_entry));
1283 }
1284
1285
1286 /* This sets the text in the preview entry. */
1287 void
1288 gtk_font_selection_set_preview_text  (GtkFontSelection *fontsel,
1289                                       const gchar         *text)
1290 {
1291   gtk_entry_set_text (GTK_ENTRY (fontsel->preview_entry), text);
1292 }
1293
1294 /*****************************************************************************
1295  * GtkFontSelectionDialog
1296  *****************************************************************************/
1297
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);
1302
1303 G_DEFINE_TYPE_WITH_CODE (GtkFontSelectionDialog, gtk_font_selection_dialog,
1304                          GTK_TYPE_DIALOG,
1305                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
1306                                                 gtk_font_selection_dialog_buildable_interface_init))
1307
1308 static GtkBuildableIface *parent_buildable_iface;
1309
1310 static void
1311 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
1312 {
1313 }
1314
1315 static void
1316 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
1317 {
1318   GtkDialog *dialog = GTK_DIALOG (fontseldiag);
1319   
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);
1325
1326   gtk_widget_push_composite_child ();
1327
1328   gtk_window_set_resizable (GTK_WINDOW (fontseldiag), TRUE);
1329   
1330   fontseldiag->main_vbox = dialog->vbox;
1331   
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);
1337   
1338   /* Create the action area */
1339   fontseldiag->action_area = dialog->action_area;
1340
1341   fontseldiag->cancel_button = gtk_dialog_add_button (dialog,
1342                                                       GTK_STOCK_CANCEL,
1343                                                       GTK_RESPONSE_CANCEL);
1344
1345   fontseldiag->apply_button = gtk_dialog_add_button (dialog,
1346                                                      GTK_STOCK_APPLY,
1347                                                      GTK_RESPONSE_APPLY);
1348   gtk_widget_hide (fontseldiag->apply_button);
1349
1350   fontseldiag->ok_button = gtk_dialog_add_button (dialog,
1351                                                   GTK_STOCK_OK,
1352                                                   GTK_RESPONSE_OK);
1353   gtk_widget_grab_default (fontseldiag->ok_button);
1354   
1355   gtk_dialog_set_alternative_button_order (GTK_DIALOG (fontseldiag),
1356                                            GTK_RESPONSE_OK,
1357                                            GTK_RESPONSE_APPLY,
1358                                            GTK_RESPONSE_CANCEL,
1359                                            -1);
1360
1361   gtk_window_set_title (GTK_WINDOW (fontseldiag),
1362                         _("Font Selection"));
1363
1364   gtk_widget_pop_composite_child ();
1365
1366   _gtk_dialog_set_ignore_separator (dialog, TRUE);
1367 }
1368
1369 GtkWidget*
1370 gtk_font_selection_dialog_new (const gchar *title)
1371 {
1372   GtkFontSelectionDialog *fontseldiag;
1373   
1374   fontseldiag = g_object_new (GTK_TYPE_FONT_SELECTION_DIALOG, NULL);
1375
1376   if (title)
1377     gtk_window_set_title (GTK_WINDOW (fontseldiag), title);
1378   
1379   return GTK_WIDGET (fontseldiag);
1380 }
1381
1382 static void
1383 gtk_font_selection_dialog_buildable_interface_init (GtkBuildableIface *iface)
1384 {
1385   parent_buildable_iface = g_type_interface_peek_parent (iface);
1386   iface->get_internal_child = gtk_font_selection_dialog_buildable_get_internal_child;
1387 }
1388
1389 static GObject *
1390 gtk_font_selection_dialog_buildable_get_internal_child (GtkBuildable *buildable,
1391                                                         GtkBuilder   *builder,
1392                                                         const gchar  *childname)
1393 {
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);
1402
1403     return parent_buildable_iface->get_internal_child (buildable, builder, childname);
1404 }
1405
1406 /**
1407  * gtk_font_selection_dialog_get_font_name:
1408  * @fsd: a #GtkFontSelectionDialog
1409  * 
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.
1416  * 
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().
1419  **/
1420 gchar*
1421 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
1422 {
1423   return gtk_font_selection_get_font_name (GTK_FONT_SELECTION (fsd->fontsel));
1424 }
1425
1426 GdkFont*
1427 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
1428 {
1429   return gtk_font_selection_get_font (GTK_FONT_SELECTION (fsd->fontsel));
1430 }
1431
1432 gboolean
1433 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
1434                                          const gchar      *fontname)
1435 {
1436   return gtk_font_selection_set_font_name (GTK_FONT_SELECTION (fsd->fontsel), fontname);
1437 }
1438
1439 G_CONST_RETURN gchar*
1440 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
1441 {
1442   return gtk_font_selection_get_preview_text (GTK_FONT_SELECTION (fsd->fontsel));
1443 }
1444
1445 void
1446 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
1447                                             const gchar            *text)
1448 {
1449   gtk_font_selection_set_preview_text (GTK_FONT_SELECTION (fsd->fontsel), text);
1450 }
1451
1452 #define __GTK_FONTSEL_C__
1453 #include "gtkaliasdef.c"