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