]> Pileus Git - ~andy/gtk/blob - gtk/gtkfontsel.c
Use accessor functions to access GtkDialog
[~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
64 /* We don't enable the font and style entries because they don't add
65  * much in terms of visible effect and have a weird effect on keynav.
66  * the Windows font selector has entries similarly positioned but they
67  * act in conjunction with the associated lists to form a single focus
68  * location.
69  */
70 #undef INCLUDE_FONT_ENTRIES
71
72 /* This is the default text shown in the preview entry, though the user
73    can set it. Remember that some fonts only have capital letters. */
74 #define PREVIEW_TEXT N_("abcdefghijk ABCDEFGHIJK")
75
76 #define DEFAULT_FONT_NAME "Sans 10"
77
78 /* This is the initial and maximum height of the preview entry (it expands
79    when large font sizes are selected). Initial height is also the minimum. */
80 #define INITIAL_PREVIEW_HEIGHT 44
81 #define MAX_PREVIEW_HEIGHT 300
82
83 /* These are the sizes of the font, style & size lists. */
84 #define FONT_LIST_HEIGHT        136
85 #define FONT_LIST_WIDTH         190
86 #define FONT_STYLE_LIST_WIDTH   170
87 #define FONT_SIZE_LIST_WIDTH    60
88
89 /* These are what we use as the standard font sizes, for the size list.
90  */
91 static const guint16 font_sizes[] = {
92   6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 26, 28,
93   32, 36, 40, 48, 56, 64, 72
94 };
95
96 enum {
97    PROP_0,
98    PROP_FONT_NAME,
99    PROP_PREVIEW_TEXT
100 };
101
102
103 enum {
104   FAMILY_COLUMN,
105   FAMILY_NAME_COLUMN
106 };
107
108 enum {
109   FACE_COLUMN,
110   FACE_NAME_COLUMN
111 };
112
113 enum {
114   SIZE_COLUMN
115 };
116
117 static void    gtk_font_selection_set_property       (GObject         *object,
118                                                       guint            prop_id,
119                                                       const GValue    *value,
120                                                       GParamSpec      *pspec);
121 static void    gtk_font_selection_get_property       (GObject         *object,
122                                                       guint            prop_id,
123                                                       GValue          *value,
124                                                       GParamSpec      *pspec);
125 static void    gtk_font_selection_finalize           (GObject         *object);
126 static void    gtk_font_selection_screen_changed     (GtkWidget       *widget,
127                                                       GdkScreen       *previous_screen);
128 static void    gtk_font_selection_style_set          (GtkWidget      *widget,
129                                                       GtkStyle       *prev_style);
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 static void     gtk_font_selection_scroll_to_selection   (GtkFontSelection *fontsel);
159
160
161 /* Misc. utility functions. */
162 static void    gtk_font_selection_load_font          (GtkFontSelection *fs);
163 static void    gtk_font_selection_update_preview     (GtkFontSelection *fs);
164
165 static PangoFontDescription *gtk_font_selection_get_font_description (GtkFontSelection *fontsel);
166 static gboolean gtk_font_selection_select_font_desc  (GtkFontSelection      *fontsel,
167                                                       PangoFontDescription  *new_desc,
168                                                       PangoFontFamily      **pfamily,
169                                                       PangoFontFace        **pface);
170 static void     gtk_font_selection_reload_fonts          (GtkFontSelection *fontsel);
171 static void     gtk_font_selection_ref_family            (GtkFontSelection *fontsel,
172                                                           PangoFontFamily  *family);
173 static void     gtk_font_selection_ref_face              (GtkFontSelection *fontsel,
174                                                           PangoFontFace    *face);
175
176 G_DEFINE_TYPE (GtkFontSelection, gtk_font_selection, GTK_TYPE_VBOX)
177
178 static void
179 gtk_font_selection_class_init (GtkFontSelectionClass *klass)
180 {
181   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
182   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
183   
184   gobject_class->set_property = gtk_font_selection_set_property;
185   gobject_class->get_property = gtk_font_selection_get_property;
186
187   widget_class->screen_changed = gtk_font_selection_screen_changed;
188   widget_class->style_set = gtk_font_selection_style_set;
189    
190   g_object_class_install_property (gobject_class,
191                                    PROP_FONT_NAME,
192                                    g_param_spec_string ("font-name",
193                                                         P_("Font name"),
194                                                         P_("The string that represents this font"),
195                                                         DEFAULT_FONT_NAME,
196                                                         GTK_PARAM_READWRITE));
197   g_object_class_install_property (gobject_class,
198                                    PROP_PREVIEW_TEXT,
199                                    g_param_spec_string ("preview-text",
200                                                         P_("Preview text"),
201                                                         P_("The text to display in order to demonstrate the selected font"),
202                                                         _(PREVIEW_TEXT),
203                                                         GTK_PARAM_READWRITE));
204   gobject_class->finalize = gtk_font_selection_finalize;
205 }
206
207 static void 
208 gtk_font_selection_set_property (GObject         *object,
209                                  guint            prop_id,
210                                  const GValue    *value,
211                                  GParamSpec      *pspec)
212 {
213   GtkFontSelection *fontsel;
214
215   fontsel = GTK_FONT_SELECTION (object);
216
217   switch (prop_id)
218     {
219     case PROP_FONT_NAME:
220       gtk_font_selection_set_font_name (fontsel, g_value_get_string (value));
221       break;
222     case PROP_PREVIEW_TEXT:
223       gtk_font_selection_set_preview_text (fontsel, g_value_get_string (value));
224       break;
225     default:
226       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
227       break;
228     }
229 }
230
231 static void gtk_font_selection_get_property (GObject         *object,
232                                              guint            prop_id,
233                                              GValue          *value,
234                                              GParamSpec      *pspec)
235 {
236   GtkFontSelection *fontsel;
237
238   fontsel = GTK_FONT_SELECTION (object);
239
240   switch (prop_id)
241     {
242     case PROP_FONT_NAME:
243       g_value_take_string (value, gtk_font_selection_get_font_name (fontsel));
244       break;
245     case PROP_PREVIEW_TEXT:
246       g_value_set_string (value, gtk_font_selection_get_preview_text (fontsel));
247       break;
248     default:
249       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
250       break;
251     }
252 }
253
254 /* Handles key press events on the lists, so that we can trap Enter to
255  * activate the default button on our own.
256  */
257 static gboolean
258 list_row_activated (GtkWidget *widget)
259 {
260   GtkWindow *window;
261   
262   window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget)));
263   if (!gtk_widget_is_toplevel (GTK_WIDGET (window)))
264     window = NULL;
265   
266   if (window
267       && widget != window->default_widget
268       && !(widget == window->focus_widget &&
269            (!window->default_widget || !gtk_widget_get_sensitive (window->default_widget))))
270     {
271       gtk_window_activate_default (window);
272     }
273   
274   return TRUE;
275 }
276
277 static void
278 gtk_font_selection_init (GtkFontSelection *fontsel)
279 {
280   GtkWidget *scrolled_win;
281   GtkWidget *text_box;
282   GtkWidget *table, *label;
283   GtkWidget *font_label, *style_label;
284   GtkWidget *vbox;
285   GtkListStore *model;
286   GtkTreeViewColumn *column;
287   GList *focus_chain = NULL;
288   AtkObject *atk_obj;
289
290   gtk_widget_push_composite_child ();
291
292   gtk_box_set_spacing (GTK_BOX (fontsel), 12);
293   fontsel->size = 12 * PANGO_SCALE;
294   
295   /* Create the table of font, style & size. */
296   table = gtk_table_new (3, 3, FALSE);
297   gtk_widget_show (table);
298   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
299   gtk_table_set_col_spacings (GTK_TABLE (table), 12);
300   gtk_box_pack_start (GTK_BOX (fontsel), table, TRUE, TRUE, 0);
301
302 #ifdef INCLUDE_FONT_ENTRIES
303   fontsel->font_entry = gtk_entry_new ();
304   gtk_editable_set_editable (GTK_EDITABLE (fontsel->font_entry), FALSE);
305   gtk_widget_set_size_request (fontsel->font_entry, 20, -1);
306   gtk_widget_show (fontsel->font_entry);
307   gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
308                     GTK_FILL, 0, 0, 0);
309   
310   fontsel->font_style_entry = gtk_entry_new ();
311   gtk_editable_set_editable (GTK_EDITABLE (fontsel->font_style_entry), FALSE);
312   gtk_widget_set_size_request (fontsel->font_style_entry, 20, -1);
313   gtk_widget_show (fontsel->font_style_entry);
314   gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
315                     GTK_FILL, 0, 0, 0);
316 #endif /* INCLUDE_FONT_ENTRIES */
317   
318   fontsel->size_entry = gtk_entry_new ();
319   gtk_widget_set_size_request (fontsel->size_entry, 20, -1);
320   gtk_widget_show (fontsel->size_entry);
321   gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
322                     GTK_FILL, 0, 0, 0);
323   g_signal_connect (fontsel->size_entry, "activate",
324                     G_CALLBACK (gtk_font_selection_size_activate),
325                     fontsel);
326   g_signal_connect_after (fontsel->size_entry, "focus-out-event",
327                           G_CALLBACK (gtk_font_selection_size_focus_out),
328                           fontsel);
329   
330   font_label = gtk_label_new_with_mnemonic (_("_Family:"));
331   gtk_misc_set_alignment (GTK_MISC (font_label), 0.0, 0.5);
332   gtk_widget_show (font_label);
333   gtk_table_attach (GTK_TABLE (table), font_label, 0, 1, 0, 1,
334                     GTK_FILL, 0, 0, 0);  
335
336   style_label = gtk_label_new_with_mnemonic (_("_Style:"));
337   gtk_misc_set_alignment (GTK_MISC (style_label), 0.0, 0.5);
338   gtk_widget_show (style_label);
339   gtk_table_attach (GTK_TABLE (table), style_label, 1, 2, 0, 1,
340                     GTK_FILL, 0, 0, 0);
341   
342   label = gtk_label_new_with_mnemonic (_("Si_ze:"));
343   gtk_label_set_mnemonic_widget (GTK_LABEL (label),
344                                  fontsel->size_entry);
345   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
346   gtk_widget_show (label);
347   gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
348                     GTK_FILL, 0, 0, 0);
349   
350   
351   /* Create the lists  */
352
353   model = gtk_list_store_new (2,
354                               G_TYPE_OBJECT,  /* FAMILY_COLUMN */
355                               G_TYPE_STRING); /* FAMILY_NAME_COLUMN */
356   fontsel->family_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
357   g_object_unref (model);
358
359   g_signal_connect (fontsel->family_list, "row-activated",
360                     G_CALLBACK (list_row_activated), fontsel);
361
362   column = gtk_tree_view_column_new_with_attributes ("Family",
363                                                      gtk_cell_renderer_text_new (),
364                                                      "text", FAMILY_NAME_COLUMN,
365                                                      NULL);
366   gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
367   gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->family_list), column);
368
369   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->family_list), FALSE);
370   gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)),
371                                GTK_SELECTION_BROWSE);
372   
373   gtk_label_set_mnemonic_widget (GTK_LABEL (font_label), fontsel->family_list);
374
375   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
376   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
377   gtk_widget_set_size_request (scrolled_win,
378                                FONT_LIST_WIDTH, FONT_LIST_HEIGHT);
379   gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->family_list);
380   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
381                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
382   gtk_widget_show (fontsel->family_list);
383   gtk_widget_show (scrolled_win);
384
385   gtk_table_attach (GTK_TABLE (table), scrolled_win, 0, 1, 1, 3,
386                     GTK_EXPAND | GTK_FILL,
387                     GTK_EXPAND | GTK_FILL, 0, 0);
388   focus_chain = g_list_append (focus_chain, scrolled_win);
389   
390   model = gtk_list_store_new (2,
391                               G_TYPE_OBJECT,  /* FACE_COLUMN */
392                               G_TYPE_STRING); /* FACE_NAME_COLUMN */
393   fontsel->face_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
394   g_object_unref (model);
395   g_signal_connect (fontsel->face_list, "row-activated",
396                     G_CALLBACK (list_row_activated), fontsel);
397
398   gtk_label_set_mnemonic_widget (GTK_LABEL (style_label), fontsel->face_list);
399
400   column = gtk_tree_view_column_new_with_attributes ("Face",
401                                                      gtk_cell_renderer_text_new (),
402                                                      "text", FACE_NAME_COLUMN,
403                                                      NULL);
404   gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
405   gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->face_list), column);
406
407   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->face_list), FALSE);
408   gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)),
409                                GTK_SELECTION_BROWSE);
410   
411   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
412   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
413   gtk_widget_set_size_request (scrolled_win,
414                                FONT_STYLE_LIST_WIDTH, FONT_LIST_HEIGHT);
415   gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->face_list);
416   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
417                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
418   gtk_widget_show (fontsel->face_list);
419   gtk_widget_show (scrolled_win);
420   gtk_table_attach (GTK_TABLE (table), scrolled_win, 1, 2, 1, 3,
421                     GTK_EXPAND | GTK_FILL,
422                     GTK_EXPAND | GTK_FILL, 0, 0);
423   focus_chain = g_list_append (focus_chain, scrolled_win);
424   
425   focus_chain = g_list_append (focus_chain, fontsel->size_entry);
426
427   model = gtk_list_store_new (1, G_TYPE_INT);
428   fontsel->size_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
429   g_object_unref (model);
430   g_signal_connect (fontsel->size_list, "row-activated",
431                     G_CALLBACK (list_row_activated), fontsel);
432
433   column = gtk_tree_view_column_new_with_attributes ("Size",
434                                                      gtk_cell_renderer_text_new (),
435                                                      "text", SIZE_COLUMN,
436                                                      NULL);
437   gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
438   gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->size_list), column);
439
440   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->size_list), FALSE);
441   gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)),
442                                GTK_SELECTION_BROWSE);
443   
444   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
445   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
446   gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->size_list);
447   gtk_widget_set_size_request (scrolled_win, -1, FONT_LIST_HEIGHT);
448   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
449                                   GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
450   gtk_widget_show (fontsel->size_list);
451   gtk_widget_show (scrolled_win);
452   gtk_table_attach (GTK_TABLE (table), scrolled_win, 2, 3, 2, 3,
453                     GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
454   focus_chain = g_list_append (focus_chain, scrolled_win);
455
456   gtk_container_set_focus_chain (GTK_CONTAINER (table), focus_chain);
457   g_list_free (focus_chain);
458   
459   /* Insert the fonts. */
460   g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)), "changed",
461                     G_CALLBACK (gtk_font_selection_select_font), fontsel);
462
463   g_signal_connect_after (fontsel->family_list, "map",
464                           G_CALLBACK (gtk_font_selection_scroll_on_map),
465                           fontsel);
466   
467   g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)), "changed",
468                     G_CALLBACK (gtk_font_selection_select_style), fontsel);
469
470   g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)), "changed",
471                     G_CALLBACK (gtk_font_selection_select_size), fontsel);
472   atk_obj = gtk_widget_get_accessible (fontsel->size_list);
473   if (GTK_IS_ACCESSIBLE (atk_obj))
474     {
475       /* Accessibility support is enabled.
476        * Make the label ATK_RELATON_LABEL_FOR for the size list as well.
477        */
478       AtkObject *atk_label;
479       AtkRelationSet *relation_set;
480       AtkRelation *relation;
481       AtkObject *obj_array[1];
482
483       atk_label = gtk_widget_get_accessible (label);
484       relation_set = atk_object_ref_relation_set (atk_obj);
485       relation = atk_relation_set_get_relation_by_type (relation_set, ATK_RELATION_LABELLED_BY);
486       if (relation)
487         {
488           atk_relation_add_target (relation, atk_label);
489         }
490       else 
491         {
492           obj_array[0] = atk_label;
493           relation = atk_relation_new (obj_array, 1, ATK_RELATION_LABELLED_BY);
494           atk_relation_set_add (relation_set, relation);
495         }
496       g_object_unref (relation_set);
497
498       relation_set = atk_object_ref_relation_set (atk_label);
499       relation = atk_relation_set_get_relation_by_type (relation_set, ATK_RELATION_LABEL_FOR);
500       if (relation)
501         {
502           atk_relation_add_target (relation, atk_obj);
503         }
504       else 
505         {
506           obj_array[0] = atk_obj;
507           relation = atk_relation_new (obj_array, 1, ATK_RELATION_LABEL_FOR);
508           atk_relation_set_add (relation_set, relation);
509         }
510       g_object_unref (relation_set);
511     }    
512       
513
514   vbox = gtk_vbox_new (FALSE, 6);
515   gtk_widget_show (vbox);
516   gtk_box_pack_start (GTK_BOX (fontsel), vbox, FALSE, TRUE, 0);
517   
518   /* create the text entry widget */
519   label = gtk_label_new_with_mnemonic (_("_Preview:"));
520   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
521   gtk_widget_show (label);
522   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0);
523   
524   text_box = gtk_hbox_new (FALSE, 0);
525   gtk_widget_show (text_box);
526   gtk_box_pack_start (GTK_BOX (vbox), text_box, FALSE, TRUE, 0);
527   
528   fontsel->preview_entry = gtk_entry_new ();
529   gtk_label_set_mnemonic_widget (GTK_LABEL (label), fontsel->preview_entry);
530   gtk_entry_set_text (GTK_ENTRY (fontsel->preview_entry), _(PREVIEW_TEXT));
531   
532   gtk_widget_show (fontsel->preview_entry);
533   g_signal_connect (fontsel->preview_entry, "changed",
534                     G_CALLBACK (gtk_font_selection_preview_changed), fontsel);
535   gtk_widget_set_size_request (fontsel->preview_entry,
536                                -1, INITIAL_PREVIEW_HEIGHT);
537   gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
538                       TRUE, TRUE, 0);
539   gtk_widget_pop_composite_child();
540 }
541
542 /**
543  * gtk_font_selection_new:
544  *
545  * Creates a new #GtkFontSelection.
546  *
547  * Return value: a n ew #GtkFontSelection
548  */
549 GtkWidget *
550 gtk_font_selection_new (void)
551 {
552   GtkFontSelection *fontsel;
553   
554   fontsel = g_object_new (GTK_TYPE_FONT_SELECTION, NULL);
555   
556   return GTK_WIDGET (fontsel);
557 }
558
559 static void
560 gtk_font_selection_finalize (GObject *object)
561 {
562   GtkFontSelection *fontsel;
563   
564   g_return_if_fail (GTK_IS_FONT_SELECTION (object));
565   
566   fontsel = GTK_FONT_SELECTION (object);
567
568   gtk_font_selection_ref_family (fontsel, NULL);
569   gtk_font_selection_ref_face (fontsel, NULL);
570
571   G_OBJECT_CLASS (gtk_font_selection_parent_class)->finalize (object);
572 }
573
574 static void
575 gtk_font_selection_ref_family (GtkFontSelection *fontsel,
576                                PangoFontFamily  *family)
577 {
578   if (family)
579     family = g_object_ref (family);
580   if (fontsel->family)
581     g_object_unref (fontsel->family);
582   fontsel->family = family;
583 }
584
585 static void gtk_font_selection_ref_face (GtkFontSelection *fontsel,
586                                          PangoFontFace    *face)
587 {
588   if (face)
589     face = g_object_ref (face);
590   if (fontsel->face)
591     g_object_unref (fontsel->face);
592   fontsel->face = face;
593 }
594
595 static void
596 gtk_font_selection_reload_fonts (GtkFontSelection *fontsel)
597 {
598   if (gtk_widget_has_screen (GTK_WIDGET (fontsel)))
599     {
600       PangoFontDescription *desc;
601       desc = gtk_font_selection_get_font_description (fontsel);
602
603       gtk_font_selection_show_available_fonts (fontsel);
604       gtk_font_selection_show_available_sizes (fontsel, TRUE);
605       gtk_font_selection_show_available_styles (fontsel);
606
607       gtk_font_selection_select_font_desc (fontsel, desc, NULL, NULL);
608       gtk_font_selection_scroll_to_selection (fontsel);
609
610       pango_font_description_free (desc);
611     }
612 }
613
614 static void
615 gtk_font_selection_screen_changed (GtkWidget *widget,
616                                    GdkScreen *previous_screen)
617 {
618   gtk_font_selection_reload_fonts (GTK_FONT_SELECTION (widget));
619 }
620
621 static void
622 gtk_font_selection_style_set (GtkWidget *widget,
623                               GtkStyle  *prev_style)
624 {
625   /* Maybe fonts where installed or removed... */
626   gtk_font_selection_reload_fonts (GTK_FONT_SELECTION (widget));
627 }
628
629 static void
630 gtk_font_selection_preview_changed (GtkWidget        *entry,
631                                     GtkFontSelection *fontsel)
632 {
633   g_object_notify (G_OBJECT (fontsel), "preview-text");
634 }
635
636 static void
637 scroll_to_selection (GtkTreeView *tree_view)
638 {
639   GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
640   GtkTreeModel *model;
641   GtkTreeIter iter;
642
643   if (gtk_tree_selection_get_selected (selection, &model, &iter))
644     {
645       GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
646       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.5);
647       gtk_tree_path_free (path);
648     }
649 }
650
651 static void
652 set_cursor_to_iter (GtkTreeView *view,
653                     GtkTreeIter *iter)
654 {
655   GtkTreeModel *model = gtk_tree_view_get_model (view);
656   GtkTreePath *path = gtk_tree_model_get_path (model, iter);
657   
658   gtk_tree_view_set_cursor (view, path, NULL, FALSE);
659
660   gtk_tree_path_free (path);
661 }
662
663 static void
664 gtk_font_selection_scroll_to_selection (GtkFontSelection *fontsel)
665 {
666   /* Try to scroll the font family list to the selected item */
667   scroll_to_selection (GTK_TREE_VIEW (fontsel->family_list));
668       
669   /* Try to scroll the font family list to the selected item */
670   scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
671       
672   /* Try to scroll the font family list to the selected item */
673   scroll_to_selection (GTK_TREE_VIEW (fontsel->size_list));
674 /* This is called when the list is mapped. Here we scroll to the current
675    font if necessary. */
676 }
677
678 static void
679 gtk_font_selection_scroll_on_map (GtkWidget             *widget,
680                                   gpointer               data)
681 {
682   gtk_font_selection_scroll_to_selection (GTK_FONT_SELECTION (data));
683 }
684
685 /* This is called when a family is selected in the list. */
686 static void
687 gtk_font_selection_select_font (GtkTreeSelection *selection,
688                                 gpointer          data)
689 {
690   GtkFontSelection *fontsel;
691   GtkTreeModel *model;
692   GtkTreeIter iter;
693 #ifdef INCLUDE_FONT_ENTRIES
694   const gchar *family_name;
695 #endif
696
697   fontsel = GTK_FONT_SELECTION (data);
698
699   if (gtk_tree_selection_get_selected (selection, &model, &iter))
700     {
701       PangoFontFamily *family;
702       
703       gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
704       if (fontsel->family != family)
705         {
706           gtk_font_selection_ref_family (fontsel, family);
707           
708 #ifdef INCLUDE_FONT_ENTRIES
709           family_name = pango_font_family_get_name (fontsel->family);
710           gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), family_name);
711 #endif
712           
713           gtk_font_selection_show_available_styles (fontsel);
714           gtk_font_selection_select_best_style (fontsel, TRUE);
715         }
716
717       g_object_unref (family);
718     }
719 }
720
721 static int
722 cmp_families (const void *a, const void *b)
723 {
724   const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a);
725   const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b);
726   
727   return g_utf8_collate (a_name, b_name);
728 }
729
730 static void
731 gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
732 {
733   GtkListStore *model;
734   PangoFontFamily **families;
735   PangoFontFamily *match_family = NULL;
736   gint n_families, i;
737   GtkTreeIter match_row;
738   
739   model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list)));
740   
741   pango_context_list_families (gtk_widget_get_pango_context (GTK_WIDGET (fontsel)),
742                                &families, &n_families);
743   qsort (families, n_families, sizeof (PangoFontFamily *), cmp_families);
744
745   gtk_list_store_clear (model);
746
747   for (i=0; i<n_families; i++)
748     {
749       const gchar *name = pango_font_family_get_name (families[i]);
750       GtkTreeIter iter;
751
752       gtk_list_store_append (model, &iter);
753       gtk_list_store_set (model, &iter,
754                           FAMILY_COLUMN, families[i],
755                           FAMILY_NAME_COLUMN, name,
756                           -1);
757       
758       if (i == 0 || !g_ascii_strcasecmp (name, "sans"))
759         {
760           match_family = families[i];
761           match_row = iter;
762         }
763     }
764
765   gtk_font_selection_ref_family (fontsel, match_family);
766   if (match_family)
767     {
768       set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &match_row);
769 #ifdef INCLUDE_FONT_ENTRIES
770       gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), 
771                           pango_font_family_get_name (match_family));
772 #endif /* INCLUDE_FONT_ENTRIES */
773     }
774
775   g_free (families);
776 }
777
778 static int
779 compare_font_descriptions (const PangoFontDescription *a, const PangoFontDescription *b)
780 {
781   int val = strcmp (pango_font_description_get_family (a), pango_font_description_get_family (b));
782   if (val != 0)
783     return val;
784
785   if (pango_font_description_get_weight (a) != pango_font_description_get_weight (b))
786     return pango_font_description_get_weight (a) - pango_font_description_get_weight (b);
787
788   if (pango_font_description_get_style (a) != pango_font_description_get_style (b))
789     return pango_font_description_get_style (a) - pango_font_description_get_style (b);
790   
791   if (pango_font_description_get_stretch (a) != pango_font_description_get_stretch (b))
792     return pango_font_description_get_stretch (a) - pango_font_description_get_stretch (b);
793
794   if (pango_font_description_get_variant (a) != pango_font_description_get_variant (b))
795     return pango_font_description_get_variant (a) - pango_font_description_get_variant (b);
796
797   return 0;
798 }
799
800 static int
801 faces_sort_func (const void *a, const void *b)
802 {
803   PangoFontDescription *desc_a = pango_font_face_describe (*(PangoFontFace **)a);
804   PangoFontDescription *desc_b = pango_font_face_describe (*(PangoFontFace **)b);
805   
806   int ord = compare_font_descriptions (desc_a, desc_b);
807
808   pango_font_description_free (desc_a);
809   pango_font_description_free (desc_b);
810
811   return ord;
812 }
813
814 static gboolean
815 font_description_style_equal (const PangoFontDescription *a,
816                               const PangoFontDescription *b)
817 {
818   return (pango_font_description_get_weight (a) == pango_font_description_get_weight (b) &&
819           pango_font_description_get_style (a) == pango_font_description_get_style (b) &&
820           pango_font_description_get_stretch (a) == pango_font_description_get_stretch (b) &&
821           pango_font_description_get_variant (a) == pango_font_description_get_variant (b));
822 }
823
824 /* This fills the font style list with all the possible style combinations
825    for the current font family. */
826 static void
827 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
828 {
829   gint n_faces, i;
830   PangoFontFace **faces;
831   PangoFontDescription *old_desc;
832   GtkListStore *model;
833   GtkTreeIter match_row;
834   PangoFontFace *match_face = NULL;
835   
836   model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list)));
837   
838   if (fontsel->face)
839     old_desc = pango_font_face_describe (fontsel->face);
840   else
841     old_desc= NULL;
842
843   pango_font_family_list_faces (fontsel->family, &faces, &n_faces);
844   qsort (faces, n_faces, sizeof (PangoFontFace *), faces_sort_func);
845
846   gtk_list_store_clear (model);
847
848   for (i=0; i < n_faces; i++)
849     {
850       GtkTreeIter iter;
851       const gchar *str = pango_font_face_get_face_name (faces[i]);
852
853       gtk_list_store_append (model, &iter);
854       gtk_list_store_set (model, &iter,
855                           FACE_COLUMN, faces[i],
856                           FACE_NAME_COLUMN, str,
857                           -1);
858
859       if (i == 0)
860         {
861           match_row = iter;
862           match_face = faces[i];
863         }
864       else if (old_desc)
865         {
866           PangoFontDescription *tmp_desc = pango_font_face_describe (faces[i]);
867           
868           if (font_description_style_equal (tmp_desc, old_desc))
869             {
870               match_row = iter;
871               match_face = faces[i];
872             }
873       
874           pango_font_description_free (tmp_desc);
875         }
876     }
877
878   if (old_desc)
879     pango_font_description_free (old_desc);
880
881   gtk_font_selection_ref_face (fontsel, match_face);
882   if (match_face)
883     {
884 #ifdef INCLUDE_FONT_ENTRIES
885       const gchar *str = pango_font_face_get_face_name (fontsel->face);
886
887       gtk_entry_set_text (GTK_ENTRY (fontsel->font_style_entry), str);
888 #endif      
889       set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_row);
890     }
891
892   g_free (faces);
893 }
894
895 /* This selects a style when the user selects a font. It just uses the first
896    available style at present. I was thinking of trying to maintain the
897    selected style, e.g. bold italic, when the user selects different fonts.
898    However, the interface is so easy to use now I'm not sure it's worth it.
899    Note: This will load a font. */
900 static void
901 gtk_font_selection_select_best_style (GtkFontSelection *fontsel,
902                                       gboolean          use_first)
903 {
904   GtkTreeIter iter;
905   GtkTreeModel *model;
906
907   model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
908
909   if (gtk_tree_model_get_iter_first (model, &iter))
910     {
911       set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &iter);
912       scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
913     }
914
915   gtk_font_selection_show_available_sizes (fontsel, FALSE);
916   gtk_font_selection_select_best_size (fontsel);
917 }
918
919
920 /* This is called when a style is selected in the list. */
921 static void
922 gtk_font_selection_select_style (GtkTreeSelection *selection,
923                                  gpointer          data)
924 {
925   GtkFontSelection *fontsel = GTK_FONT_SELECTION (data);
926   GtkTreeModel *model;
927   GtkTreeIter iter;
928   
929   if (gtk_tree_selection_get_selected (selection, &model, &iter))
930     {
931       PangoFontFace *face;
932       
933       gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
934       gtk_font_selection_ref_face (fontsel, face);
935       g_object_unref (face);
936     }
937
938   gtk_font_selection_show_available_sizes (fontsel, FALSE);
939   gtk_font_selection_select_best_size (fontsel);
940 }
941
942 static void
943 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel,
944                                          gboolean          first_time)
945 {
946   gint i;
947   GtkListStore *model;
948   gchar buffer[128];
949   gchar *p;
950       
951   model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->size_list)));
952
953   /* Insert the standard font sizes */
954   if (first_time)
955     {
956       gtk_list_store_clear (model);
957
958       for (i = 0; i < G_N_ELEMENTS (font_sizes); i++)
959         {
960           GtkTreeIter iter;
961           
962           gtk_list_store_append (model, &iter);
963           gtk_list_store_set (model, &iter, SIZE_COLUMN, font_sizes[i], -1);
964           
965           if (font_sizes[i] * PANGO_SCALE == fontsel->size)
966             set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
967         }
968     }
969   else
970     {
971       GtkTreeIter iter;
972       gboolean found = FALSE;
973       
974       gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
975       for (i = 0; i < G_N_ELEMENTS (font_sizes) && !found; i++)
976         {
977           if (font_sizes[i] * PANGO_SCALE == fontsel->size)
978             {
979               set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
980               found = TRUE;
981             }
982
983           gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter);
984         }
985
986       if (!found)
987         {
988           GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
989           gtk_tree_selection_unselect_all (selection);
990         }
991     }
992
993   /* Set the entry to the new size, rounding to 1 digit,
994    * trimming of trailing 0's and a trailing period
995    */
996   g_snprintf (buffer, sizeof (buffer), "%.1f", fontsel->size / (1.0 * PANGO_SCALE));
997   if (strchr (buffer, '.'))
998     {
999       p = buffer + strlen (buffer) - 1;
1000       while (*p == '0')
1001         p--;
1002       if (*p == '.')
1003         p--;
1004       p[1] = '\0';
1005     }
1006
1007   /* Compare, to avoid moving the cursor unecessarily */
1008   if (strcmp (gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry)), buffer) != 0)
1009     gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
1010 }
1011
1012 static void
1013 gtk_font_selection_select_best_size (GtkFontSelection *fontsel)
1014 {
1015   gtk_font_selection_load_font (fontsel);  
1016 }
1017
1018 static void
1019 gtk_font_selection_set_size (GtkFontSelection *fontsel,
1020                              gint              new_size)
1021 {
1022   if (fontsel->size != new_size)
1023     {
1024       fontsel->size = new_size;
1025
1026       gtk_font_selection_show_available_sizes (fontsel, FALSE);      
1027       gtk_font_selection_load_font (fontsel);
1028     }
1029 }
1030
1031 /* If the user hits return in the font size entry, we change to the new font
1032    size. */
1033 static void
1034 gtk_font_selection_size_activate (GtkWidget   *w,
1035                                   gpointer     data)
1036 {
1037   GtkFontSelection *fontsel;
1038   gint new_size;
1039   const gchar *text;
1040   
1041   fontsel = GTK_FONT_SELECTION (data);
1042
1043   text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1044   new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);
1045
1046   if (fontsel->size != new_size)
1047     gtk_font_selection_set_size (fontsel, new_size);
1048   else 
1049     list_row_activated (w);
1050 }
1051
1052 static gboolean
1053 gtk_font_selection_size_focus_out (GtkWidget     *w,
1054                                    GdkEventFocus *event,
1055                                    gpointer       data)
1056 {
1057   GtkFontSelection *fontsel;
1058   gint new_size;
1059   const gchar *text;
1060   
1061   fontsel = GTK_FONT_SELECTION (data);
1062
1063   text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1064   new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);
1065
1066   gtk_font_selection_set_size (fontsel, new_size);
1067   
1068   return TRUE;
1069 }
1070
1071 /* This is called when a size is selected in the list. */
1072 static void
1073 gtk_font_selection_select_size (GtkTreeSelection *selection,
1074                                 gpointer          data)
1075 {
1076   GtkFontSelection *fontsel;
1077   GtkTreeModel *model;
1078   GtkTreeIter iter;
1079   gint new_size;
1080   
1081   fontsel = GTK_FONT_SELECTION (data);
1082   
1083   if (gtk_tree_selection_get_selected (selection, &model, &iter))
1084     {
1085       gtk_tree_model_get (model, &iter, SIZE_COLUMN, &new_size, -1);
1086       gtk_font_selection_set_size (fontsel, new_size * PANGO_SCALE);
1087     }
1088 }
1089
1090 static void
1091 gtk_font_selection_load_font (GtkFontSelection *fontsel)
1092 {
1093   gtk_font_selection_update_preview (fontsel);
1094 }
1095
1096 static PangoFontDescription *
1097 gtk_font_selection_get_font_description (GtkFontSelection *fontsel)
1098 {
1099   PangoFontDescription *font_desc;
1100
1101   if (fontsel->face)
1102     {
1103       font_desc = pango_font_face_describe (fontsel->face);
1104       pango_font_description_set_size (font_desc, fontsel->size);
1105     }
1106   else
1107     font_desc = pango_font_description_from_string (DEFAULT_FONT_NAME);
1108
1109   return font_desc;
1110 }
1111
1112 /* This sets the font in the preview entry to the selected font, and tries to
1113    make sure that the preview entry is a reasonable size, i.e. so that the
1114    text can be seen with a bit of space to spare. But it tries to avoid
1115    resizing the entry every time the font changes.
1116    This also used to shrink the preview if the font size was decreased, but
1117    that made it awkward if the user wanted to resize the window themself. */
1118 static void
1119 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1120 {
1121   GtkRcStyle *rc_style;
1122   gint new_height;
1123   GtkRequisition old_requisition;
1124   GtkWidget *preview_entry = fontsel->preview_entry;
1125   const gchar *text;
1126
1127   gtk_widget_get_child_requisition (preview_entry, &old_requisition);
1128   
1129   rc_style = gtk_rc_style_new ();
1130   rc_style->font_desc = gtk_font_selection_get_font_description (fontsel);
1131   
1132   gtk_widget_modify_style (preview_entry, rc_style);
1133   g_object_unref (rc_style);
1134
1135   gtk_widget_size_request (preview_entry, NULL);
1136   
1137   /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1138   new_height = CLAMP (preview_entry->requisition.height, INITIAL_PREVIEW_HEIGHT, MAX_PREVIEW_HEIGHT);
1139
1140   if (new_height > old_requisition.height || new_height < old_requisition.height - 30)
1141     gtk_widget_set_size_request (preview_entry, -1, new_height);
1142   
1143   /* This sets the preview text, if it hasn't been set already. */
1144   text = gtk_entry_get_text (GTK_ENTRY (preview_entry));
1145   if (strlen (text) == 0)
1146     gtk_entry_set_text (GTK_ENTRY (preview_entry), _(PREVIEW_TEXT));
1147   gtk_editable_set_position (GTK_EDITABLE (preview_entry), 0);
1148 }
1149
1150
1151 /*****************************************************************************
1152  * These functions are the main public interface for getting/setting the font.
1153  *****************************************************************************/
1154
1155 /**
1156  * gtk_font_selection_get_family_list:
1157  * @fontsel: a #GtkFontSelection
1158  *
1159  * This returns the #GtkTreeView that lists font families, for
1160  * example, 'Sans', 'Serif', etc.
1161  * 
1162  * Return value: A #GtkWidget that is part of @fontsel
1163  *
1164  * Since: 2.14
1165  */
1166 GtkWidget *
1167 gtk_font_selection_get_family_list (GtkFontSelection *fontsel)
1168 {
1169   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1170   
1171   return fontsel->family_list;
1172 }
1173
1174 /**
1175  * gtk_font_selection_get_face_list:
1176  * @fontsel: a #GtkFontSelection
1177  *
1178  * This returns the #GtkTreeView which lists all styles available for
1179  * the selected font. For example, 'Regular', 'Bold', etc.
1180  * 
1181  * Return value: A #GtkWidget that is part of @fontsel
1182  *
1183  * Since: 2.14
1184  */
1185 GtkWidget *
1186 gtk_font_selection_get_face_list (GtkFontSelection *fontsel)
1187 {
1188   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1189   
1190   return fontsel->face_list;
1191 }
1192
1193 /**
1194  * gtk_font_selection_get_size_entry:
1195  * @fontsel: a #GtkFontSelection
1196  *
1197  * This returns the #GtkEntry used to allow the user to edit the font
1198  * number manually instead of selecting it from the list of font sizes. 
1199  * 
1200  * Return value: A #GtkWidget that is part of @fontsel
1201  *
1202  * Since: 2.14
1203  */
1204 GtkWidget *
1205 gtk_font_selection_get_size_entry (GtkFontSelection *fontsel)
1206 {
1207   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1208   
1209   return fontsel->size_entry;
1210 }
1211
1212 /**
1213  * gtk_font_selection_get_size_list:
1214  * @fontsel: a #GtkFontSelection
1215  *
1216  * This returns the #GtkTreeeView used to list font sizes. 
1217  * 
1218  * Return value: A #GtkWidget that is part of @fontsel
1219  *
1220  * Since: 2.14
1221  */
1222 GtkWidget *
1223 gtk_font_selection_get_size_list (GtkFontSelection *fontsel)
1224 {
1225   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1226   
1227   return fontsel->size_list;
1228 }
1229
1230 /**
1231  * gtk_font_selection_get_preview_entry:
1232  * @fontsel: a #GtkFontSelection
1233  * 
1234  * This returns the #GtkEntry used to display the font as a preview.
1235  *
1236  * Return value: A #GtkWidget that is part of @fontsel
1237  *
1238  * Since: 2.14
1239  */
1240 GtkWidget *
1241 gtk_font_selection_get_preview_entry (GtkFontSelection *fontsel)
1242 {
1243   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1244   
1245   return fontsel->preview_entry;
1246 }
1247
1248 /**
1249  * gtk_font_selection_get_family:
1250  * @fontsel: a #GtkFontSelection
1251  * 
1252  * Gets the #PangoFontFamily representing the selected font family.
1253  *
1254  * Return value: A #PangoFontFamily representing the selected font
1255  *     family. Font families are a collection of font faces. The 
1256  *     returned object is owned by @fontsel and must not be modified 
1257  *     or freed.
1258  *
1259  * Since: 2.14
1260  */
1261 PangoFontFamily *
1262 gtk_font_selection_get_family (GtkFontSelection *fontsel)
1263 {
1264   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1265   
1266   return fontsel->family;
1267 }
1268
1269 /**
1270  * gtk_font_selection_get_face:
1271  * @fontsel: a #GtkFontSelection
1272  * 
1273  * Gets the #PangoFontFace representing the selected font group
1274  * details (i.e. family, slant, weight, width, etc).   
1275  *
1276  * Return value: A #PangoFontFace representing the selected font 
1277  *     group details. The returned object is owned by @fontsel and
1278  *     must not be modified or freed. 
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  * The selected font size.
1295  *
1296  * Return value: A n integer representing the selected font size, 
1297  *     or -1 if no font size is selected.
1298  *
1299  * Since: 2.14
1300  **/
1301 gint
1302 gtk_font_selection_get_size (GtkFontSelection *fontsel)
1303 {
1304   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), -1);
1305   
1306   return fontsel->size;
1307 }
1308
1309 /**
1310  * gtk_font_selection_get_font_name:
1311  * @fontsel: a #GtkFontSelection
1312  * 
1313  * Gets the currently-selected font name. 
1314  *
1315  * Note that this can be a different string than what you set with 
1316  * gtk_font_selection_set_font_name(), as the font selection widget may 
1317  * normalize font names and thus return a string with a different structure. 
1318  * For example, "Helvetica Italic Bold 12" could be normalized to 
1319  * "Helvetica Bold Italic 12". Use pango_font_description_equal()
1320  * if you want to compare two font descriptions.
1321  * 
1322  * Return value: A string with the name of the current font, or %NULL if 
1323  *     no font is selected. You must free this string with g_free().
1324  */
1325 gchar *
1326 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
1327 {
1328   gchar *result;
1329   
1330   PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1331   result = pango_font_description_to_string (font_desc);
1332   pango_font_description_free (font_desc);
1333
1334   return result;
1335 }
1336
1337 /* This selects the appropriate list rows.
1338    First we check the fontname is valid and try to find the font family
1339    - i.e. the name in the main list. If we can't find that, then just return.
1340    Next we try to set each of the properties according to the fontname.
1341    Finally we select the font family & style in the lists. */
1342 static gboolean
1343 gtk_font_selection_select_font_desc (GtkFontSelection      *fontsel,
1344                                      PangoFontDescription  *new_desc,
1345                                      PangoFontFamily      **pfamily,
1346                                      PangoFontFace        **pface)
1347 {
1348   PangoFontFamily *new_family = NULL;
1349   PangoFontFace *new_face = NULL;
1350   PangoFontFace *fallback_face = NULL;
1351   GtkTreeModel *model;
1352   GtkTreeIter iter;
1353   GtkTreeIter match_iter;
1354   gboolean valid;
1355   const gchar *new_family_name;
1356
1357   new_family_name = pango_font_description_get_family (new_desc);
1358
1359   if (!new_family_name)
1360     return FALSE;
1361
1362   /* Check to make sure that this is in the list of allowed fonts 
1363    */
1364   model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list));
1365   for (valid = gtk_tree_model_get_iter_first (model, &iter);
1366        valid;
1367        valid = gtk_tree_model_iter_next (model, &iter))
1368     {
1369       PangoFontFamily *family;
1370       
1371       gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
1372       
1373       if (g_ascii_strcasecmp (pango_font_family_get_name (family),
1374                               new_family_name) == 0)
1375         new_family = g_object_ref (family);
1376
1377       g_object_unref (family);
1378       
1379       if (new_family)
1380         break;
1381     }
1382
1383   if (!new_family)
1384     return FALSE;
1385
1386   if (pfamily)
1387     *pfamily = new_family;
1388   else
1389     g_object_unref (new_family);
1390   set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &iter);
1391   gtk_font_selection_show_available_styles (fontsel);
1392
1393   model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
1394   for (valid = gtk_tree_model_get_iter_first (model, &iter);
1395        valid;
1396        valid = gtk_tree_model_iter_next (model, &iter))
1397     {
1398       PangoFontFace *face;
1399       PangoFontDescription *tmp_desc;
1400       
1401       gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
1402       tmp_desc = pango_font_face_describe (face);
1403       
1404       if (font_description_style_equal (tmp_desc, new_desc))
1405         new_face = g_object_ref (face);
1406       
1407       if (!fallback_face)
1408         {
1409           fallback_face = g_object_ref (face);
1410           match_iter = iter;
1411         }
1412       
1413       pango_font_description_free (tmp_desc);
1414       g_object_unref (face);
1415       
1416       if (new_face)
1417         {
1418           match_iter = iter;
1419           break;
1420         }
1421     }
1422
1423   if (!new_face)
1424     new_face = fallback_face;
1425   else if (fallback_face)
1426     g_object_unref (fallback_face);
1427
1428   if (pface)
1429     *pface = new_face;
1430   else if (new_face)
1431     g_object_unref (new_face);
1432   set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_iter);  
1433
1434   gtk_font_selection_set_size (fontsel, pango_font_description_get_size (new_desc));
1435
1436   return TRUE;
1437 }
1438
1439
1440 /* This sets the current font, then selecting the appropriate list rows. */
1441
1442 /**
1443  * gtk_font_selection_set_font_name:
1444  * @fontsel: a #GtkFontSelection
1445  * @fontname: a font name like "Helvetica 12" or "Times Bold 18"
1446  * 
1447  * Sets the currently-selected font. 
1448  *
1449  * Note that the @fontsel needs to know the screen in which it will appear 
1450  * for this to work; this can be guaranteed by simply making sure that the 
1451  * @fontsel is inserted in a toplevel window before you call this function.
1452  * 
1453  * Return value: %TRUE if the font could be set successfully; %FALSE if no 
1454  *     such font exists or if the @fontsel doesn't belong to a particular 
1455  *     screen yet.
1456  */
1457 gboolean
1458 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
1459                                   const gchar      *fontname)
1460 {
1461   PangoFontFamily *family = NULL;
1462   PangoFontFace *face = NULL;
1463   PangoFontDescription *new_desc;
1464   
1465   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
1466
1467   if (!gtk_widget_has_screen (GTK_WIDGET (fontsel)))
1468     return FALSE;
1469
1470   new_desc = pango_font_description_from_string (fontname);
1471
1472   if (gtk_font_selection_select_font_desc (fontsel, new_desc, &family, &face))
1473     {
1474       gtk_font_selection_ref_family (fontsel, family);
1475       if (family)
1476         g_object_unref (family);
1477
1478       gtk_font_selection_ref_face (fontsel, face);
1479       if (face)
1480         g_object_unref (face);
1481     }
1482
1483   pango_font_description_free (new_desc);
1484   
1485   g_object_freeze_notify (G_OBJECT (fontsel));
1486   g_object_notify (G_OBJECT (fontsel), "font-name");
1487   g_object_notify (G_OBJECT (fontsel), "font");
1488   g_object_thaw_notify (G_OBJECT (fontsel));
1489
1490   return TRUE;
1491 }
1492
1493 /**
1494  * gtk_font_selection_get_preview_text:
1495  * @fontsel: a #GtkFontSelection
1496  *
1497  * Gets the text displayed in the preview area.
1498  * 
1499  * Return value: the text displayed in the preview area. 
1500  *     This string is owned by the widget and should not be 
1501  *     modified or freed 
1502  */
1503 G_CONST_RETURN gchar*
1504 gtk_font_selection_get_preview_text (GtkFontSelection *fontsel)
1505 {
1506   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
1507
1508   return gtk_entry_get_text (GTK_ENTRY (fontsel->preview_entry));
1509 }
1510
1511
1512 /**
1513  * gtk_font_selection_set_preview_text:
1514  * @fontsel: a #GtkFontSelection
1515  * @text: the text to display in the preview area 
1516  *
1517  * Sets the text displayed in the preview area.
1518  * The @text is used to show how the selected font looks.
1519  */
1520 void
1521 gtk_font_selection_set_preview_text  (GtkFontSelection *fontsel,
1522                                       const gchar      *text)
1523 {
1524   g_return_if_fail (GTK_IS_FONT_SELECTION (fontsel));
1525   g_return_if_fail (text != NULL);
1526
1527   gtk_entry_set_text (GTK_ENTRY (fontsel->preview_entry), text);
1528 }
1529
1530 /*****************************************************************************
1531  * GtkFontSelectionDialog
1532  *****************************************************************************/
1533
1534 static void gtk_font_selection_dialog_buildable_interface_init     (GtkBuildableIface *iface);
1535 static GObject * gtk_font_selection_dialog_buildable_get_internal_child (GtkBuildable *buildable,
1536                                                                           GtkBuilder   *builder,
1537                                                                           const gchar  *childname);
1538
1539 G_DEFINE_TYPE_WITH_CODE (GtkFontSelectionDialog, gtk_font_selection_dialog,
1540                          GTK_TYPE_DIALOG,
1541                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
1542                                                 gtk_font_selection_dialog_buildable_interface_init))
1543
1544 static GtkBuildableIface *parent_buildable_iface;
1545
1546 static void
1547 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
1548 {
1549 }
1550
1551 static void
1552 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
1553 {
1554   GtkDialog *dialog = GTK_DIALOG (fontseldiag);
1555   GtkWidget *action_area, *content_area;
1556
1557   content_area = gtk_dialog_get_content_area (dialog);
1558   action_area = gtk_dialog_get_action_area (dialog);
1559   
1560   gtk_dialog_set_has_separator (dialog, FALSE);
1561   gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
1562   gtk_box_set_spacing (GTK_BOX (content_area), 2); /* 2 * 5 + 2 = 12 */
1563   gtk_container_set_border_width (GTK_CONTAINER (action_area), 5);
1564   gtk_box_set_spacing (GTK_BOX (action_area), 6);
1565
1566   gtk_widget_push_composite_child ();
1567
1568   gtk_window_set_resizable (GTK_WINDOW (fontseldiag), TRUE);
1569   
1570   fontseldiag->main_vbox = content_area;
1571   
1572   fontseldiag->fontsel = gtk_font_selection_new ();
1573   gtk_container_set_border_width (GTK_CONTAINER (fontseldiag->fontsel), 5);
1574   gtk_widget_show (fontseldiag->fontsel);
1575   gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
1576                       fontseldiag->fontsel, TRUE, TRUE, 0);
1577   
1578   /* Create the action area */
1579   fontseldiag->action_area = action_area;
1580
1581   fontseldiag->cancel_button = gtk_dialog_add_button (dialog,
1582                                                       GTK_STOCK_CANCEL,
1583                                                       GTK_RESPONSE_CANCEL);
1584
1585   fontseldiag->apply_button = gtk_dialog_add_button (dialog,
1586                                                      GTK_STOCK_APPLY,
1587                                                      GTK_RESPONSE_APPLY);
1588   gtk_widget_hide (fontseldiag->apply_button);
1589
1590   fontseldiag->ok_button = gtk_dialog_add_button (dialog,
1591                                                   GTK_STOCK_OK,
1592                                                   GTK_RESPONSE_OK);
1593   gtk_widget_grab_default (fontseldiag->ok_button);
1594   
1595   gtk_dialog_set_alternative_button_order (GTK_DIALOG (fontseldiag),
1596                                            GTK_RESPONSE_OK,
1597                                            GTK_RESPONSE_APPLY,
1598                                            GTK_RESPONSE_CANCEL,
1599                                            -1);
1600
1601   gtk_window_set_title (GTK_WINDOW (fontseldiag),
1602                         _("Font Selection"));
1603
1604   gtk_widget_pop_composite_child ();
1605
1606   _gtk_dialog_set_ignore_separator (dialog, TRUE);
1607 }
1608
1609 /**
1610  * gtk_font_selection_dialog_new:
1611  * @title: the title of the dialog window 
1612  *
1613  * Creates a new #GtkFontSelectionDialog.
1614  *
1615  * Return value: a new #GtkFontSelectionDialog
1616  */
1617 GtkWidget*
1618 gtk_font_selection_dialog_new (const gchar *title)
1619 {
1620   GtkFontSelectionDialog *fontseldiag;
1621   
1622   fontseldiag = g_object_new (GTK_TYPE_FONT_SELECTION_DIALOG, NULL);
1623
1624   if (title)
1625     gtk_window_set_title (GTK_WINDOW (fontseldiag), title);
1626   
1627   return GTK_WIDGET (fontseldiag);
1628 }
1629
1630 /**
1631  * gtk_font_selection_dialog_get_font_selection:
1632  * @colorsel: a #GtkFontSelectionDialog
1633  *
1634  * Retrieves the #GtkFontSelection widget embedded in the dialog.
1635  *
1636  * Returns: the embedded #GtkFontSelection
1637  *
1638  * Since: 2.22
1639  **/
1640 GtkWidget*
1641 gtk_font_selection_dialog_get_font_selection (GtkFontSelectionDialog *fsd)
1642 {
1643   g_return_val_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd), NULL);
1644
1645   return fsd->fontsel;
1646 }
1647
1648
1649 /**
1650  * gtk_font_selection_dialog_get_ok_button:
1651  * @fsd: a #GtkFontSelectionDialog
1652  *
1653  * Gets the 'OK' button.
1654  *
1655  * Return value: the #GtkWidget used in the dialog for the 'OK' button.
1656  *
1657  * Since: 2.14
1658  */
1659 GtkWidget *
1660 gtk_font_selection_dialog_get_ok_button (GtkFontSelectionDialog *fsd)
1661 {
1662   g_return_val_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd), NULL);
1663
1664   return fsd->ok_button;
1665 }
1666
1667 /**
1668  * gtk_font_selection_dialog_get_cancel_button:
1669  * @fsd: a #GtkFontSelectionDialog
1670  *
1671  * Gets the 'Cancel' button.
1672  *
1673  * Return value: the #GtkWidget used in the dialog for the 'Cancel' button.
1674  *
1675  * Since: 2.14
1676  */
1677 GtkWidget *
1678 gtk_font_selection_dialog_get_cancel_button (GtkFontSelectionDialog *fsd)
1679 {
1680   g_return_val_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd), NULL);
1681
1682   return fsd->cancel_button;
1683 }
1684
1685 static void
1686 gtk_font_selection_dialog_buildable_interface_init (GtkBuildableIface *iface)
1687 {
1688   parent_buildable_iface = g_type_interface_peek_parent (iface);
1689   iface->get_internal_child = gtk_font_selection_dialog_buildable_get_internal_child;
1690 }
1691
1692 static GObject *
1693 gtk_font_selection_dialog_buildable_get_internal_child (GtkBuildable *buildable,
1694                                                         GtkBuilder   *builder,
1695                                                         const gchar  *childname)
1696 {
1697     if (strcmp(childname, "ok_button") == 0)
1698         return G_OBJECT (GTK_FONT_SELECTION_DIALOG(buildable)->ok_button);
1699     else if (strcmp(childname, "cancel_button") == 0)
1700         return G_OBJECT (GTK_FONT_SELECTION_DIALOG (buildable)->cancel_button);
1701     else if (strcmp(childname, "apply_button") == 0)
1702         return G_OBJECT (GTK_FONT_SELECTION_DIALOG(buildable)->apply_button);
1703     else if (strcmp(childname, "font_selection") == 0)
1704         return G_OBJECT (GTK_FONT_SELECTION_DIALOG(buildable)->fontsel);
1705
1706     return parent_buildable_iface->get_internal_child (buildable, builder, childname);
1707 }
1708
1709 /**
1710  * gtk_font_selection_dialog_get_font_name:
1711  * @fsd: a #GtkFontSelectionDialog
1712  * 
1713  * Gets the currently-selected font name.
1714  *
1715  * Note that this can be a different string than what you set with 
1716  * gtk_font_selection_dialog_set_font_name(), as the font selection widget
1717  * may normalize font names and thus return a string with a different 
1718  * structure. For example, "Helvetica Italic Bold 12" could be normalized 
1719  * to "Helvetica Bold Italic 12".  Use pango_font_description_equal()
1720  * if you want to compare two font descriptions.
1721  * 
1722  * Return value: A string with the name of the current font, or %NULL if no 
1723  *     font is selected. You must free this string with g_free().
1724  */
1725 gchar*
1726 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
1727 {
1728   g_return_val_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd), NULL);
1729
1730   return gtk_font_selection_get_font_name (GTK_FONT_SELECTION (fsd->fontsel));
1731 }
1732
1733 /**
1734  * gtk_font_selection_dialog_set_font_name:
1735  * @fsd: a #GtkFontSelectionDialog
1736  * @fontname: a font name like "Helvetica 12" or "Times Bold 18"
1737  *
1738  * Sets the currently selected font. 
1739  * 
1740  * Return value: %TRUE if the font selected in @fsd is now the
1741  *     @fontname specified, %FALSE otherwise. 
1742  */
1743 gboolean
1744 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
1745                                          const gchar            *fontname)
1746 {
1747   g_return_val_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd), FALSE);
1748   g_return_val_if_fail (fontname, FALSE);
1749
1750   return gtk_font_selection_set_font_name (GTK_FONT_SELECTION (fsd->fontsel), fontname);
1751 }
1752
1753 /**
1754  * gtk_font_selection_dialog_get_preview_text:
1755  * @fsd: a #GtkFontSelectionDialog
1756  *
1757  * Gets the text displayed in the preview area.
1758  * 
1759  * Return value: the text displayed in the preview area. 
1760  *     This string is owned by the widget and should not be 
1761  *     modified or freed 
1762  */
1763 G_CONST_RETURN gchar*
1764 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
1765 {
1766   g_return_val_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd), NULL);
1767
1768   return gtk_font_selection_get_preview_text (GTK_FONT_SELECTION (fsd->fontsel));
1769 }
1770
1771 /**
1772  * gtk_font_selection_dialog_set_preview_text:
1773  * @fsd: a #GtkFontSelectionDialog
1774  * @text: the text to display in the preview area
1775  *
1776  * Sets the text displayed in the preview area. 
1777  */
1778 void
1779 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
1780                                             const gchar            *text)
1781 {
1782   g_return_if_fail (GTK_IS_FONT_SELECTION_DIALOG (fsd));
1783   g_return_if_fail (text != NULL);
1784
1785   gtk_font_selection_set_preview_text (GTK_FONT_SELECTION (fsd->fontsel), text);
1786 }