]> Pileus Git - ~andy/gtk/blob - gtk/gtkfontsel.c
Forgotten files
[~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 /**
542  * gtk_font_selection_new:
543  *
544  * Creates a new #GtkFontSelection.
545  *
546  * Return value: a n ew #GtkFontSelection
547  */
548 GtkWidget *
549 gtk_font_selection_new (void)
550 {
551   GtkFontSelection *fontsel;
552   
553   fontsel = g_object_new (GTK_TYPE_FONT_SELECTION, NULL);
554   
555   return GTK_WIDGET (fontsel);
556 }
557
558 static void
559 gtk_font_selection_finalize (GObject *object)
560 {
561   GtkFontSelection *fontsel;
562   
563   g_return_if_fail (GTK_IS_FONT_SELECTION (object));
564   
565   fontsel = GTK_FONT_SELECTION (object);
566
567   if (fontsel->font)
568     gdk_font_unref (fontsel->font);
569
570   G_OBJECT_CLASS (gtk_font_selection_parent_class)->finalize (object);
571 }
572
573 static void
574 gtk_font_selection_screen_changed (GtkWidget *widget,
575                                    GdkScreen *previous_screen)
576 {
577   GtkFontSelection *fontsel = GTK_FONT_SELECTION (widget);
578
579   if (gtk_widget_has_screen (GTK_WIDGET (fontsel)))
580     {
581       gtk_font_selection_show_available_fonts (fontsel);
582       gtk_font_selection_show_available_sizes (fontsel, TRUE);
583       gtk_font_selection_show_available_styles (fontsel);
584     }
585 }
586
587 static void
588 gtk_font_selection_preview_changed (GtkWidget        *entry,
589                                     GtkFontSelection *fontsel)
590 {
591   g_object_notify (G_OBJECT (fontsel), "preview-text");
592 }
593
594 static void
595 scroll_to_selection (GtkTreeView *tree_view)
596 {
597   GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
598   GtkTreeModel *model;
599   GtkTreeIter iter;
600
601   if (gtk_tree_selection_get_selected (selection, &model, &iter))
602     {
603       GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
604       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.5);
605       gtk_tree_path_free (path);
606     }
607 }
608
609 static void
610 set_cursor_to_iter (GtkTreeView *view,
611                     GtkTreeIter *iter)
612 {
613   GtkTreeModel *model = gtk_tree_view_get_model (view);
614   GtkTreePath *path = gtk_tree_model_get_path (model, iter);
615   
616   gtk_tree_view_set_cursor (view, path, NULL, FALSE);
617
618   gtk_tree_path_free (path);
619 }
620
621 /* This is called when the list is mapped. Here we scroll to the current
622    font if necessary. */
623 static void
624 gtk_font_selection_scroll_on_map (GtkWidget             *widget,
625                                   gpointer               data)
626 {
627   GtkFontSelection *fontsel;
628   
629 #ifdef FONTSEL_DEBUG
630   g_message ("In expose_list\n");
631 #endif
632   fontsel = GTK_FONT_SELECTION (data);
633   
634   /* Try to scroll the font family list to the selected item */
635   scroll_to_selection (GTK_TREE_VIEW (fontsel->family_list));
636       
637   /* Try to scroll the font family list to the selected item */
638   scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
639       
640   /* Try to scroll the font family list to the selected item */
641   scroll_to_selection (GTK_TREE_VIEW (fontsel->size_list));
642 }
643
644 /* This is called when a family is selected in the list. */
645 static void
646 gtk_font_selection_select_font (GtkTreeSelection *selection,
647                                 gpointer          data)
648 {
649   GtkFontSelection *fontsel;
650   GtkTreeModel *model;
651   GtkTreeIter iter;
652 #ifdef INCLUDE_FONT_ENTRIES
653   const gchar *family_name;
654 #endif
655
656   fontsel = GTK_FONT_SELECTION (data);
657
658   if (gtk_tree_selection_get_selected (selection, &model, &iter))
659     {
660       PangoFontFamily *family;
661       
662       gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
663       if (fontsel->family != family)
664         {
665           fontsel->family = family;
666           
667 #ifdef INCLUDE_FONT_ENTRIES
668           family_name = pango_font_family_get_name (fontsel->family);
669           gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), family_name);
670 #endif
671           
672           gtk_font_selection_show_available_styles (fontsel);
673           gtk_font_selection_select_best_style (fontsel, TRUE);
674         }
675
676       g_object_unref (family);
677     }
678 }
679
680 static int
681 cmp_families (const void *a, const void *b)
682 {
683   const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a);
684   const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b);
685   
686   return g_utf8_collate (a_name, b_name);
687 }
688
689 static void
690 gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
691 {
692   GtkListStore *model;
693   PangoFontFamily **families;
694   PangoFontFamily *match_family = NULL;
695   gint n_families, i;
696   GtkTreeIter match_row;
697   
698   model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list)));
699   
700   pango_context_list_families (gtk_widget_get_pango_context (GTK_WIDGET (fontsel)),
701                                &families, &n_families);
702   qsort (families, n_families, sizeof (PangoFontFamily *), cmp_families);
703
704   gtk_list_store_clear (model);
705
706   for (i=0; i<n_families; i++)
707     {
708       const gchar *name = pango_font_family_get_name (families[i]);
709       GtkTreeIter iter;
710
711       gtk_list_store_append (model, &iter);
712       gtk_list_store_set (model, &iter,
713                           FAMILY_COLUMN, families[i],
714                           FAMILY_NAME_COLUMN, name,
715                           -1);
716       
717       if (i == 0 || !g_ascii_strcasecmp (name, "sans"))
718         {
719           match_family = families[i];
720           match_row = iter;
721         }
722     }
723
724   fontsel->family = match_family;
725   if (match_family)
726     {
727       set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &match_row);
728 #ifdef INCLUDE_FONT_ENTRIES
729       gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), 
730                           pango_font_family_get_name (match_family));
731 #endif /* INCLUDE_FONT_ENTRIES */
732     }
733
734   g_free (families);
735 }
736
737 static int
738 compare_font_descriptions (const PangoFontDescription *a, const PangoFontDescription *b)
739 {
740   int val = strcmp (pango_font_description_get_family (a), pango_font_description_get_family (b));
741   if (val != 0)
742     return val;
743
744   if (pango_font_description_get_weight (a) != pango_font_description_get_weight (b))
745     return pango_font_description_get_weight (a) - pango_font_description_get_weight (b);
746
747   if (pango_font_description_get_style (a) != pango_font_description_get_style (b))
748     return pango_font_description_get_style (a) - pango_font_description_get_style (b);
749   
750   if (pango_font_description_get_stretch (a) != pango_font_description_get_stretch (b))
751     return pango_font_description_get_stretch (a) - pango_font_description_get_stretch (b);
752
753   if (pango_font_description_get_variant (a) != pango_font_description_get_variant (b))
754     return pango_font_description_get_variant (a) - pango_font_description_get_variant (b);
755
756   return 0;
757 }
758
759 static int
760 faces_sort_func (const void *a, const void *b)
761 {
762   PangoFontDescription *desc_a = pango_font_face_describe (*(PangoFontFace **)a);
763   PangoFontDescription *desc_b = pango_font_face_describe (*(PangoFontFace **)b);
764   
765   int ord = compare_font_descriptions (desc_a, desc_b);
766
767   pango_font_description_free (desc_a);
768   pango_font_description_free (desc_b);
769
770   return ord;
771 }
772
773 static gboolean
774 font_description_style_equal (const PangoFontDescription *a,
775                               const PangoFontDescription *b)
776 {
777   return (pango_font_description_get_weight (a) == pango_font_description_get_weight (b) &&
778           pango_font_description_get_style (a) == pango_font_description_get_style (b) &&
779           pango_font_description_get_stretch (a) == pango_font_description_get_stretch (b) &&
780           pango_font_description_get_variant (a) == pango_font_description_get_variant (b));
781 }
782
783 /* This fills the font style list with all the possible style combinations
784    for the current font family. */
785 static void
786 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
787 {
788   gint n_faces, i;
789   PangoFontFace **faces;
790   PangoFontDescription *old_desc;
791   GtkListStore *model;
792   GtkTreeIter match_row;
793   PangoFontFace *match_face = NULL;
794   
795   model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list)));
796   
797   if (fontsel->face)
798     old_desc = pango_font_face_describe (fontsel->face);
799   else
800     old_desc= NULL;
801
802   pango_font_family_list_faces (fontsel->family, &faces, &n_faces);
803   qsort (faces, n_faces, sizeof (PangoFontFace *), faces_sort_func);
804
805   gtk_list_store_clear (model);
806
807   for (i=0; i < n_faces; i++)
808     {
809       GtkTreeIter iter;
810       const gchar *str = pango_font_face_get_face_name (faces[i]);
811
812       gtk_list_store_append (model, &iter);
813       gtk_list_store_set (model, &iter,
814                           FACE_COLUMN, faces[i],
815                           FACE_NAME_COLUMN, str,
816                           -1);
817
818       if (i == 0)
819         {
820           match_row = iter;
821           match_face = faces[i];
822         }
823       else if (old_desc)
824         {
825           PangoFontDescription *tmp_desc = pango_font_face_describe (faces[i]);
826           
827           if (font_description_style_equal (tmp_desc, old_desc))
828             {
829               match_row = iter;
830               match_face = faces[i];
831             }
832       
833           pango_font_description_free (tmp_desc);
834         }
835     }
836
837   if (old_desc)
838     pango_font_description_free (old_desc);
839
840   fontsel->face = match_face;
841   if (match_face)
842     {
843 #ifdef INCLUDE_FONT_ENTRIES
844       const gchar *str = pango_font_face_get_face_name (fontsel->face);
845
846       gtk_entry_set_text (GTK_ENTRY (fontsel->font_style_entry), str);
847 #endif      
848       set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_row);
849     }
850
851   g_free (faces);
852 }
853
854 /* This selects a style when the user selects a font. It just uses the first
855    available style at present. I was thinking of trying to maintain the
856    selected style, e.g. bold italic, when the user selects different fonts.
857    However, the interface is so easy to use now I'm not sure it's worth it.
858    Note: This will load a font. */
859 static void
860 gtk_font_selection_select_best_style (GtkFontSelection *fontsel,
861                                       gboolean          use_first)
862 {
863   GtkTreeIter iter;
864   GtkTreeModel *model;
865
866   model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
867
868   if (gtk_tree_model_get_iter_first (model, &iter))
869     {
870       set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &iter);
871       scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
872     }
873
874   gtk_font_selection_show_available_sizes (fontsel, FALSE);
875   gtk_font_selection_select_best_size (fontsel);
876 }
877
878
879 /* This is called when a style is selected in the list. */
880 static void
881 gtk_font_selection_select_style (GtkTreeSelection *selection,
882                                  gpointer          data)
883 {
884   GtkFontSelection *fontsel = GTK_FONT_SELECTION (data);
885   GtkTreeModel *model;
886   GtkTreeIter iter;
887   
888   if (gtk_tree_selection_get_selected (selection, &model, &iter))
889     {
890       PangoFontFace *face;
891       
892       gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
893       fontsel->face = face;
894
895       g_object_unref (face);
896     }
897
898   gtk_font_selection_show_available_sizes (fontsel, FALSE);
899   gtk_font_selection_select_best_size (fontsel);
900 }
901
902 static void
903 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel,
904                                          gboolean          first_time)
905 {
906   gint i;
907   GtkListStore *model;
908   gchar buffer[128];
909   gchar *p;
910       
911   model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->size_list)));
912
913   /* Insert the standard font sizes */
914   if (first_time)
915     {
916       gtk_list_store_clear (model);
917
918       for (i = 0; i < G_N_ELEMENTS (font_sizes); i++)
919         {
920           GtkTreeIter iter;
921           
922           gtk_list_store_append (model, &iter);
923           gtk_list_store_set (model, &iter, SIZE_COLUMN, font_sizes[i], -1);
924           
925           if (font_sizes[i] * PANGO_SCALE == fontsel->size)
926             set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
927         }
928     }
929   else
930     {
931       GtkTreeIter iter;
932       gboolean found = FALSE;
933       
934       gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
935       for (i = 0; i < G_N_ELEMENTS (font_sizes) && !found; i++)
936         {
937           if (font_sizes[i] * PANGO_SCALE == fontsel->size)
938             {
939               set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
940               found = TRUE;
941             }
942
943           gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter);
944         }
945
946       if (!found)
947         {
948           GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
949           gtk_tree_selection_unselect_all (selection);
950         }
951     }
952
953   /* Set the entry to the new size, rounding to 1 digit,
954    * trimming of trailing 0's and a trailing period
955    */
956   g_snprintf (buffer, sizeof (buffer), "%.1f", fontsel->size / (1.0 * PANGO_SCALE));
957   if (strchr (buffer, '.'))
958     {
959       p = buffer + strlen (buffer) - 1;
960       while (*p == '0')
961         p--;
962       if (*p == '.')
963         p--;
964       p[1] = '\0';
965     }
966
967   /* Compare, to avoid moving the cursor unecessarily */
968   if (strcmp (gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry)), buffer) != 0)
969     gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
970 }
971
972 static void
973 gtk_font_selection_select_best_size (GtkFontSelection *fontsel)
974 {
975   gtk_font_selection_load_font (fontsel);  
976 }
977
978 static void
979 gtk_font_selection_set_size (GtkFontSelection *fontsel,
980                              gint              new_size)
981 {
982   if (fontsel->size != new_size)
983     {
984       fontsel->size = new_size;
985
986       gtk_font_selection_show_available_sizes (fontsel, FALSE);      
987       gtk_font_selection_load_font (fontsel);
988     }
989 }
990
991 /* If the user hits return in the font size entry, we change to the new font
992    size. */
993 static void
994 gtk_font_selection_size_activate (GtkWidget   *w,
995                                   gpointer     data)
996 {
997   GtkFontSelection *fontsel;
998   gint new_size;
999   const gchar *text;
1000   
1001   fontsel = GTK_FONT_SELECTION (data);
1002
1003   text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1004   new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);
1005
1006   if (fontsel->size != new_size)
1007     gtk_font_selection_set_size (fontsel, new_size);
1008   else 
1009     list_row_activated (w);
1010 }
1011
1012 static gboolean
1013 gtk_font_selection_size_focus_out (GtkWidget     *w,
1014                                    GdkEventFocus *event,
1015                                    gpointer       data)
1016 {
1017   GtkFontSelection *fontsel;
1018   gint new_size;
1019   const gchar *text;
1020   
1021   fontsel = GTK_FONT_SELECTION (data);
1022
1023   text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1024   new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);
1025
1026   gtk_font_selection_set_size (fontsel, new_size);
1027   
1028   return TRUE;
1029 }
1030
1031 /* This is called when a size is selected in the list. */
1032 static void
1033 gtk_font_selection_select_size (GtkTreeSelection *selection,
1034                                 gpointer          data)
1035 {
1036   GtkFontSelection *fontsel;
1037   GtkTreeModel *model;
1038   GtkTreeIter iter;
1039   gint new_size;
1040   
1041   fontsel = GTK_FONT_SELECTION (data);
1042   
1043   if (gtk_tree_selection_get_selected (selection, &model, &iter))
1044     {
1045       gtk_tree_model_get (model, &iter, SIZE_COLUMN, &new_size, -1);
1046       gtk_font_selection_set_size (fontsel, new_size * PANGO_SCALE);
1047     }
1048 }
1049
1050 static void
1051 gtk_font_selection_load_font (GtkFontSelection *fontsel)
1052 {
1053   if (fontsel->font)
1054     gdk_font_unref (fontsel->font);
1055   fontsel->font = NULL;
1056
1057   gtk_font_selection_update_preview (fontsel);
1058 }
1059
1060 static PangoFontDescription *
1061 gtk_font_selection_get_font_description (GtkFontSelection *fontsel)
1062 {
1063   PangoFontDescription *font_desc;
1064
1065   if (fontsel->face)
1066     {
1067       font_desc = pango_font_face_describe (fontsel->face);
1068       pango_font_description_set_size (font_desc, fontsel->size);
1069     }
1070   else
1071     font_desc = pango_font_description_from_string (DEFAULT_FONT_NAME);
1072
1073   return font_desc;
1074 }
1075
1076 /* This sets the font in the preview entry to the selected font, and tries to
1077    make sure that the preview entry is a reasonable size, i.e. so that the
1078    text can be seen with a bit of space to spare. But it tries to avoid
1079    resizing the entry every time the font changes.
1080    This also used to shrink the preview if the font size was decreased, but
1081    that made it awkward if the user wanted to resize the window themself. */
1082 static void
1083 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1084 {
1085   GtkRcStyle *rc_style;
1086   gint new_height;
1087   GtkRequisition old_requisition;
1088   GtkWidget *preview_entry = fontsel->preview_entry;
1089   const gchar *text;
1090
1091   gtk_widget_get_child_requisition (preview_entry, &old_requisition);
1092   
1093   rc_style = gtk_rc_style_new ();
1094   rc_style->font_desc = gtk_font_selection_get_font_description (fontsel);
1095   
1096   gtk_widget_modify_style (preview_entry, rc_style);
1097   g_object_unref (rc_style);
1098
1099   gtk_widget_size_request (preview_entry, NULL);
1100   
1101   /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1102   new_height = CLAMP (preview_entry->requisition.height, INITIAL_PREVIEW_HEIGHT, MAX_PREVIEW_HEIGHT);
1103
1104   if (new_height > old_requisition.height || new_height < old_requisition.height - 30)
1105     gtk_widget_set_size_request (preview_entry, -1, new_height);
1106   
1107   /* This sets the preview text, if it hasn't been set already. */
1108   text = gtk_entry_get_text (GTK_ENTRY (preview_entry));
1109   if (strlen (text) == 0)
1110     gtk_entry_set_text (GTK_ENTRY (preview_entry), _(PREVIEW_TEXT));
1111   gtk_editable_set_position (GTK_EDITABLE (preview_entry), 0);
1112 }
1113
1114 static GdkFont*
1115 gtk_font_selection_get_font_internal (GtkFontSelection *fontsel)
1116 {
1117   if (!fontsel->font)
1118     {
1119       PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1120       fontsel->font = gdk_font_from_description_for_display (gtk_widget_get_display (GTK_WIDGET (fontsel)), font_desc);
1121       pango_font_description_free (font_desc);
1122     }
1123   
1124   return fontsel->font;
1125 }
1126
1127
1128 /*****************************************************************************
1129  * These functions are the main public interface for getting/setting the font.
1130  *****************************************************************************/
1131
1132 /**
1133  * gtk_font_selection_get_family_list:
1134  * @fontsel: a #GtkFontSelection
1135  *
1136  * This returns the #GtkTreeView that lists font families, for
1137  * example, 'Sans', 'Serif', etc.
1138  * 
1139  * Return value: A #GtkWidget that is part of @fontsel
1140  *
1141  * Since: 2.14
1142  */
1143 GtkWidget *
1144 gtk_font_selection_get_family_list (GtkFontSelection *fontsel)
1145 {
1146   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1147   
1148   return fontsel->family_list;
1149 }
1150
1151 /**
1152  * gtk_font_selection_get_face_list:
1153  * @fontsel: a #GtkFontSelection
1154  *
1155  * This returns the #GtkTreeView which lists all styles available for
1156  * the selected font. For example, 'Regular', 'Bold', etc.
1157  * 
1158  * Return value: A #GtkWidget that is part of @fontsel
1159  *
1160  * Since: 2.14
1161  */
1162 GtkWidget *
1163 gtk_font_selection_get_face_list (GtkFontSelection *fontsel)
1164 {
1165   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1166   
1167   return fontsel->face_list;
1168 }
1169
1170 /**
1171  * gtk_font_selection_get_size_entry:
1172  * @fontsel: a #GtkFontSelection
1173  *
1174  * This returns the #GtkEntry used to allow the user to edit the font
1175  * number manually instead of selecting it from the list of font sizes. 
1176  * 
1177  * Return value: A #GtkWidget that is part of @fontsel
1178  *
1179  * Since: 2.14
1180  */
1181 GtkWidget *
1182 gtk_font_selection_get_size_entry (GtkFontSelection *fontsel)
1183 {
1184   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1185   
1186   return fontsel->size_entry;
1187 }
1188
1189 /**
1190  * gtk_font_selection_get_size_list:
1191  * @fontsel: a #GtkFontSelection
1192  *
1193  * This returns the #GtkTreeeView used to list font sizes. 
1194  * 
1195  * Return value: A #GtkWidget that is part of @fontsel
1196  *
1197  * Since: 2.14
1198  */
1199 GtkWidget *
1200 gtk_font_selection_get_size_list (GtkFontSelection *fontsel)
1201 {
1202   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1203   
1204   return fontsel->size_list;
1205 }
1206
1207 /**
1208  * gtk_font_selection_get_preview_entry:
1209  * @fontsel: a #GtkFontSelection
1210  * 
1211  * This returns the #GtkEntry used to display the font as a preview.
1212  *
1213  * Return value: A #GtkWidget that is part of @fontsel
1214  *
1215  * Since: 2.14
1216  */
1217 GtkWidget *
1218 gtk_font_selection_get_preview_entry (GtkFontSelection *fontsel)
1219 {
1220   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1221   
1222   return fontsel->preview_entry;
1223 }
1224
1225 /**
1226  * gtk_font_selection_get_family:
1227  * @fontsel: a #GtkFontSelection
1228  * 
1229  * Gets the #PangoFontFamily representing the selected font family.
1230  *
1231  * Return value: A #PangoFontFamily representing the selected font
1232  *     family. Font families are a collection of font faces. The 
1233  *     returned object is owned by @fontsel and must not be modified 
1234  *     or freed.
1235  *
1236  * Since: 2.14
1237  */
1238 PangoFontFamily *
1239 gtk_font_selection_get_family (GtkFontSelection *fontsel)
1240 {
1241   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1242   
1243   return fontsel->family;
1244 }
1245
1246 /**
1247  * gtk_font_selection_get_face:
1248  * @fontsel: a #GtkFontSelection
1249  * 
1250  * Gets the #PangoFontFace representing the selected font group
1251  * details (i.e. family, slant, weight, width, etc).   
1252  *
1253  * Return value: A #PangoFontFace representing the selected font 
1254  *     group details. The returned object is owned by @fontsel and
1255  *     must not be modified or freed. 
1256  *
1257  * Since: 2.14
1258  */
1259 PangoFontFace *
1260 gtk_font_selection_get_face (GtkFontSelection *fontsel)
1261 {
1262   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1263   
1264   return fontsel->face;
1265 }
1266
1267 /**
1268  * gtk_font_selection_get_size:
1269  * @fontsel: a #GtkFontSelection
1270  * 
1271  * The selected font size.
1272  *
1273  * Return value: A n integer representing the selected font size, 
1274  *     or -1 if no font size is selected.
1275  *
1276  * Since: 2.14
1277  **/
1278 gint
1279 gtk_font_selection_get_size (GtkFontSelection *fontsel)
1280 {
1281   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), -1);
1282   
1283   return fontsel->size;
1284 }
1285
1286 /**
1287  * gtk_font_selection_get_font:
1288  * @fontsel: a #GtkFontSelection
1289  *
1290  * Gets the currently-selected font.
1291  * 
1292  * Return value: A #GdkFont.
1293  *
1294  * Deprecated: 2.0: Use gtk_font_selection_get_font_name() instead.
1295  */
1296 GdkFont *
1297 gtk_font_selection_get_font (GtkFontSelection *fontsel)
1298 {
1299   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1300
1301   return gtk_font_selection_get_font_internal (fontsel);
1302 }
1303
1304 /**
1305  * gtk_font_selection_get_font_name:
1306  * @fontsel: a #GtkFontSelection
1307  * 
1308  * Gets the currently-selected font name. 
1309  *
1310  * Note that this can be a different string than what you set with 
1311  * gtk_font_selection_set_font_name(), as the font selection widget may 
1312  * normalize font names and thus return a string with a different structure. 
1313  * For example, "Helvetica Italic Bold 12" could be normalized to 
1314  * "Helvetica Bold Italic 12". Use pango_font_description_equal()
1315  * if you want to compare two font descriptions.
1316  * 
1317  * Return value: A string with the name of the current font, or %NULL if 
1318  *     no font is selected. You must free this string with g_free().
1319  */
1320 gchar *
1321 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
1322 {
1323   gchar *result;
1324   
1325   PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1326   result = pango_font_description_to_string (font_desc);
1327   pango_font_description_free (font_desc);
1328
1329   return result;
1330 }
1331
1332
1333 /* This sets the current font, selecting the appropriate list rows.
1334    First we check the fontname is valid and try to find the font family
1335    - i.e. the name in the main list. If we can't find that, then just return.
1336    Next we try to set each of the properties according to the fontname.
1337    Finally we select the font family & style in the lists. */
1338
1339 /**
1340  * gtk_font_selection_set_font_name:
1341  * @fontsel: a #GtkFontSelection
1342  * @fontname: a font name like "Helvetica 12" or "Times Bold 18"
1343  * 
1344  * Sets the currently-selected font. 
1345  *
1346  * Note that the @fontsel needs to know the screen in which it will appear 
1347  * for this to work; this can be guaranteed by simply making sure that the 
1348  * @fontsel is inserted in a toplevel window before you call this function.
1349  * 
1350  * Return value: %TRUE if the font could be set successfully; %FALSE if no 
1351  *     such font exists or if the @fontsel doesn't belong to a particular 
1352  *     screen yet.
1353  */
1354 gboolean
1355 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
1356                                   const gchar      *fontname)
1357 {
1358   PangoFontFamily *new_family = NULL;
1359   PangoFontFace *new_face = NULL;
1360   PangoFontFace *fallback_face = NULL;
1361   PangoFontDescription *new_desc;
1362   GtkTreeModel *model;
1363   GtkTreeIter iter;
1364   GtkTreeIter match_iter;
1365   gboolean valid;
1366   const gchar *new_family_name;
1367   
1368   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
1369
1370   if (!gtk_widget_has_screen (GTK_WIDGET (fontsel)))
1371     return FALSE;
1372
1373   new_desc = pango_font_description_from_string (fontname);
1374   new_family_name = pango_font_description_get_family (new_desc);
1375
1376   if (!new_family_name)
1377     return FALSE;
1378
1379   /* Check to make sure that this is in the list of allowed fonts 
1380    */
1381   model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list));
1382   for (valid = gtk_tree_model_get_iter_first (model, &iter);
1383        valid;
1384        valid = gtk_tree_model_iter_next (model, &iter))
1385     {
1386       PangoFontFamily *family;
1387       
1388       gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
1389       
1390       if (g_ascii_strcasecmp (pango_font_family_get_name (family),
1391                               new_family_name) == 0)
1392         new_family = family;
1393       
1394       g_object_unref (family);
1395       
1396       if (new_family)
1397         break;
1398     }
1399
1400   if (!new_family)
1401     return FALSE;
1402
1403   fontsel->family = new_family;
1404   set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &iter);
1405   gtk_font_selection_show_available_styles (fontsel);
1406
1407   model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
1408   for (valid = gtk_tree_model_get_iter_first (model, &iter);
1409        valid;
1410        valid = gtk_tree_model_iter_next (model, &iter))
1411     {
1412       PangoFontFace *face;
1413       PangoFontDescription *tmp_desc;
1414       
1415       gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
1416       tmp_desc = pango_font_face_describe (face);
1417       
1418       if (font_description_style_equal (tmp_desc, new_desc))
1419         new_face = face;
1420       
1421       if (!fallback_face)
1422         {
1423           fallback_face = face;
1424           match_iter = iter;
1425         }
1426       
1427       pango_font_description_free (tmp_desc);
1428       g_object_unref (face);
1429       
1430       if (new_face)
1431         {
1432           match_iter = iter;
1433           break;
1434         }
1435     }
1436
1437   if (!new_face)
1438     new_face = fallback_face;
1439
1440   fontsel->face = new_face;
1441   set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_iter);  
1442
1443   gtk_font_selection_set_size (fontsel, pango_font_description_get_size (new_desc));
1444   
1445   g_object_freeze_notify (G_OBJECT (fontsel));
1446   g_object_notify (G_OBJECT (fontsel), "font-name");
1447   g_object_notify (G_OBJECT (fontsel), "font");
1448   g_object_thaw_notify (G_OBJECT (fontsel));
1449
1450   pango_font_description_free (new_desc);
1451
1452   return TRUE;
1453 }
1454
1455 /**
1456  * gtk_font_selection_get_preview_text:
1457  * @fontsel: a #GtkFontSelection
1458  *
1459  * Gets the text displayed in the preview area.
1460  * 
1461  * Return value: the text displayed in the preview area. 
1462  *     This string is owned by the widget and should not be 
1463  *     modified or freed 
1464  */
1465 G_CONST_RETURN gchar*
1466 gtk_font_selection_get_preview_text (GtkFontSelection *fontsel)
1467 {
1468   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1469
1470   return gtk_entry_get_text (GTK_ENTRY (fontsel->preview_entry));
1471 }
1472
1473
1474 /**
1475  * gtk_font_selection_set_preview_text:
1476  * @fontsel: a #GtkFontSelection
1477  * @text: the text to display in the preview area 
1478  *
1479  * Sets the text displayed in the preview area.
1480  * The @text is used to show how the selected font looks.
1481  */
1482 void
1483 gtk_font_selection_set_preview_text  (GtkFontSelection *fontsel,
1484                                       const gchar      *text)
1485 {
1486   g_return_if_fail (GTK_IS_FONT_SELECTION (fontsel));
1487   g_return_if_fail (text != NULL);
1488
1489   gtk_entry_set_text (GTK_ENTRY (fontsel->preview_entry), text);
1490 }
1491
1492 /*****************************************************************************
1493  * GtkFontSelectionDialog
1494  *****************************************************************************/
1495
1496 static void gtk_font_selection_dialog_buildable_interface_init     (GtkBuildableIface *iface);
1497 static GObject * gtk_font_selection_dialog_buildable_get_internal_child (GtkBuildable *buildable,
1498                                                                           GtkBuilder   *builder,
1499                                                                           const gchar  *childname);
1500
1501 G_DEFINE_TYPE_WITH_CODE (GtkFontSelectionDialog, gtk_font_selection_dialog,
1502                          GTK_TYPE_DIALOG,
1503                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
1504                                                 gtk_font_selection_dialog_buildable_interface_init))
1505
1506 static GtkBuildableIface *parent_buildable_iface;
1507
1508 static void
1509 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
1510 {
1511 }
1512
1513 static void
1514 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
1515 {
1516   GtkDialog *dialog = GTK_DIALOG (fontseldiag);
1517   
1518   gtk_dialog_set_has_separator (dialog, FALSE);
1519   gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
1520   gtk_box_set_spacing (GTK_BOX (dialog->vbox), 2); /* 2 * 5 + 2 = 12 */
1521   gtk_container_set_border_width (GTK_CONTAINER (dialog->action_area), 5);
1522   gtk_box_set_spacing (GTK_BOX (dialog->action_area), 6);
1523
1524   gtk_widget_push_composite_child ();
1525
1526   gtk_window_set_resizable (GTK_WINDOW (fontseldiag), TRUE);
1527   
1528   fontseldiag->main_vbox = dialog->vbox;
1529   
1530   fontseldiag->fontsel = gtk_font_selection_new ();
1531   gtk_container_set_border_width (GTK_CONTAINER (fontseldiag->fontsel), 5);
1532   gtk_widget_show (fontseldiag->fontsel);
1533   gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
1534                       fontseldiag->fontsel, TRUE, TRUE, 0);
1535   
1536   /* Create the action area */
1537   fontseldiag->action_area = dialog->action_area;
1538
1539   fontseldiag->cancel_button = gtk_dialog_add_button (dialog,
1540                                                       GTK_STOCK_CANCEL,
1541                                                       GTK_RESPONSE_CANCEL);
1542
1543   fontseldiag->apply_button = gtk_dialog_add_button (dialog,
1544                                                      GTK_STOCK_APPLY,
1545                                                      GTK_RESPONSE_APPLY);
1546   gtk_widget_hide (fontseldiag->apply_button);
1547
1548   fontseldiag->ok_button = gtk_dialog_add_button (dialog,
1549                                                   GTK_STOCK_OK,
1550                                                   GTK_RESPONSE_OK);
1551   gtk_widget_grab_default (fontseldiag->ok_button);
1552   
1553   gtk_dialog_set_alternative_button_order (GTK_DIALOG (fontseldiag),
1554                                            GTK_RESPONSE_OK,
1555                                            GTK_RESPONSE_APPLY,
1556                                            GTK_RESPONSE_CANCEL,
1557                                            -1);
1558
1559   gtk_window_set_title (GTK_WINDOW (fontseldiag),
1560                         _("Font Selection"));
1561
1562   gtk_widget_pop_composite_child ();
1563
1564   _gtk_dialog_set_ignore_separator (dialog, TRUE);
1565 }
1566
1567 /**
1568  * gtk_font_selection_dialog_new:
1569  * @title: the title of the dialog window 
1570  *
1571  * Creates a new #GtkFontSelectionDialog.
1572  *
1573  * Return value: a new #GtkFontSelectionDialog
1574  */
1575 GtkWidget*
1576 gtk_font_selection_dialog_new (const gchar *title)
1577 {
1578   GtkFontSelectionDialog *fontseldiag;
1579   
1580   fontseldiag = g_object_new (GTK_TYPE_FONT_SELECTION_DIALOG, NULL);
1581
1582   if (title)
1583     gtk_window_set_title (GTK_WINDOW (fontseldiag), title);
1584   
1585   return GTK_WIDGET (fontseldiag);
1586 }
1587
1588 /**
1589  * gtk_font_selection_dialog_get_ok_button:
1590  * @fsd: a #GtkFontSelectionDialog
1591  *
1592  * Gets the 'OK' button.
1593  *
1594  * Return value: the #GtkWidget used in the dialog for the 'OK' button.
1595  *
1596  * Since: 2.14
1597  */
1598 GtkWidget *
1599 gtk_font_selection_dialog_get_ok_button (GtkFontSelectionDialog *fsd)
1600 {
1601   g_return_val_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd), NULL);
1602
1603   return fsd->ok_button;
1604 }
1605
1606 /**
1607  * gtk_font_selection_dialog_get_apply_button:
1608  * @fsd: a #GtkFontSelectionDialog
1609  *
1610  * Obtains a button. The button doesn't have any function.
1611  *
1612  * Return value: a #GtkWidget
1613  *
1614  * Since: 2.14
1615  *
1616  * Deprecated: 2.16: Don't use this function.
1617  */
1618 GtkWidget *
1619 gtk_font_selection_dialog_get_apply_button (GtkFontSelectionDialog *fsd)
1620 {
1621   g_return_val_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd), NULL);
1622
1623   return fsd->apply_button;
1624 }
1625
1626 /**
1627  * gtk_font_selection_dialog_get_cancel_button:
1628  * @fsd: a #GtkFontSelectionDialog
1629  *
1630  * Gets the 'Cancel' button.
1631  *
1632  * Return value: the #GtkWidget used in the dialog for the 'Cancel' button.
1633  *
1634  * Since: 2.14
1635  */
1636 GtkWidget *
1637 gtk_font_selection_dialog_get_cancel_button (GtkFontSelectionDialog *fsd)
1638 {
1639   g_return_val_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd), NULL);
1640
1641   return fsd->cancel_button;
1642 }
1643
1644 static void
1645 gtk_font_selection_dialog_buildable_interface_init (GtkBuildableIface *iface)
1646 {
1647   parent_buildable_iface = g_type_interface_peek_parent (iface);
1648   iface->get_internal_child = gtk_font_selection_dialog_buildable_get_internal_child;
1649 }
1650
1651 static GObject *
1652 gtk_font_selection_dialog_buildable_get_internal_child (GtkBuildable *buildable,
1653                                                         GtkBuilder   *builder,
1654                                                         const gchar  *childname)
1655 {
1656     if (strcmp(childname, "ok_button") == 0)
1657         return G_OBJECT (GTK_FONT_SELECTION_DIALOG(buildable)->ok_button);
1658     else if (strcmp(childname, "cancel_button") == 0)
1659         return G_OBJECT (GTK_FONT_SELECTION_DIALOG (buildable)->cancel_button);
1660     else if (strcmp(childname, "apply_button") == 0)
1661         return G_OBJECT (GTK_FONT_SELECTION_DIALOG(buildable)->apply_button);
1662     else if (strcmp(childname, "font_selection") == 0)
1663         return G_OBJECT (GTK_FONT_SELECTION_DIALOG(buildable)->fontsel);
1664
1665     return parent_buildable_iface->get_internal_child (buildable, builder, childname);
1666 }
1667
1668 /**
1669  * gtk_font_selection_dialog_get_font_name:
1670  * @fsd: a #GtkFontSelectionDialog
1671  * 
1672  * Gets the currently-selected font name.
1673  *
1674  * Note that this can be a different string than what you set with 
1675  * gtk_font_selection_dialog_set_font_name(), as the font selection widget
1676  * may normalize font names and thus return a string with a different 
1677  * structure. For example, "Helvetica Italic Bold 12" could be normalized 
1678  * to "Helvetica Bold Italic 12".  Use pango_font_description_equal()
1679  * if you want to compare two font descriptions.
1680  * 
1681  * Return value: A string with the name of the current font, or %NULL if no 
1682  *     font is selected. You must free this string with g_free().
1683  */
1684 gchar*
1685 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
1686 {
1687   g_return_val_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd), NULL);
1688
1689   return gtk_font_selection_get_font_name (GTK_FONT_SELECTION (fsd->fontsel));
1690 }
1691
1692 /**
1693  * gtk_font_selection_dialog_get_font:
1694  * @fsd: a #GtkFontSelectionDialog
1695  *
1696  * Gets the currently-selected font.
1697  *
1698  * Return value: the #GdkFont from the #GtkFontSelection for the
1699  *     currently selected font in the dialog, or %NULL if no font is selected
1700  *
1701  * Deprecated: 2.0: Use gtk_font_selection_dialog_get_font_name() instead.
1702  */
1703 GdkFont*
1704 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
1705 {
1706   g_return_val_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd), NULL);
1707
1708   return gtk_font_selection_get_font_internal (GTK_FONT_SELECTION (fsd->fontsel));
1709 }
1710
1711 /**
1712  * gtk_font_selection_dialog_set_font_name:
1713  * @fsd: a #GtkFontSelectionDialog
1714  * @fontname: a font name like "Helvetica 12" or "Times Bold 18"
1715  *
1716  * Sets the currently selected font. 
1717  * 
1718  * Return value: %TRUE if the font selected in @fsd is now the
1719  *     @fontname specified, %FALSE otherwise. 
1720  */
1721 gboolean
1722 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
1723                                          const gchar            *fontname)
1724 {
1725   g_return_val_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd), FALSE);
1726   g_return_val_if_fail (fontname, FALSE);
1727
1728   return gtk_font_selection_set_font_name (GTK_FONT_SELECTION (fsd->fontsel), fontname);
1729 }
1730
1731 /**
1732  * gtk_font_selection_dialog_get_preview_text:
1733  * @fsd: a #GtkFontSelectionDialog
1734  *
1735  * Gets the text displayed in the preview area.
1736  * 
1737  * Return value: the text displayed in the preview area. 
1738  *     This string is owned by the widget and should not be 
1739  *     modified or freed 
1740  */
1741 G_CONST_RETURN gchar*
1742 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
1743 {
1744   g_return_val_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd), NULL);
1745
1746   return gtk_font_selection_get_preview_text (GTK_FONT_SELECTION (fsd->fontsel));
1747 }
1748
1749 /**
1750  * gtk_font_selection_dialog_set_preview_text:
1751  * @fsd: a #GtkFontSelectionDialog
1752  * @text: the text to display in the preview area
1753  *
1754  * Sets the text displayed in the preview area. 
1755  */
1756 void
1757 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
1758                                             const gchar            *text)
1759 {
1760   g_return_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd));
1761   g_return_if_fail (text != NULL);
1762
1763   gtk_font_selection_set_preview_text (GTK_FONT_SELECTION (fsd->fontsel), text);
1764 }
1765
1766 #define __GTK_FONTSEL_C__
1767 #include "gtkaliasdef.c"