]> Pileus Git - ~andy/gtk/blob - gtk/gtkfontsel.c
Check that the fontsel has a screen assigned before doing anything. This
[~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 "gtkalias.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 /* This is the initial and maximum height of the preview entry (it expands
77    when large font sizes are selected). Initial height is also the minimum. */
78 #define INITIAL_PREVIEW_HEIGHT 44
79 #define MAX_PREVIEW_HEIGHT 300
80
81 /* These are the sizes of the font, style & size lists. */
82 #define FONT_LIST_HEIGHT        136
83 #define FONT_LIST_WIDTH         190
84 #define FONT_STYLE_LIST_WIDTH   170
85 #define FONT_SIZE_LIST_WIDTH    60
86
87 /* These are what we use as the standard font sizes, for the size list.
88  */
89 static const guint16 font_sizes[] = {
90   8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28,
91   32, 36, 40, 48, 56, 64, 72
92 };
93
94 enum {
95    PROP_0,
96    PROP_FONT_NAME,
97    PROP_FONT,
98    PROP_PREVIEW_TEXT
99 };
100
101
102 enum {
103   FAMILY_COLUMN,
104   FAMILY_NAME_COLUMN
105 };
106
107 enum {
108   FACE_COLUMN,
109   FACE_NAME_COLUMN
110 };
111
112 enum {
113   SIZE_COLUMN
114 };
115
116 static void    gtk_font_selection_class_init         (GtkFontSelectionClass *klass);
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_init               (GtkFontSelection      *fontsel);
126 static void    gtk_font_selection_finalize           (GObject               *object);
127 static void    gtk_font_selection_screen_changed     (GtkWidget             *widget,
128                                                       GdkScreen             *previous_screen);
129
130 /* These are the callbacks & related functions. */
131 static void     gtk_font_selection_select_font           (GtkTreeSelection *selection,
132                                                           gpointer          data);
133 static void     gtk_font_selection_show_available_fonts  (GtkFontSelection *fs);
134
135 static void     gtk_font_selection_show_available_styles (GtkFontSelection *fs);
136 static void     gtk_font_selection_select_best_style     (GtkFontSelection *fs,
137                                                           gboolean          use_first);
138 static void     gtk_font_selection_select_style          (GtkTreeSelection *selection,
139                                                           gpointer          data);
140
141 static void     gtk_font_selection_select_best_size      (GtkFontSelection *fs);
142 static void     gtk_font_selection_show_available_sizes  (GtkFontSelection *fs,
143                                                           gboolean          first_time);
144 static void     gtk_font_selection_size_activate         (GtkWidget        *w,
145                                                           gpointer          data);
146 static gboolean gtk_font_selection_size_focus_out        (GtkWidget        *w,
147                                                           GdkEventFocus    *event,
148                                                           gpointer          data);
149 static void     gtk_font_selection_select_size           (GtkTreeSelection *selection,
150                                                           gpointer          data);
151
152 static void     gtk_font_selection_scroll_on_map         (GtkWidget        *w,
153                                                           gpointer          data);
154
155 static void     gtk_font_selection_preview_changed       (GtkWidget        *entry,
156                                                           GtkFontSelection *fontsel);
157
158 /* Misc. utility functions. */
159 static void    gtk_font_selection_load_font          (GtkFontSelection *fs);
160 static void    gtk_font_selection_update_preview     (GtkFontSelection *fs);
161
162 static GdkFont* gtk_font_selection_get_font_internal (GtkFontSelection *fontsel);
163
164 /* FontSelectionDialog */
165 static void    gtk_font_selection_dialog_class_init  (GtkFontSelectionDialogClass *klass);
166 static void    gtk_font_selection_dialog_init        (GtkFontSelectionDialog *fontseldiag);
167
168 static GtkVBoxClass *font_selection_parent_class = NULL;
169 static GtkWindowClass *font_selection_dialog_parent_class = NULL;
170
171
172 GType
173 gtk_font_selection_get_type (void)
174 {
175   static GType font_selection_type = 0;
176   
177   if (!font_selection_type)
178     {
179       static const GTypeInfo fontsel_type_info =
180       {
181         sizeof (GtkFontSelectionClass),
182         NULL,           /* base_init */
183         NULL,           /* base_finalize */
184         (GClassInitFunc) gtk_font_selection_class_init,
185         NULL,           /* class_finalize */
186         NULL,           /* class_data */
187         sizeof (GtkFontSelection),
188         0,              /* n_preallocs */
189         (GInstanceInitFunc) gtk_font_selection_init,
190       };
191       
192       font_selection_type =
193         g_type_register_static (GTK_TYPE_VBOX, I_("GtkFontSelection"),
194                                 &fontsel_type_info, 0);
195     }
196   
197   return font_selection_type;
198 }
199
200 static void
201 gtk_font_selection_class_init (GtkFontSelectionClass *klass)
202 {
203   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
204   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
205   
206   font_selection_parent_class = g_type_class_peek_parent (klass);
207   
208   gobject_class->set_property = gtk_font_selection_set_property;
209   gobject_class->get_property = gtk_font_selection_get_property;
210
211   widget_class->screen_changed = gtk_font_selection_screen_changed;
212    
213   g_object_class_install_property (gobject_class,
214                                    PROP_FONT_NAME,
215                                    g_param_spec_string ("font-name",
216                                                         P_("Font name"),
217                                                         P_("The X string that represents this font"),
218                                                         NULL,
219                                                         GTK_PARAM_READWRITE));
220   g_object_class_install_property (gobject_class,
221                                    PROP_FONT,
222                                    g_param_spec_boxed ("font",
223                                                        P_("Font"),
224                                                        P_("The GdkFont that is currently selected"),
225                                                        GDK_TYPE_FONT,
226                                                        GTK_PARAM_READABLE));
227   g_object_class_install_property (gobject_class,
228                                    PROP_PREVIEW_TEXT,
229                                    g_param_spec_string ("preview-text",
230                                                         P_("Preview text"),
231                                                         P_("The text to display in order to demonstrate the selected font"),
232                                                         PREVIEW_TEXT,
233                                                         GTK_PARAM_READWRITE));
234   gobject_class->finalize = gtk_font_selection_finalize;
235 }
236
237 static void 
238 gtk_font_selection_set_property (GObject         *object,
239                                  guint            prop_id,
240                                  const GValue    *value,
241                                  GParamSpec      *pspec)
242 {
243   GtkFontSelection *fontsel;
244
245   fontsel = GTK_FONT_SELECTION (object);
246
247   switch (prop_id)
248     {
249     case PROP_FONT_NAME:
250       gtk_font_selection_set_font_name (fontsel, g_value_get_string (value));
251       break;
252     case PROP_PREVIEW_TEXT:
253       gtk_font_selection_set_preview_text (fontsel, g_value_get_string (value));
254       break;
255     default:
256       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
257       break;
258     }
259 }
260
261 static void gtk_font_selection_get_property (GObject         *object,
262                                              guint            prop_id,
263                                              GValue          *value,
264                                              GParamSpec      *pspec)
265 {
266   GtkFontSelection *fontsel;
267
268   fontsel = GTK_FONT_SELECTION (object);
269
270   switch (prop_id)
271     {
272     case PROP_FONT_NAME:
273       g_value_set_string (value, gtk_font_selection_get_font_name (fontsel));
274       break;
275     case PROP_FONT:
276       g_value_set_object (value, gtk_font_selection_get_font_internal (fontsel));
277       break;
278     case PROP_PREVIEW_TEXT:
279       g_value_set_string (value, gtk_font_selection_get_preview_text (fontsel));
280       break;
281     default:
282       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
283       break;
284     }
285 }
286
287 /* Handles key press events on the lists, so that we can trap Enter to
288  * activate the default button on our own.
289  */
290 static gboolean
291 list_row_activated (GtkWidget *widget)
292 {
293   GtkWindow *window;
294   
295   window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget)));
296   if (!GTK_WIDGET_TOPLEVEL (window))
297     window = NULL;
298   
299   if (window
300       && widget != window->default_widget
301       && !(widget == window->focus_widget &&
302            (!window->default_widget || !GTK_WIDGET_SENSITIVE (window->default_widget))))
303     {
304       gtk_window_activate_default (window);
305     }
306   
307   return TRUE;
308 }
309
310 static void
311 gtk_font_selection_init (GtkFontSelection *fontsel)
312 {
313   GtkWidget *scrolled_win;
314   GtkWidget *text_frame;
315   GtkWidget *text_box;
316   GtkWidget *table, *label;
317   GtkWidget *font_label, *style_label;
318   GtkListStore *model;
319   GtkTreeViewColumn *column;
320   GList *focus_chain = NULL;
321   AtkObject *atk_obj;
322
323   gtk_widget_push_composite_child ();
324
325   fontsel->size = 12 * PANGO_SCALE;
326   
327   /* Create the table of font, style & size. */
328   table = gtk_table_new (3, 3, FALSE);
329   gtk_widget_show (table);
330   gtk_table_set_col_spacings (GTK_TABLE (table), 8);
331   gtk_box_pack_start (GTK_BOX (fontsel), table, TRUE, TRUE, 0);
332
333 #ifdef INCLUDE_FONT_ENTRIES
334   fontsel->font_entry = gtk_entry_new ();
335   gtk_editable_set_editable (GTK_EDITABLE (fontsel->font_entry), FALSE);
336   gtk_widget_set_size_request (fontsel->font_entry, 20, -1);
337   gtk_widget_show (fontsel->font_entry);
338   gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
339                     GTK_FILL, 0, 0, 0);
340   
341   fontsel->font_style_entry = gtk_entry_new ();
342   gtk_editable_set_editable (GTK_EDITABLE (fontsel->font_style_entry), FALSE);
343   gtk_widget_set_size_request (fontsel->font_style_entry, 20, -1);
344   gtk_widget_show (fontsel->font_style_entry);
345   gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
346                     GTK_FILL, 0, 0, 0);
347 #endif /* INCLUDE_FONT_ENTRIES */
348   
349   fontsel->size_entry = gtk_entry_new ();
350   gtk_widget_set_size_request (fontsel->size_entry, 20, -1);
351   gtk_widget_show (fontsel->size_entry);
352   gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
353                     GTK_FILL, 0, 0, 0);
354   g_signal_connect (fontsel->size_entry, "activate",
355                     G_CALLBACK (gtk_font_selection_size_activate),
356                     fontsel);
357   g_signal_connect_after (fontsel->size_entry, "focus_out_event",
358                           G_CALLBACK (gtk_font_selection_size_focus_out),
359                           fontsel);
360   
361   font_label = gtk_label_new_with_mnemonic (_("_Family:"));
362   gtk_misc_set_alignment (GTK_MISC (font_label), 0.0, 0.5);
363   gtk_widget_show (font_label);
364   gtk_table_attach (GTK_TABLE (table), font_label, 0, 1, 0, 1,
365                     GTK_FILL, 0, 0, 0);  
366
367   style_label = gtk_label_new_with_mnemonic (_("_Style:"));
368   gtk_misc_set_alignment (GTK_MISC (style_label), 0.0, 0.5);
369   gtk_widget_show (style_label);
370   gtk_table_attach (GTK_TABLE (table), style_label, 1, 2, 0, 1,
371                     GTK_FILL, 0, 0, 0);
372   
373   label = gtk_label_new_with_mnemonic (_("Si_ze:"));
374   gtk_label_set_mnemonic_widget (GTK_LABEL (label),
375                                  fontsel->size_entry);
376   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
377   gtk_widget_show (label);
378   gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
379                     GTK_FILL, 0, 0, 0);
380   
381   
382   /* Create the lists  */
383
384   model = gtk_list_store_new (2,
385                               G_TYPE_OBJECT,  /* FAMILY_COLUMN */
386                               G_TYPE_STRING); /* FAMILY_NAME_COLUMN */
387   fontsel->family_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
388   g_object_unref (model);
389
390   g_signal_connect (fontsel->family_list, "row-activated",
391                     G_CALLBACK (list_row_activated), fontsel);
392
393   column = gtk_tree_view_column_new_with_attributes ("Family",
394                                                      gtk_cell_renderer_text_new (),
395                                                      "text", FAMILY_NAME_COLUMN,
396                                                      NULL);
397   gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
398   gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->family_list), column);
399
400   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->family_list), FALSE);
401   gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)),
402                                GTK_SELECTION_BROWSE);
403   
404   gtk_label_set_mnemonic_widget (GTK_LABEL (font_label), fontsel->family_list);
405
406   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
407   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
408   gtk_widget_set_size_request (scrolled_win,
409                                FONT_LIST_WIDTH, FONT_LIST_HEIGHT);
410   gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->family_list);
411   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
412                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
413   gtk_widget_show (fontsel->family_list);
414   gtk_widget_show (scrolled_win);
415
416   gtk_table_attach (GTK_TABLE (table), scrolled_win, 0, 1, 1, 3,
417                     GTK_EXPAND | GTK_FILL,
418                     GTK_EXPAND | GTK_FILL, 0, 0);
419   focus_chain = g_list_append (focus_chain, scrolled_win);
420   
421   model = gtk_list_store_new (2,
422                               G_TYPE_OBJECT,  /* FACE_COLUMN */
423                               G_TYPE_STRING); /* FACE_NAME_COLUMN */
424   fontsel->face_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
425   g_object_unref (model);
426   g_signal_connect (fontsel->face_list, "row-activated",
427                     G_CALLBACK (list_row_activated), fontsel);
428
429   gtk_label_set_mnemonic_widget (GTK_LABEL (style_label), fontsel->face_list);
430
431   column = gtk_tree_view_column_new_with_attributes ("Face",
432                                                      gtk_cell_renderer_text_new (),
433                                                      "text", FACE_NAME_COLUMN,
434                                                      NULL);
435   gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
436   gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->face_list), column);
437
438   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->face_list), FALSE);
439   gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)),
440                                GTK_SELECTION_BROWSE);
441   
442   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
443   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
444   gtk_widget_set_size_request (scrolled_win,
445                                FONT_STYLE_LIST_WIDTH, FONT_LIST_HEIGHT);
446   gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->face_list);
447   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
448                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
449   gtk_widget_show (fontsel->face_list);
450   gtk_widget_show (scrolled_win);
451   gtk_table_attach (GTK_TABLE (table), scrolled_win, 1, 2, 1, 3,
452                     GTK_EXPAND | GTK_FILL,
453                     GTK_EXPAND | GTK_FILL, 0, 0);
454   focus_chain = g_list_append (focus_chain, scrolled_win);
455   
456   focus_chain = g_list_append (focus_chain, fontsel->size_entry);
457
458   model = gtk_list_store_new (1, G_TYPE_INT);
459   fontsel->size_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
460   g_object_unref (model);
461   g_signal_connect (fontsel->size_list, "row-activated",
462                     G_CALLBACK (list_row_activated), fontsel);
463
464   column = gtk_tree_view_column_new_with_attributes ("Size",
465                                                      gtk_cell_renderer_text_new (),
466                                                      "text", SIZE_COLUMN,
467                                                      NULL);
468   gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
469   gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->size_list), column);
470
471   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->size_list), FALSE);
472   gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)),
473                                GTK_SELECTION_BROWSE);
474   
475   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
476   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
477   gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->size_list);
478   gtk_widget_set_size_request (scrolled_win, -1, FONT_LIST_HEIGHT);
479   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
480                                   GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
481   gtk_widget_show (fontsel->size_list);
482   gtk_widget_show (scrolled_win);
483   gtk_table_attach (GTK_TABLE (table), scrolled_win, 2, 3, 2, 3,
484                     GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
485   focus_chain = g_list_append (focus_chain, scrolled_win);
486
487   gtk_container_set_focus_chain (GTK_CONTAINER (table), focus_chain);
488   g_list_free (focus_chain);
489   
490   /* Insert the fonts. */
491   g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)), "changed",
492                     G_CALLBACK (gtk_font_selection_select_font), fontsel);
493
494   g_signal_connect_after (fontsel->family_list, "map",
495                           G_CALLBACK (gtk_font_selection_scroll_on_map),
496                           fontsel);
497   
498   g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)), "changed",
499                     G_CALLBACK (gtk_font_selection_select_style), fontsel);
500
501   g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)), "changed",
502                     G_CALLBACK (gtk_font_selection_select_size), fontsel);
503   atk_obj = gtk_widget_get_accessible (fontsel->size_list);
504   if (GTK_IS_ACCESSIBLE (atk_obj))
505     {
506       /* Accessibility support is enabled.
507        * Make the label ATK_RELATON_LABEL_FOR for the size list as well.
508        */
509       AtkObject *atk_label;
510       AtkRelationSet *relation_set;
511       AtkRelation *relation;
512       AtkObject *obj_array[1];
513       GPtrArray *array;
514
515       atk_label = gtk_widget_get_accessible (label);
516       relation_set = atk_object_ref_relation_set (atk_obj);
517       relation = atk_relation_set_get_relation_by_type (relation_set, ATK_RELATION_LABELLED_BY);
518       if (relation)
519         {
520           array = atk_relation_get_target (relation);
521           g_ptr_array_add (array, atk_label);
522         }
523       else 
524         {
525           obj_array[0] = atk_label;
526           relation = atk_relation_new (obj_array, 1, ATK_RELATION_LABELLED_BY);
527           atk_relation_set_add (relation_set, relation);
528         }
529       g_object_unref (relation_set);
530
531       relation_set = atk_object_ref_relation_set (atk_label);
532       relation = atk_relation_set_get_relation_by_type (relation_set, ATK_RELATION_LABEL_FOR);
533       if (relation)
534         {
535           array = atk_relation_get_target (relation);
536           g_ptr_array_add (array, atk_obj);
537         }
538       else 
539         {
540           obj_array[0] = atk_obj;
541           relation = atk_relation_new (obj_array, 1, ATK_RELATION_LABEL_FOR);
542           atk_relation_set_add (relation_set, relation);
543         }
544       g_object_unref (relation_set);
545     }    
546       
547
548   /* create the text entry widget */
549   label = gtk_label_new_with_mnemonic (_("_Preview:"));
550   gtk_widget_show (label);
551   
552   text_frame = gtk_frame_new (NULL);
553   gtk_frame_set_label_widget (GTK_FRAME (text_frame), label);
554   
555   gtk_widget_show (text_frame);
556   gtk_frame_set_shadow_type (GTK_FRAME (text_frame), GTK_SHADOW_ETCHED_IN);
557   gtk_box_pack_start (GTK_BOX (fontsel), text_frame,
558                       FALSE, TRUE, 0);
559   
560   /* This is just used to get a 4-pixel space around the preview entry. */
561   text_box = gtk_hbox_new (FALSE, 0);
562   gtk_widget_show (text_box);
563   gtk_container_add (GTK_CONTAINER (text_frame), text_box);
564   gtk_container_set_border_width (GTK_CONTAINER (text_box), 4);
565   
566   fontsel->preview_entry = gtk_entry_new ();
567   gtk_label_set_mnemonic_widget (GTK_LABEL (label), fontsel->preview_entry);
568   
569   gtk_widget_show (fontsel->preview_entry);
570   g_signal_connect (fontsel->preview_entry, "changed",
571                     G_CALLBACK (gtk_font_selection_preview_changed), fontsel);
572   gtk_widget_set_size_request (fontsel->preview_entry,
573                                -1, INITIAL_PREVIEW_HEIGHT);
574   gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
575                       TRUE, TRUE, 0);
576
577   gtk_widget_pop_composite_child();
578 }
579
580 GtkWidget *
581 gtk_font_selection_new (void)
582 {
583   GtkFontSelection *fontsel;
584   
585   fontsel = g_object_new (GTK_TYPE_FONT_SELECTION, NULL);
586   
587   return GTK_WIDGET (fontsel);
588 }
589
590 static void
591 gtk_font_selection_finalize (GObject *object)
592 {
593   GtkFontSelection *fontsel;
594   
595   g_return_if_fail (GTK_IS_FONT_SELECTION (object));
596   
597   fontsel = GTK_FONT_SELECTION (object);
598
599   if (fontsel->font)
600     gdk_font_unref (fontsel->font);
601   
602   (* G_OBJECT_CLASS (font_selection_parent_class)->finalize) (object);
603 }
604
605 static void
606 gtk_font_selection_screen_changed (GtkWidget *widget,
607                                    GdkScreen *previous_screen)
608 {
609   GtkFontSelection *fontsel = GTK_FONT_SELECTION (widget);
610
611   if (gtk_widget_has_screen (GTK_WIDGET (fontsel)))
612     {
613       gtk_font_selection_show_available_fonts (fontsel);
614       gtk_font_selection_show_available_sizes (fontsel, TRUE);
615       gtk_font_selection_show_available_styles (fontsel);
616     }
617 }
618
619 static void
620 gtk_font_selection_preview_changed (GtkWidget        *entry,
621                                     GtkFontSelection *fontsel)
622 {
623   g_object_notify (G_OBJECT (fontsel), "preview_text");
624 }
625
626 static void
627 scroll_to_selection (GtkTreeView *tree_view)
628 {
629   GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
630   GtkTreeModel *model;
631   GtkTreeIter iter;
632
633   if (gtk_tree_selection_get_selected (selection, &model, &iter))
634     {
635       GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
636       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.5);
637       gtk_tree_path_free (path);
638     }
639 }
640
641 static void
642 set_cursor_to_iter (GtkTreeView *view,
643                     GtkTreeIter *iter)
644 {
645   GtkTreeModel *model = gtk_tree_view_get_model (view);
646   GtkTreePath *path = gtk_tree_model_get_path (model, iter);
647   
648   gtk_tree_view_set_cursor (view, path, NULL, FALSE);
649
650   gtk_tree_path_free (path);
651 }
652
653 /* This is called when the list is mapped. Here we scroll to the current
654    font if necessary. */
655 static void
656 gtk_font_selection_scroll_on_map (GtkWidget             *widget,
657                                   gpointer               data)
658 {
659   GtkFontSelection *fontsel;
660   
661 #ifdef FONTSEL_DEBUG
662   g_message ("In expose_list\n");
663 #endif
664   fontsel = GTK_FONT_SELECTION (data);
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 }
675
676 /* This is called when a family is selected in the list. */
677 static void
678 gtk_font_selection_select_font (GtkTreeSelection *selection,
679                                 gpointer          data)
680 {
681   GtkFontSelection *fontsel;
682   GtkTreeModel *model;
683   GtkTreeIter iter;
684 #ifdef INCLUDE_FONT_ENTRIES
685   const gchar *family_name;
686 #endif
687
688   fontsel = GTK_FONT_SELECTION (data);
689
690   if (gtk_tree_selection_get_selected (selection, &model, &iter))
691     {
692       PangoFontFamily *family;
693       
694       gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
695       if (fontsel->family != family)
696         {
697           fontsel->family = family;
698           
699 #ifdef INCLUDE_FONT_ENTRIES
700           family_name = pango_font_family_get_name (fontsel->family);
701           gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), family_name);
702 #endif
703           
704           gtk_font_selection_show_available_styles (fontsel);
705           gtk_font_selection_select_best_style (fontsel, TRUE);
706         }
707
708       g_object_unref (family);
709     }
710 }
711
712 static int
713 cmp_families (const void *a, const void *b)
714 {
715   const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a);
716   const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b);
717   
718   return g_utf8_collate (a_name, b_name);
719 }
720
721 static void
722 gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
723 {
724   GtkListStore *model;
725   PangoFontFamily **families;
726   PangoFontFamily *match_family = NULL;
727   gint n_families, i;
728   GtkTreeIter match_row;
729   
730   model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list)));
731   
732   pango_context_list_families (gtk_widget_get_pango_context (GTK_WIDGET (fontsel)),
733                                &families, &n_families);
734   qsort (families, n_families, sizeof (PangoFontFamily *), cmp_families);
735
736   gtk_list_store_clear (model);
737
738   for (i=0; i<n_families; i++)
739     {
740       const gchar *name = pango_font_family_get_name (families[i]);
741       GtkTreeIter iter;
742
743       gtk_list_store_append (model, &iter);
744       gtk_list_store_set (model, &iter,
745                           FAMILY_COLUMN, families[i],
746                           FAMILY_NAME_COLUMN, name,
747                           -1);
748       
749       if (i == 0 || !g_ascii_strcasecmp (name, "sans"))
750         {
751           match_family = families[i];
752           match_row = iter;
753         }
754     }
755
756   fontsel->family = match_family;
757   if (match_family)
758     {
759       set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &match_row);
760 #ifdef INCLUDE_FONT_ENTRIES
761       gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), 
762                           pango_font_family_get_name (match_family));
763 #endif /* INCLUDE_FONT_ENTRIES */
764     }
765
766   g_free (families);
767 }
768
769 static int
770 compare_font_descriptions (const PangoFontDescription *a, const PangoFontDescription *b)
771 {
772   int val = strcmp (pango_font_description_get_family (a), pango_font_description_get_family (b));
773   if (val != 0)
774     return val;
775
776   if (pango_font_description_get_weight (a) != pango_font_description_get_weight (b))
777     return pango_font_description_get_weight (a) - pango_font_description_get_weight (b);
778
779   if (pango_font_description_get_style (a) != pango_font_description_get_style (b))
780     return pango_font_description_get_style (a) - pango_font_description_get_style (b);
781   
782   if (pango_font_description_get_stretch (a) != pango_font_description_get_stretch (b))
783     return pango_font_description_get_stretch (a) - pango_font_description_get_stretch (b);
784
785   if (pango_font_description_get_variant (a) != pango_font_description_get_variant (b))
786     return pango_font_description_get_variant (a) - pango_font_description_get_variant (b);
787
788   return 0;
789 }
790
791 static int
792 faces_sort_func (const void *a, const void *b)
793 {
794   PangoFontDescription *desc_a = pango_font_face_describe (*(PangoFontFace **)a);
795   PangoFontDescription *desc_b = pango_font_face_describe (*(PangoFontFace **)b);
796   
797   int ord = compare_font_descriptions (desc_a, desc_b);
798
799   pango_font_description_free (desc_a);
800   pango_font_description_free (desc_b);
801
802   return ord;
803 }
804
805 static gboolean
806 font_description_style_equal (const PangoFontDescription *a,
807                               const PangoFontDescription *b)
808 {
809   return (pango_font_description_get_weight (a) == pango_font_description_get_weight (b) &&
810           pango_font_description_get_style (a) == pango_font_description_get_style (b) &&
811           pango_font_description_get_stretch (a) == pango_font_description_get_stretch (b) &&
812           pango_font_description_get_variant (a) == pango_font_description_get_variant (b));
813 }
814
815 /* This fills the font style list with all the possible style combinations
816    for the current font family. */
817 static void
818 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
819 {
820   gint n_faces, i;
821   PangoFontFace **faces;
822   PangoFontDescription *old_desc;
823   GtkListStore *model;
824   GtkTreeIter match_row;
825   PangoFontFace *match_face = NULL;
826   
827   model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list)));
828   
829   if (fontsel->face)
830     old_desc = pango_font_face_describe (fontsel->face);
831   else
832     old_desc= NULL;
833
834   pango_font_family_list_faces (fontsel->family, &faces, &n_faces);
835   qsort (faces, n_faces, sizeof (PangoFontFace *), faces_sort_func);
836
837   gtk_list_store_clear (model);
838
839   for (i=0; i < n_faces; i++)
840     {
841       GtkTreeIter iter;
842       const gchar *str = pango_font_face_get_face_name (faces[i]);
843
844       gtk_list_store_append (model, &iter);
845       gtk_list_store_set (model, &iter,
846                           FACE_COLUMN, faces[i],
847                           FACE_NAME_COLUMN, str,
848                           -1);
849
850       if (i == 0)
851         {
852           match_row = iter;
853           match_face = faces[i];
854         }
855       else if (old_desc)
856         {
857           PangoFontDescription *tmp_desc = pango_font_face_describe (faces[i]);
858           
859           if (font_description_style_equal (tmp_desc, old_desc))
860             {
861               match_row = iter;
862               match_face = faces[i];
863             }
864       
865           pango_font_description_free (tmp_desc);
866         }
867     }
868
869   if (old_desc)
870     pango_font_description_free (old_desc);
871
872   fontsel->face = match_face;
873   if (match_face)
874     {
875 #ifdef INCLUDE_FONT_ENTRIES
876       const gchar *str = pango_font_face_get_face_name (fontsel->face);
877
878       gtk_entry_set_text (GTK_ENTRY (fontsel->font_style_entry), str);
879 #endif      
880       set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_row);
881     }
882
883   g_free (faces);
884 }
885
886 /* This selects a style when the user selects a font. It just uses the first
887    available style at present. I was thinking of trying to maintain the
888    selected style, e.g. bold italic, when the user selects different fonts.
889    However, the interface is so easy to use now I'm not sure it's worth it.
890    Note: This will load a font. */
891 static void
892 gtk_font_selection_select_best_style (GtkFontSelection *fontsel,
893                                       gboolean          use_first)
894 {
895   GtkTreeIter iter;
896   GtkTreeModel *model;
897
898   model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
899
900   if (gtk_tree_model_get_iter_first (model, &iter))
901     {
902       set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &iter);
903       scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
904     }
905
906   gtk_font_selection_show_available_sizes (fontsel, FALSE);
907   gtk_font_selection_select_best_size (fontsel);
908 }
909
910
911 /* This is called when a style is selected in the list. */
912 static void
913 gtk_font_selection_select_style (GtkTreeSelection *selection,
914                                  gpointer          data)
915 {
916   GtkFontSelection *fontsel = GTK_FONT_SELECTION (data);
917   GtkTreeModel *model;
918   GtkTreeIter iter;
919   
920   if (gtk_tree_selection_get_selected (selection, &model, &iter))
921     {
922       PangoFontFace *face;
923       
924       gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
925       fontsel->face = face;
926
927       g_object_unref (face);
928     }
929
930   gtk_font_selection_show_available_sizes (fontsel, FALSE);
931   gtk_font_selection_select_best_size (fontsel);
932 }
933
934 static void
935 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel,
936                                          gboolean          first_time)
937 {
938   gint i;
939   GtkListStore *model;
940   gchar buffer[128];
941   gchar *p;
942       
943   model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->size_list)));
944
945   /* Insert the standard font sizes */
946   if (first_time)
947     {
948       gtk_list_store_clear (model);
949
950       for (i = 0; i < G_N_ELEMENTS (font_sizes); i++)
951         {
952           GtkTreeIter iter;
953           
954           gtk_list_store_append (model, &iter);
955           gtk_list_store_set (model, &iter, SIZE_COLUMN, font_sizes[i], -1);
956           
957           if (font_sizes[i] * PANGO_SCALE == fontsel->size)
958             set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
959         }
960     }
961   else
962     {
963       GtkTreeIter iter;
964       gboolean found = FALSE;
965       
966       gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
967       for (i = 0; i < G_N_ELEMENTS (font_sizes) && !found; i++)
968         {
969           if (font_sizes[i] * PANGO_SCALE == fontsel->size)
970             {
971               set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
972               found = TRUE;
973             }
974
975           gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter);
976         }
977
978       if (!found)
979         {
980           GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
981           gtk_tree_selection_unselect_all (selection);
982         }
983     }
984
985   /* Set the entry to the new size, rounding to 1 digit,
986    * trimming of trailing 0's and a trailing period
987    */
988   g_snprintf (buffer, sizeof (buffer), "%.1f", fontsel->size / (1.0 * PANGO_SCALE));
989   if (strchr (buffer, '.'))
990     {
991       p = buffer + strlen (buffer) - 1;
992       while (*p == '0')
993         p--;
994       if (*p == '.')
995         p--;
996       p[1] = '\0';
997     }
998
999   /* Compare, to avoid moving the cursor unecessarily */
1000   if (strcmp (gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry)), buffer) != 0)
1001     gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
1002 }
1003
1004 static void
1005 gtk_font_selection_select_best_size (GtkFontSelection *fontsel)
1006 {
1007   gtk_font_selection_load_font (fontsel);  
1008 }
1009
1010 static void
1011 gtk_font_selection_set_size (GtkFontSelection *fontsel,
1012                              gint              new_size)
1013 {
1014   if (fontsel->size != new_size)
1015     {
1016       fontsel->size = new_size;
1017
1018       gtk_font_selection_show_available_sizes (fontsel, FALSE);      
1019       gtk_font_selection_load_font (fontsel);
1020     }
1021 }
1022
1023 /* If the user hits return in the font size entry, we change to the new font
1024    size. */
1025 static void
1026 gtk_font_selection_size_activate (GtkWidget   *w,
1027                                   gpointer     data)
1028 {
1029   GtkFontSelection *fontsel;
1030   gint new_size;
1031   const gchar *text;
1032   
1033   fontsel = GTK_FONT_SELECTION (data);
1034
1035   text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1036   new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);
1037
1038   if (fontsel->size != new_size)
1039     gtk_font_selection_set_size (fontsel, new_size);
1040   else 
1041     list_row_activated (w);
1042 }
1043
1044 static gboolean
1045 gtk_font_selection_size_focus_out (GtkWidget     *w,
1046                                    GdkEventFocus *event,
1047                                    gpointer       data)
1048 {
1049   GtkFontSelection *fontsel;
1050   gint new_size;
1051   const gchar *text;
1052   
1053   fontsel = GTK_FONT_SELECTION (data);
1054
1055   text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1056   new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);
1057
1058   gtk_font_selection_set_size (fontsel, new_size);
1059   
1060   return TRUE;
1061 }
1062
1063 /* This is called when a size is selected in the list. */
1064 static void
1065 gtk_font_selection_select_size (GtkTreeSelection *selection,
1066                                 gpointer          data)
1067 {
1068   GtkFontSelection *fontsel;
1069   GtkTreeModel *model;
1070   GtkTreeIter iter;
1071   gint new_size;
1072   
1073   fontsel = GTK_FONT_SELECTION (data);
1074   
1075   if (gtk_tree_selection_get_selected (selection, &model, &iter))
1076     {
1077       gtk_tree_model_get (model, &iter, SIZE_COLUMN, &new_size, -1);
1078       gtk_font_selection_set_size (fontsel, new_size * PANGO_SCALE);
1079     }
1080 }
1081
1082 static void
1083 gtk_font_selection_load_font (GtkFontSelection *fontsel)
1084 {
1085   if (fontsel->font)
1086     gdk_font_unref (fontsel->font);
1087   fontsel->font = NULL;
1088
1089   gtk_font_selection_update_preview (fontsel);
1090 }
1091
1092 static PangoFontDescription *
1093 gtk_font_selection_get_font_description (GtkFontSelection *fontsel)
1094 {
1095   PangoFontDescription *font_desc;
1096
1097   if (fontsel->face)
1098     {
1099       font_desc = pango_font_face_describe (fontsel->face);
1100       pango_font_description_set_size (font_desc, fontsel->size);
1101     }
1102   else
1103     font_desc = pango_font_description_from_string ("Sans 10");
1104
1105   return font_desc;
1106 }
1107
1108 /* This sets the font in the preview entry to the selected font, and tries to
1109    make sure that the preview entry is a reasonable size, i.e. so that the
1110    text can be seen with a bit of space to spare. But it tries to avoid
1111    resizing the entry every time the font changes.
1112    This also used to shrink the preview if the font size was decreased, but
1113    that made it awkward if the user wanted to resize the window themself. */
1114 static void
1115 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1116 {
1117   GtkRcStyle *rc_style;
1118   gint new_height;
1119   GtkRequisition old_requisition;
1120   GtkWidget *preview_entry = fontsel->preview_entry;
1121   const gchar *text;
1122
1123   gtk_widget_get_child_requisition (preview_entry, &old_requisition);
1124   
1125   rc_style = gtk_rc_style_new ();
1126   rc_style->font_desc = gtk_font_selection_get_font_description (fontsel);
1127   
1128   gtk_widget_modify_style (preview_entry, rc_style);
1129   gtk_rc_style_unref (rc_style);
1130
1131   gtk_widget_size_request (preview_entry, NULL);
1132   
1133   /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1134   new_height = CLAMP (preview_entry->requisition.height, INITIAL_PREVIEW_HEIGHT, MAX_PREVIEW_HEIGHT);
1135
1136   if (new_height > old_requisition.height || new_height < old_requisition.height - 30)
1137     gtk_widget_set_size_request (preview_entry, -1, new_height);
1138   
1139   /* This sets the preview text, if it hasn't been set already. */
1140   text = gtk_entry_get_text (GTK_ENTRY (preview_entry));
1141   if (strlen (text) == 0)
1142     gtk_entry_set_text (GTK_ENTRY (preview_entry), _(PREVIEW_TEXT));
1143   gtk_editable_set_position (GTK_EDITABLE (preview_entry), 0);
1144 }
1145
1146 static GdkFont*
1147 gtk_font_selection_get_font_internal (GtkFontSelection *fontsel)
1148 {
1149   if (!fontsel->font)
1150     {
1151       PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1152       fontsel->font = gdk_font_from_description_for_display (gtk_widget_get_display (GTK_WIDGET (fontsel)), font_desc);
1153       pango_font_description_free (font_desc);
1154     }
1155   
1156   return fontsel->font;
1157 }
1158
1159
1160 /*****************************************************************************
1161  * These functions are the main public interface for getting/setting the font.
1162  *****************************************************************************/
1163
1164 GdkFont*
1165 gtk_font_selection_get_font (GtkFontSelection *fontsel)
1166 {
1167   return gtk_font_selection_get_font_internal (fontsel);
1168 }
1169
1170 /**
1171  * gtk_font_selection_get_font_name:
1172  * @fontsel: a #GtkFontSelection
1173  * 
1174  * Gets the currently-selected font name.  Note that this can be a different
1175  * string than what you set with gtk_font_selection_set_font_name(), as
1176  * the font selection widget may normalize font names and thus return a string
1177  * with a different structure.  For example, "Helvetica Italic Bold 12" could be
1178  * normalized to "Helvetica Bold Italic 12".  Use pango_font_description_equal()
1179  * if you want to compare two font descriptions.
1180  * 
1181  * Return value: A string with the name of the current font, or #NULL if no font
1182  * is selected.  You must free this string with g_free().
1183  **/
1184 gchar *
1185 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
1186 {
1187   gchar *result;
1188   
1189   PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1190   result = pango_font_description_to_string (font_desc);
1191   pango_font_description_free (font_desc);
1192
1193   return result;
1194 }
1195
1196
1197 /* This sets the current font, selecting the appropriate list rows.
1198    First we check the fontname is valid and try to find the font family
1199    - i.e. the name in the main list. If we can't find that, then just return.
1200    Next we try to set each of the properties according to the fontname.
1201    Finally we select the font family & style in the lists. */
1202
1203 /**
1204  * gtk_font_selection_set_font_name:
1205  * @fontsel: a #GtkFontSelection
1206  * @fontname: a font name like "Helvetica 12" or "Times Bold 18"
1207  * 
1208  * Sets the currently-selected font.  Note that the @fontsel needs to know the
1209  * screen in which it will appear for this to work; this can be guaranteed by
1210  * simply making sure that the @fontsel is inserted in a toplevel window before
1211  * you call this function.
1212  * 
1213  * Return value: #TRUE if the font could be set successfully; #FALSE if no such
1214  * font exists or if the @fontsel doesn't belong to a particular screen yet.
1215  **/
1216 gboolean
1217 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
1218                                   const gchar      *fontname)
1219 {
1220   PangoFontFamily *new_family = NULL;
1221   PangoFontFace *new_face = NULL;
1222   PangoFontFace *fallback_face = NULL;
1223   PangoFontDescription *new_desc;
1224   GtkTreeModel *model;
1225   GtkTreeIter iter;
1226   GtkTreeIter match_iter;
1227   gboolean valid;
1228   const gchar *new_family_name;
1229   
1230   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
1231   g_return_val_if_fail (gtk_widget_has_screen (GTK_WIDGET (fontsel)), FALSE);
1232   
1233   new_desc = pango_font_description_from_string (fontname);
1234   new_family_name = pango_font_description_get_family (new_desc);
1235
1236   if (!new_family_name)
1237     return FALSE;
1238
1239   /* Check to make sure that this is in the list of allowed fonts 
1240    */
1241   model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list));
1242   for (valid = gtk_tree_model_get_iter_first (model, &iter);
1243        valid;
1244        valid = gtk_tree_model_iter_next (model, &iter))
1245     {
1246       PangoFontFamily *family;
1247       
1248       gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
1249       
1250       if (g_ascii_strcasecmp (pango_font_family_get_name (family),
1251                               new_family_name) == 0)
1252         new_family = family;
1253       
1254       g_object_unref (family);
1255       
1256       if (new_family)
1257         break;
1258     }
1259
1260   if (!new_family)
1261     return FALSE;
1262
1263   fontsel->family = new_family;
1264   set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &iter);
1265   gtk_font_selection_show_available_styles (fontsel);
1266
1267   model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
1268   for (valid = gtk_tree_model_get_iter_first (model, &iter);
1269        valid;
1270        valid = gtk_tree_model_iter_next (model, &iter))
1271     {
1272       PangoFontFace *face;
1273       PangoFontDescription *tmp_desc;
1274       
1275       gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
1276       tmp_desc = pango_font_face_describe (face);
1277       
1278       if (font_description_style_equal (tmp_desc, new_desc))
1279         new_face = face;
1280       
1281       if (!fallback_face)
1282         {
1283           fallback_face = face;
1284           match_iter = iter;
1285         }
1286       
1287       pango_font_description_free (tmp_desc);
1288       g_object_unref (face);
1289       
1290       if (new_face)
1291         {
1292           match_iter = iter;
1293           break;
1294         }
1295     }
1296
1297   if (!new_face)
1298     new_face = fallback_face;
1299
1300   fontsel->face = new_face;
1301   set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_iter);  
1302
1303   gtk_font_selection_set_size (fontsel, pango_font_description_get_size (new_desc));
1304   
1305   g_object_freeze_notify (G_OBJECT (fontsel));
1306   g_object_notify (G_OBJECT (fontsel), "font_name");
1307   g_object_notify (G_OBJECT (fontsel), "font");
1308   g_object_thaw_notify (G_OBJECT (fontsel));
1309
1310   pango_font_description_free (new_desc);
1311
1312   return TRUE;
1313 }
1314
1315
1316 /* This returns the text in the preview entry. You should copy the returned
1317    text if you need it. */
1318 G_CONST_RETURN gchar*
1319 gtk_font_selection_get_preview_text  (GtkFontSelection *fontsel)
1320 {
1321   return gtk_entry_get_text (GTK_ENTRY (fontsel->preview_entry));
1322 }
1323
1324
1325 /* This sets the text in the preview entry. */
1326 void
1327 gtk_font_selection_set_preview_text  (GtkFontSelection *fontsel,
1328                                       const gchar         *text)
1329 {
1330   gtk_entry_set_text (GTK_ENTRY (fontsel->preview_entry), text);
1331 }
1332
1333 /*****************************************************************************
1334  * GtkFontSelectionDialog
1335  *****************************************************************************/
1336
1337 GType
1338 gtk_font_selection_dialog_get_type (void)
1339 {
1340   static GType font_selection_dialog_type = 0;
1341   
1342   if (!font_selection_dialog_type)
1343     {
1344       static const GTypeInfo fontsel_diag_info =
1345       {
1346         sizeof (GtkFontSelectionDialogClass),
1347         NULL,           /* base_init */
1348         NULL,           /* base_finalize */
1349         (GClassInitFunc) gtk_font_selection_dialog_class_init,
1350         NULL,           /* class_finalize */
1351         NULL,           /* class_data */
1352         sizeof (GtkFontSelectionDialog),
1353         0,              /* n_preallocs */
1354         (GInstanceInitFunc) gtk_font_selection_dialog_init,
1355       };
1356       
1357       font_selection_dialog_type =
1358         g_type_register_static (GTK_TYPE_DIALOG, I_("GtkFontSelectionDialog"),
1359                                 &fontsel_diag_info, 0);
1360     }
1361   
1362   return font_selection_dialog_type;
1363 }
1364
1365 static void
1366 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
1367 {
1368   font_selection_dialog_parent_class = g_type_class_peek_parent (klass);
1369 }
1370
1371 static void
1372 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
1373 {
1374   GtkDialog *dialog;
1375
1376   gtk_widget_push_composite_child ();
1377
1378   dialog = GTK_DIALOG (fontseldiag);
1379   
1380   gtk_container_set_border_width (GTK_CONTAINER (fontseldiag), 4);
1381   gtk_window_set_resizable (GTK_WINDOW (fontseldiag), TRUE);
1382   
1383   fontseldiag->main_vbox = dialog->vbox;
1384   
1385   fontseldiag->fontsel = gtk_font_selection_new ();
1386   gtk_container_set_border_width (GTK_CONTAINER (fontseldiag->fontsel), 4);
1387   gtk_widget_show (fontseldiag->fontsel);
1388   gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
1389                       fontseldiag->fontsel, TRUE, TRUE, 0);
1390   
1391   /* Create the action area */
1392   fontseldiag->action_area = dialog->action_area;
1393
1394   fontseldiag->cancel_button = gtk_dialog_add_button (dialog,
1395                                                       GTK_STOCK_CANCEL,
1396                                                       GTK_RESPONSE_CANCEL);
1397
1398   fontseldiag->apply_button = gtk_dialog_add_button (dialog,
1399                                                      GTK_STOCK_APPLY,
1400                                                      GTK_RESPONSE_APPLY);
1401   gtk_widget_hide (fontseldiag->apply_button);
1402
1403   fontseldiag->ok_button = gtk_dialog_add_button (dialog,
1404                                                   GTK_STOCK_OK,
1405                                                   GTK_RESPONSE_OK);
1406   gtk_widget_grab_default (fontseldiag->ok_button);
1407   
1408   gtk_dialog_set_alternative_button_order (GTK_DIALOG (fontseldiag),
1409                                            GTK_RESPONSE_OK,
1410                                            GTK_RESPONSE_APPLY,
1411                                            GTK_RESPONSE_CANCEL,
1412                                            -1);
1413
1414
1415   gtk_window_set_title (GTK_WINDOW (fontseldiag),
1416                         _("Font Selection"));
1417
1418   gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
1419   
1420   gtk_widget_pop_composite_child ();
1421 }
1422
1423 GtkWidget*
1424 gtk_font_selection_dialog_new (const gchar *title)
1425 {
1426   GtkFontSelectionDialog *fontseldiag;
1427   
1428   fontseldiag = g_object_new (GTK_TYPE_FONT_SELECTION_DIALOG, NULL);
1429
1430   if (title)
1431     gtk_window_set_title (GTK_WINDOW (fontseldiag), title);
1432   
1433   return GTK_WIDGET (fontseldiag);
1434 }
1435
1436 /**
1437  * gtk_font_selection_dialog_get_font_name:
1438  * @fsd: a #GtkFontSelectionDialog
1439  * 
1440  * Gets the currently-selected font name.  Note that this can be a different
1441  * string than what you set with gtk_font_selection_dialog_set_font_name(), as
1442  * the font selection widget may normalize font names and thus return a string
1443  * with a different structure.  For example, "Helvetica Italic Bold 12" could be
1444  * normalized to "Helvetica Bold Italic 12".  Use pango_font_description_equal()
1445  * if you want to compare two font descriptions.
1446  * 
1447  * Return value: A string with the name of the current font, or #NULL if no font
1448  * is selected.  You must free this string with g_free().
1449  **/
1450 gchar*
1451 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
1452 {
1453   return gtk_font_selection_get_font_name (GTK_FONT_SELECTION (fsd->fontsel));
1454 }
1455
1456 GdkFont*
1457 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
1458 {
1459   return gtk_font_selection_get_font (GTK_FONT_SELECTION (fsd->fontsel));
1460 }
1461
1462 gboolean
1463 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
1464                                          const gchar      *fontname)
1465 {
1466   return gtk_font_selection_set_font_name (GTK_FONT_SELECTION (fsd->fontsel), fontname);
1467 }
1468
1469 G_CONST_RETURN gchar*
1470 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
1471 {
1472   return gtk_font_selection_get_preview_text (GTK_FONT_SELECTION (fsd->fontsel));
1473 }
1474
1475 void
1476 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
1477                                             const gchar            *text)
1478 {
1479   gtk_font_selection_set_preview_text (GTK_FONT_SELECTION (fsd->fontsel), text);
1480 }
1481
1482 #define __GTK_FONTSEL_C__
1483 #include "gtkaliasdef.c"