]> Pileus Git - ~andy/gtk/blob - gtk/gtkfontsel.c
Revert name change
[~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   g_object_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 /**
1126  * gtk_font_selection_get_family_entry:
1127  * @fontsel: a #GtkFontSelection
1128  *
1129  * This returns the #GtkEntry that allows the user to manually enter
1130  * the font family they want to use.
1131  * 
1132  * Return value: A #GtkWidget.
1133  *
1134  * Since: 2.14
1135  **/
1136 GtkWidget *
1137 gtk_font_selection_get_family_entry (GtkFontSelection *fontsel)
1138 {
1139   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1140   
1141   return fontsel->font_entry;
1142 }
1143
1144 /**
1145  * gtk_font_selection_get_family_list:
1146  * @fontsel: a #GtkFontSelection
1147  *
1148  * This returns the #GtkTreeView that lists font families, for
1149  * example, 'Sans', 'Serif', etc.
1150  * 
1151  * Return value: A #GtkWidget. 
1152  *
1153  * Since: 2.14
1154  **/
1155 GtkWidget *
1156 gtk_font_selection_get_family_list (GtkFontSelection *fontsel)
1157 {
1158   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1159   
1160   return fontsel->family_list;
1161 }
1162
1163 /**
1164  * gtk_font_selection_get_face_entry:
1165  * @fontsel: a #GtkFontSelection
1166  *
1167  * This returns the #GtkEntry responsible for allowing manual
1168  * configuration of the font style.
1169  * 
1170  * Return value: A #GtkWidget. 
1171  *
1172  * Since: 2.14
1173  **/
1174 GtkWidget *
1175 gtk_font_selection_get_face_entry (GtkFontSelection *fontsel)
1176 {
1177   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1178   
1179   return fontsel->font_style_entry;
1180 }
1181
1182 /**
1183  * gtk_font_selection_get_face_list:
1184  * @fontsel: a #GtkFontSelection
1185  *
1186  * This returns the #GtkTreeView which lists all styles available for
1187  * the selected font. For example, 'Regular', 'Bold', etc.
1188  * 
1189  * Return value: A #GtkWidget. 
1190  *
1191  * Since: 2.14
1192  **/
1193 GtkWidget *
1194 gtk_font_selection_get_face_list (GtkFontSelection *fontsel)
1195 {
1196   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1197   
1198   return fontsel->face_list;
1199 }
1200
1201 /**
1202  * gtk_font_selection_get_size_entry:
1203  * @fontsel: a #GtkFontSelection
1204  *
1205  * This returns the #GtkEntry used to allow the user to edit the font
1206  * number manually instead of selecting it from the list of font sizes. 
1207  * 
1208  * Return value: A #GtkWidget. 
1209  *
1210  * Since: 2.14
1211  **/
1212 GtkWidget *
1213 gtk_font_selection_get_size_entry (GtkFontSelection *fontsel)
1214 {
1215   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1216   
1217   return fontsel->size_entry;
1218 }
1219
1220 /**
1221  * gtk_font_selection_get_size_list:
1222  * @fontsel: a #GtkFontSelection
1223  *
1224  * This returns the #GtkTreeeView used to list font sizes. 
1225  * 
1226  * Return value: A #GtkWidget. 
1227  *
1228  * Since: 2.14
1229  **/
1230 GtkWidget *
1231 gtk_font_selection_get_size_list (GtkFontSelection *fontsel)
1232 {
1233   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1234   
1235   return fontsel->size_list;
1236 }
1237
1238 /**
1239  * gtk_font_selection_get_preview_entry:
1240  * @fontsel: a #GtkFontSelection
1241  * 
1242  * This returns the #GtkEntry used to display the font as a preview.
1243  *
1244  * Return value: A #GtkWidget. 
1245  *
1246  * Since: 2.14
1247  **/
1248 GtkWidget *
1249 gtk_font_selection_get_preview_entry (GtkFontSelection *fontsel)
1250 {
1251   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1252   
1253   return fontsel->preview_entry;
1254 }
1255
1256 /**
1257  * gtk_font_selection_get_family:
1258  * @fontsel: a #GtkFontSelection
1259  * 
1260  * Return value: A #PangoFontFamily representing the selected font
1261  * family. Font families are a collection of font faces.
1262  *
1263  * Since: 2.14
1264  **/
1265 PangoFontFamily *
1266 gtk_font_selection_get_family (GtkFontSelection *fontsel)
1267 {
1268   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1269   
1270   return fontsel->family;
1271 }
1272
1273 /**
1274  * gtk_font_selection_get_face:
1275  * @fontsel: a #GtkFontSelection
1276  * 
1277  * Return value: A #PangoFontFace representing the selected font group
1278  * details (i.e. family, slant, weight, width, etc).   
1279  *
1280  * Since: 2.14
1281  **/
1282 PangoFontFace *
1283 gtk_font_selection_get_face (GtkFontSelection *fontsel)
1284 {
1285   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1286   
1287   return fontsel->face;
1288 }
1289
1290 /**
1291  * gtk_font_selection_get_size:
1292  * @fontsel: a #GtkFontSelection
1293  * 
1294  * Return value: A #gint representing the font size selected, or -1
1295  * if not.
1296  *
1297  * Since: 2.14
1298  **/
1299 gint
1300 gtk_font_selection_get_size (GtkFontSelection *fontsel)
1301 {
1302   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), -1);
1303   
1304   return fontsel->size;
1305 }
1306
1307 /**
1308  * gtk_font_selection_get_font:
1309  * @fontsel: a #GtkFontSelection
1310  * 
1311  * Return value: A #GdkFont.  
1312  **/
1313 GdkFont *
1314 gtk_font_selection_get_font (GtkFontSelection *fontsel)
1315 {
1316   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1317   
1318   return gtk_font_selection_get_font_internal (fontsel);
1319 }
1320
1321 /**
1322  * gtk_font_selection_get_font_name:
1323  * @fontsel: a #GtkFontSelection
1324  * 
1325  * Gets the currently-selected font name.  Note that this can be a different
1326  * string than what you set with gtk_font_selection_set_font_name(), as
1327  * the font selection widget may normalize font names and thus return a string
1328  * with a different structure.  For example, "Helvetica Italic Bold 12" could be
1329  * normalized to "Helvetica Bold Italic 12".  Use pango_font_description_equal()
1330  * if you want to compare two font descriptions.
1331  * 
1332  * Return value: A string with the name of the current font, or #NULL if no font
1333  * is selected.  You must free this string with g_free().
1334  **/
1335 gchar *
1336 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
1337 {
1338   gchar *result;
1339   
1340   PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1341   result = pango_font_description_to_string (font_desc);
1342   pango_font_description_free (font_desc);
1343
1344   return result;
1345 }
1346
1347
1348 /* This sets the current font, selecting the appropriate list rows.
1349    First we check the fontname is valid and try to find the font family
1350    - i.e. the name in the main list. If we can't find that, then just return.
1351    Next we try to set each of the properties according to the fontname.
1352    Finally we select the font family & style in the lists. */
1353
1354 /**
1355  * gtk_font_selection_set_font_name:
1356  * @fontsel: a #GtkFontSelection
1357  * @fontname: a font name like "Helvetica 12" or "Times Bold 18"
1358  * 
1359  * Sets the currently-selected font.  Note that the @fontsel needs to know the
1360  * screen in which it will appear for this to work; this can be guaranteed by
1361  * simply making sure that the @fontsel is inserted in a toplevel window before
1362  * you call this function.
1363  * 
1364  * Return value: #TRUE if the font could be set successfully; #FALSE if no such
1365  * font exists or if the @fontsel doesn't belong to a particular screen yet.
1366  **/
1367 gboolean
1368 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
1369                                   const gchar      *fontname)
1370 {
1371   PangoFontFamily *new_family = NULL;
1372   PangoFontFace *new_face = NULL;
1373   PangoFontFace *fallback_face = NULL;
1374   PangoFontDescription *new_desc;
1375   GtkTreeModel *model;
1376   GtkTreeIter iter;
1377   GtkTreeIter match_iter;
1378   gboolean valid;
1379   const gchar *new_family_name;
1380   
1381   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
1382   g_return_val_if_fail (gtk_widget_has_screen (GTK_WIDGET (fontsel)), FALSE);
1383   
1384   new_desc = pango_font_description_from_string (fontname);
1385   new_family_name = pango_font_description_get_family (new_desc);
1386
1387   if (!new_family_name)
1388     return FALSE;
1389
1390   /* Check to make sure that this is in the list of allowed fonts 
1391    */
1392   model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list));
1393   for (valid = gtk_tree_model_get_iter_first (model, &iter);
1394        valid;
1395        valid = gtk_tree_model_iter_next (model, &iter))
1396     {
1397       PangoFontFamily *family;
1398       
1399       gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
1400       
1401       if (g_ascii_strcasecmp (pango_font_family_get_name (family),
1402                               new_family_name) == 0)
1403         new_family = family;
1404       
1405       g_object_unref (family);
1406       
1407       if (new_family)
1408         break;
1409     }
1410
1411   if (!new_family)
1412     return FALSE;
1413
1414   fontsel->family = new_family;
1415   set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &iter);
1416   gtk_font_selection_show_available_styles (fontsel);
1417
1418   model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
1419   for (valid = gtk_tree_model_get_iter_first (model, &iter);
1420        valid;
1421        valid = gtk_tree_model_iter_next (model, &iter))
1422     {
1423       PangoFontFace *face;
1424       PangoFontDescription *tmp_desc;
1425       
1426       gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
1427       tmp_desc = pango_font_face_describe (face);
1428       
1429       if (font_description_style_equal (tmp_desc, new_desc))
1430         new_face = face;
1431       
1432       if (!fallback_face)
1433         {
1434           fallback_face = face;
1435           match_iter = iter;
1436         }
1437       
1438       pango_font_description_free (tmp_desc);
1439       g_object_unref (face);
1440       
1441       if (new_face)
1442         {
1443           match_iter = iter;
1444           break;
1445         }
1446     }
1447
1448   if (!new_face)
1449     new_face = fallback_face;
1450
1451   fontsel->face = new_face;
1452   set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_iter);  
1453
1454   gtk_font_selection_set_size (fontsel, pango_font_description_get_size (new_desc));
1455   
1456   g_object_freeze_notify (G_OBJECT (fontsel));
1457   g_object_notify (G_OBJECT (fontsel), "font-name");
1458   g_object_notify (G_OBJECT (fontsel), "font");
1459   g_object_thaw_notify (G_OBJECT (fontsel));
1460
1461   pango_font_description_free (new_desc);
1462
1463   return TRUE;
1464 }
1465
1466 /**
1467  * gtk_font_selection_get_preview_text:
1468  * @fontsel: a #GtkFontSelection
1469  *
1470  * The text returned is the preview text used to show how the selected
1471  * font looks.  
1472  * 
1473  * Return value: pointer to the preview text string. This string
1474  * points to internally allocated storage in the widget and must not
1475  * be freed, modified or stored. 
1476  **/
1477 G_CONST_RETURN gchar*
1478 gtk_font_selection_get_preview_text (GtkFontSelection *fontsel)
1479 {
1480   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1481
1482   return gtk_entry_get_text (GTK_ENTRY (fontsel->preview_entry));
1483 }
1484
1485
1486 /**
1487  * gtk_font_selection_set_preview_text:
1488  * @fontsel: a #GtkFontSelection
1489  * @text: a pointer to a string
1490  *
1491  * The @text is used to show how the selected font looks.
1492  **/
1493 void
1494 gtk_font_selection_set_preview_text  (GtkFontSelection *fontsel,
1495                                       const gchar      *text)
1496 {
1497   g_return_if_fail (GTK_IS_FONT_SELECTION (fontsel));
1498   g_return_if_fail (text != NULL);
1499
1500   gtk_entry_set_text (GTK_ENTRY (fontsel->preview_entry), text);
1501 }
1502
1503 /*****************************************************************************
1504  * GtkFontSelectionDialog
1505  *****************************************************************************/
1506
1507 static void gtk_font_selection_dialog_buildable_interface_init     (GtkBuildableIface *iface);
1508 static GObject * gtk_font_selection_dialog_buildable_get_internal_child (GtkBuildable *buildable,
1509                                                                           GtkBuilder   *builder,
1510                                                                           const gchar  *childname);
1511
1512 G_DEFINE_TYPE_WITH_CODE (GtkFontSelectionDialog, gtk_font_selection_dialog,
1513                          GTK_TYPE_DIALOG,
1514                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
1515                                                 gtk_font_selection_dialog_buildable_interface_init))
1516
1517 static GtkBuildableIface *parent_buildable_iface;
1518
1519 static void
1520 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
1521 {
1522 }
1523
1524 static void
1525 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
1526 {
1527   GtkDialog *dialog = GTK_DIALOG (fontseldiag);
1528   
1529   gtk_dialog_set_has_separator (dialog, FALSE);
1530   gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
1531   gtk_box_set_spacing (GTK_BOX (dialog->vbox), 2); /* 2 * 5 + 2 = 12 */
1532   gtk_container_set_border_width (GTK_CONTAINER (dialog->action_area), 5);
1533   gtk_box_set_spacing (GTK_BOX (dialog->action_area), 6);
1534
1535   gtk_widget_push_composite_child ();
1536
1537   gtk_window_set_resizable (GTK_WINDOW (fontseldiag), TRUE);
1538   
1539   fontseldiag->main_vbox = dialog->vbox;
1540   
1541   fontseldiag->fontsel = gtk_font_selection_new ();
1542   gtk_container_set_border_width (GTK_CONTAINER (fontseldiag->fontsel), 5);
1543   gtk_widget_show (fontseldiag->fontsel);
1544   gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
1545                       fontseldiag->fontsel, TRUE, TRUE, 0);
1546   
1547   /* Create the action area */
1548   fontseldiag->action_area = dialog->action_area;
1549
1550   fontseldiag->cancel_button = gtk_dialog_add_button (dialog,
1551                                                       GTK_STOCK_CANCEL,
1552                                                       GTK_RESPONSE_CANCEL);
1553
1554   fontseldiag->apply_button = gtk_dialog_add_button (dialog,
1555                                                      GTK_STOCK_APPLY,
1556                                                      GTK_RESPONSE_APPLY);
1557   gtk_widget_hide (fontseldiag->apply_button);
1558
1559   fontseldiag->ok_button = gtk_dialog_add_button (dialog,
1560                                                   GTK_STOCK_OK,
1561                                                   GTK_RESPONSE_OK);
1562   gtk_widget_grab_default (fontseldiag->ok_button);
1563   
1564   gtk_dialog_set_alternative_button_order (GTK_DIALOG (fontseldiag),
1565                                            GTK_RESPONSE_OK,
1566                                            GTK_RESPONSE_APPLY,
1567                                            GTK_RESPONSE_CANCEL,
1568                                            -1);
1569
1570   gtk_window_set_title (GTK_WINDOW (fontseldiag),
1571                         _("Font Selection"));
1572
1573   gtk_widget_pop_composite_child ();
1574
1575   _gtk_dialog_set_ignore_separator (dialog, TRUE);
1576 }
1577
1578 /**
1579  * gtk_font_selection_dialog_new:
1580  * @title: a pointer to a string
1581  *
1582  * The @title is used to set the title of the #GtkFontSelectionDialog
1583  * returned. This #GtkDialog is specifically catered with widgets for
1584  * selecting a font from those installed. 
1585  *
1586  * Return value: a new #GtkFontSelectionDialog.
1587  */
1588 GtkWidget*
1589 gtk_font_selection_dialog_new (const gchar *title)
1590 {
1591   GtkFontSelectionDialog *fontseldiag;
1592   
1593   fontseldiag = g_object_new (GTK_TYPE_FONT_SELECTION_DIALOG, NULL);
1594
1595   if (title)
1596     gtk_window_set_title (GTK_WINDOW (fontseldiag), title);
1597   
1598   return GTK_WIDGET (fontseldiag);
1599 }
1600
1601 /**
1602  * gtk_font_selection_dialog_get_ok_button:
1603  * @fsd: a #GtkFontSelectionDialog
1604  *
1605  * Return value: the #GtkWidget used in the dialog for the 'OK' button.
1606  *
1607  * Since: 2.14
1608  */
1609 GtkWidget *
1610 gtk_font_selection_dialog_get_ok_button (GtkFontSelectionDialog *fsd)
1611 {
1612   g_return_val_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd), NULL);
1613
1614   return fsd->ok_button;
1615 }
1616
1617 /**
1618  * gtk_font_selection_dialog_get_apply_button:
1619  * @fsd: a #GtkFontSelectionDialog
1620  *
1621  * Return value: the #GtkWidget used in the dialog for the 'Apply' button.
1622  *
1623  * Since: 2.14
1624  */
1625 GtkWidget *
1626 gtk_font_selection_dialog_get_apply_button (GtkFontSelectionDialog *fsd)
1627 {
1628   g_return_val_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd), NULL);
1629
1630   return fsd->apply_button;
1631 }
1632
1633 /**
1634  * gtk_font_selection_dialog_get_apply_button:
1635  * @fsd: a #GtkFontSelectionDialog
1636  *
1637  * Return value: the #GtkWidget used in the dialog for the 'Cancel' button.
1638  */
1639 GtkWidget *
1640 gtk_font_selection_dialog_get_cancel_button (GtkFontSelectionDialog *fsd)
1641 {
1642   g_return_val_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd), NULL);
1643
1644   return fsd->cancel_button;
1645 }
1646
1647 static void
1648 gtk_font_selection_dialog_buildable_interface_init (GtkBuildableIface *iface)
1649 {
1650   parent_buildable_iface = g_type_interface_peek_parent (iface);
1651   iface->get_internal_child = gtk_font_selection_dialog_buildable_get_internal_child;
1652 }
1653
1654 static GObject *
1655 gtk_font_selection_dialog_buildable_get_internal_child (GtkBuildable *buildable,
1656                                                         GtkBuilder   *builder,
1657                                                         const gchar  *childname)
1658 {
1659     if (strcmp(childname, "ok_button") == 0)
1660         return G_OBJECT (GTK_FONT_SELECTION_DIALOG(buildable)->ok_button);
1661     else if (strcmp(childname, "cancel_button") == 0)
1662         return G_OBJECT (GTK_FONT_SELECTION_DIALOG (buildable)->cancel_button);
1663     else if (strcmp(childname, "apply_button") == 0)
1664         return G_OBJECT (GTK_FONT_SELECTION_DIALOG(buildable)->apply_button);
1665     else if (strcmp(childname, "font_selection") == 0)
1666         return G_OBJECT (GTK_FONT_SELECTION_DIALOG(buildable)->fontsel);
1667
1668     return parent_buildable_iface->get_internal_child (buildable, builder, childname);
1669 }
1670
1671 /**
1672  * gtk_font_selection_dialog_get_font_name:
1673  * @fsd: a #GtkFontSelectionDialog
1674  * 
1675  * Gets the currently-selected font name.  Note that this can be a different
1676  * string than what you set with gtk_font_selection_dialog_set_font_name(), as
1677  * the font selection widget may normalize font names and thus return a string
1678  * with a different structure.  For example, "Helvetica Italic Bold 12" could be
1679  * normalized to "Helvetica Bold Italic 12".  Use pango_font_description_equal()
1680  * if you want to compare two font descriptions.
1681  * 
1682  * Return value: A string with the name of the current font, or #NULL if no font
1683  * is selected.  You must free this string with g_free().
1684  **/
1685 gchar*
1686 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
1687 {
1688   g_return_val_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd), NULL);
1689
1690   return gtk_font_selection_get_font_name (GTK_FONT_SELECTION (fsd->fontsel));
1691 }
1692
1693 /**
1694  * gtk_font_selection_dialog_get_font:
1695  * @fsd: a #GtkFontSelectionDialog
1696  *
1697  * Return value: the #GdkFont from the #GtkFontSelection for the
1698  * currently selected font in the dialog.
1699  */
1700 GdkFont*
1701 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
1702 {
1703   g_return_val_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd), NULL);
1704
1705   return gtk_font_selection_get_font (GTK_FONT_SELECTION (fsd->fontsel));
1706 }
1707
1708 /**
1709  * gtk_font_selection_dialog_set_font_name:
1710  * @fsd: a #GtkFontSelectionDialog
1711  * @fontname: a pointer to a string
1712  *
1713  * Return value: %TRUE if the font selected in @fsd is now the
1714  * @fontname specified. %FALSE otherwise. 
1715  */
1716 gboolean
1717 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
1718                                          const gchar            *fontname)
1719 {
1720   g_return_val_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd), FALSE);
1721   g_return_val_if_fail (fontname, FALSE);
1722
1723   return gtk_font_selection_set_font_name (GTK_FONT_SELECTION (fsd->fontsel), fontname);
1724 }
1725
1726 /**
1727  * gtk_font_selection_dialog_get_preview_text:
1728  * @fsd: a #GtkFontSelectionDialog
1729  *
1730  * The text returned is the preview text used to show how the selected
1731  * font looks.  
1732  *
1733  * Return value: pointer to the preview text string. This string
1734  * points to internally allocated storage in the widget and must not
1735  * be freed, modified or stored. 
1736  */
1737 G_CONST_RETURN gchar*
1738 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
1739 {
1740   g_return_val_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd), NULL);
1741
1742   return gtk_font_selection_get_preview_text (GTK_FONT_SELECTION (fsd->fontsel));
1743 }
1744
1745 /**
1746  * gtk_font_selection_dialog_set_preview_text:
1747  * @fsd: a #GtkFontSelectionDialog
1748  * @text: a pointer to a string
1749
1750  * The @text is used to show how the selected font looks.
1751  */
1752 void
1753 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
1754                                             const gchar            *text)
1755 {
1756   g_return_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd));
1757   g_return_if_fail (text != NULL);
1758
1759   gtk_font_selection_set_preview_text (GTK_FONT_SELECTION (fsd->fontsel), text);
1760 }
1761
1762 #define __GTK_FONTSEL_C__
1763 #include "gtkaliasdef.c"