]> Pileus Git - ~andy/gtk/blob - gtk/gtkfontsel.c
Fix many sparse warnings.
[~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 "gtkalias.h"
43 #include "gtkfontsel.h"
44
45 #include "gtkbutton.h"
46 #include "gtkcellrenderertext.h"
47 #include "gtkentry.h"
48 #include "gtkframe.h"
49 #include "gtkhbbox.h"
50 #include "gtkhbox.h"
51 #include "gtklabel.h"
52 #include "gtkliststore.h"
53 #include "gtkrc.h"
54 #include "gtkstock.h"
55 #include "gtktable.h"
56 #include "gtktreeselection.h"
57 #include "gtktreeview.h"
58 #include "gtkvbox.h"
59 #include "gtkscrolledwindow.h"
60 #include "gtkintl.h"
61 #include "gtkaccessible.h"
62
63 /* We don't enable the font and style entries because they don't add
64  * much in terms of visible effect and have a weird effect on keynav.
65  * the Windows font selector has entries similarly positioned but they
66  * act in conjunction with the associated lists to form a single focus
67  * location.
68  */
69 #undef INCLUDE_FONT_ENTRIES
70
71 /* This is the default text shown in the preview entry, though the user
72    can set it. Remember that some fonts only have capital letters. */
73 #define PREVIEW_TEXT N_("abcdefghijk ABCDEFGHIJK")
74
75 /* This is the initial and maximum height of the preview entry (it expands
76    when large font sizes are selected). Initial height is also the minimum. */
77 #define INITIAL_PREVIEW_HEIGHT 44
78 #define MAX_PREVIEW_HEIGHT 300
79
80 /* These are the sizes of the font, style & size lists. */
81 #define FONT_LIST_HEIGHT        136
82 #define FONT_LIST_WIDTH         190
83 #define FONT_STYLE_LIST_WIDTH   170
84 #define FONT_SIZE_LIST_WIDTH    60
85
86 /* These are what we use as the standard font sizes, for the size list.
87  */
88 static const guint16 font_sizes[] = {
89   8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28,
90   32, 36, 40, 48, 56, 64, 72
91 };
92
93 enum {
94    PROP_0,
95    PROP_FONT_NAME,
96    PROP_FONT,
97    PROP_PREVIEW_TEXT
98 };
99
100
101 enum {
102   FAMILY_COLUMN,
103   FAMILY_NAME_COLUMN
104 };
105
106 enum {
107   FACE_COLUMN,
108   FACE_NAME_COLUMN
109 };
110
111 enum {
112   SIZE_COLUMN
113 };
114
115 static void    gtk_font_selection_class_init         (GtkFontSelectionClass *klass);
116 static void    gtk_font_selection_set_property       (GObject         *object,
117                                                       guint            prop_id,
118                                                       const GValue    *value,
119                                                       GParamSpec      *pspec);
120 static void    gtk_font_selection_get_property       (GObject         *object,
121                                                       guint            prop_id,
122                                                       GValue          *value,
123                                                       GParamSpec      *pspec);
124 static void    gtk_font_selection_init               (GtkFontSelection      *fontsel);
125 static void    gtk_font_selection_finalize           (GObject               *object);
126 static void    gtk_font_selection_screen_changed     (GtkWidget             *widget,
127                                                       GdkScreen             *previous_screen);
128
129 /* These are the callbacks & related functions. */
130 static void     gtk_font_selection_select_font           (GtkTreeSelection *selection,
131                                                           gpointer          data);
132 static void     gtk_font_selection_show_available_fonts  (GtkFontSelection *fs);
133
134 static void     gtk_font_selection_show_available_styles (GtkFontSelection *fs);
135 static void     gtk_font_selection_select_best_style     (GtkFontSelection *fs,
136                                                           gboolean          use_first);
137 static void     gtk_font_selection_select_style          (GtkTreeSelection *selection,
138                                                           gpointer          data);
139
140 static void     gtk_font_selection_select_best_size      (GtkFontSelection *fs);
141 static void     gtk_font_selection_show_available_sizes  (GtkFontSelection *fs,
142                                                           gboolean          first_time);
143 static void     gtk_font_selection_size_activate         (GtkWidget        *w,
144                                                           gpointer          data);
145 static gboolean gtk_font_selection_size_focus_out        (GtkWidget        *w,
146                                                           GdkEventFocus    *event,
147                                                           gpointer          data);
148 static void     gtk_font_selection_select_size           (GtkTreeSelection *selection,
149                                                           gpointer          data);
150
151 static void     gtk_font_selection_scroll_on_map         (GtkWidget        *w,
152                                                           gpointer          data);
153
154 static void     gtk_font_selection_preview_changed       (GtkWidget        *entry,
155                                                           GtkFontSelection *fontsel);
156
157 /* Misc. utility functions. */
158 static void    gtk_font_selection_load_font          (GtkFontSelection *fs);
159 static void    gtk_font_selection_update_preview     (GtkFontSelection *fs);
160
161 static GdkFont* gtk_font_selection_get_font_internal (GtkFontSelection *fontsel);
162
163 /* FontSelectionDialog */
164 static void    gtk_font_selection_dialog_class_init  (GtkFontSelectionDialogClass *klass);
165 static void    gtk_font_selection_dialog_init        (GtkFontSelectionDialog *fontseldiag);
166
167 static GtkVBoxClass *font_selection_parent_class = NULL;
168 static GtkWindowClass *font_selection_dialog_parent_class = NULL;
169
170
171 GType
172 gtk_font_selection_get_type (void)
173 {
174   static GType font_selection_type = 0;
175   
176   if (!font_selection_type)
177     {
178       static const GTypeInfo fontsel_type_info =
179       {
180         sizeof (GtkFontSelectionClass),
181         NULL,           /* base_init */
182         NULL,           /* base_finalize */
183         (GClassInitFunc) gtk_font_selection_class_init,
184         NULL,           /* class_finalize */
185         NULL,           /* class_data */
186         sizeof (GtkFontSelection),
187         0,              /* n_preallocs */
188         (GInstanceInitFunc) gtk_font_selection_init,
189       };
190       
191       font_selection_type =
192         g_type_register_static (GTK_TYPE_VBOX, "GtkFontSelection",
193                                 &fontsel_type_info, 0);
194     }
195   
196   return font_selection_type;
197 }
198
199 static void
200 gtk_font_selection_class_init (GtkFontSelectionClass *klass)
201 {
202   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
203   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
204   
205   font_selection_parent_class = g_type_class_peek_parent (klass);
206   
207   gobject_class->set_property = gtk_font_selection_set_property;
208   gobject_class->get_property = gtk_font_selection_get_property;
209
210   widget_class->screen_changed = gtk_font_selection_screen_changed;
211    
212   g_object_class_install_property (gobject_class,
213                                    PROP_FONT_NAME,
214                                    g_param_spec_string ("font_name",
215                                                         P_("Font name"),
216                                                         P_("The X string that represents this font"),
217                                                         NULL,
218                                                         G_PARAM_READWRITE));
219   g_object_class_install_property (gobject_class,
220                                    PROP_FONT,
221                                    g_param_spec_boxed ("font",
222                                                        P_("Font"),
223                                                        P_("The GdkFont that is currently selected"),
224                                                        GDK_TYPE_FONT,
225                                                        G_PARAM_READABLE));
226   g_object_class_install_property (gobject_class,
227                                    PROP_PREVIEW_TEXT,
228                                    g_param_spec_string ("preview_text",
229                                                         P_("Preview text"),
230                                                         P_("The text to display in order to demonstrate the selected font"),
231                                                         PREVIEW_TEXT,
232                                                         G_PARAM_READWRITE));
233   gobject_class->finalize = gtk_font_selection_finalize;
234 }
235
236 static void 
237 gtk_font_selection_set_property (GObject         *object,
238                                  guint            prop_id,
239                                  const GValue    *value,
240                                  GParamSpec      *pspec)
241 {
242   GtkFontSelection *fontsel;
243
244   fontsel = GTK_FONT_SELECTION (object);
245
246   switch (prop_id)
247     {
248     case PROP_FONT_NAME:
249       gtk_font_selection_set_font_name (fontsel, g_value_get_string (value));
250       break;
251     case PROP_PREVIEW_TEXT:
252       gtk_font_selection_set_preview_text (fontsel, g_value_get_string (value));
253       break;
254     default:
255       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
256       break;
257     }
258 }
259
260 static void gtk_font_selection_get_property (GObject         *object,
261                                              guint            prop_id,
262                                              GValue          *value,
263                                              GParamSpec      *pspec)
264 {
265   GtkFontSelection *fontsel;
266
267   fontsel = GTK_FONT_SELECTION (object);
268
269   switch (prop_id)
270     {
271     case PROP_FONT_NAME:
272       g_value_set_string (value, gtk_font_selection_get_font_name (fontsel));
273       break;
274     case PROP_FONT:
275       g_value_set_object (value, gtk_font_selection_get_font_internal (fontsel));
276       break;
277     case PROP_PREVIEW_TEXT:
278       g_value_set_string (value, gtk_font_selection_get_preview_text (fontsel));
279       break;
280     default:
281       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
282       break;
283     }
284 }
285
286 /* Handles key press events on the lists, so that we can trap Enter to
287  * activate the default button on our own.
288  */
289 static gboolean
290 list_row_activated (GtkWidget *widget)
291 {
292   GtkWindow *window;
293   
294   window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget)));
295   if (!GTK_WIDGET_TOPLEVEL (window))
296     window = NULL;
297   
298   if (window
299       && widget != window->default_widget
300       && !(widget == window->focus_widget &&
301            (!window->default_widget || !GTK_WIDGET_SENSITIVE (window->default_widget))))
302     {
303       gtk_window_activate_default (window);
304     }
305   
306   return TRUE;
307 }
308
309 static void
310 gtk_font_selection_init (GtkFontSelection *fontsel)
311 {
312   GtkWidget *scrolled_win;
313   GtkWidget *text_frame;
314   GtkWidget *text_box;
315   GtkWidget *table, *label;
316   GtkWidget *font_label, *style_label;
317   GtkListStore *model;
318   GtkTreeViewColumn *column;
319   GList *focus_chain = NULL;
320   AtkObject *atk_obj;
321
322   gtk_widget_push_composite_child ();
323
324   fontsel->size = 12 * PANGO_SCALE;
325   
326   /* Create the table of font, style & size. */
327   table = gtk_table_new (3, 3, FALSE);
328   gtk_widget_show (table);
329   gtk_table_set_col_spacings (GTK_TABLE (table), 8);
330   gtk_box_pack_start (GTK_BOX (fontsel), table, TRUE, TRUE, 0);
331
332 #ifdef INCLUDE_FONT_ENTRIES
333   fontsel->font_entry = gtk_entry_new ();
334   gtk_editable_set_editable (GTK_EDITABLE (fontsel->font_entry), FALSE);
335   gtk_widget_set_size_request (fontsel->font_entry, 20, -1);
336   gtk_widget_show (fontsel->font_entry);
337   gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
338                     GTK_FILL, 0, 0, 0);
339   
340   fontsel->font_style_entry = gtk_entry_new ();
341   gtk_editable_set_editable (GTK_EDITABLE (fontsel->font_style_entry), FALSE);
342   gtk_widget_set_size_request (fontsel->font_style_entry, 20, -1);
343   gtk_widget_show (fontsel->font_style_entry);
344   gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
345                     GTK_FILL, 0, 0, 0);
346 #endif /* INCLUDE_FONT_ENTRIES */
347   
348   fontsel->size_entry = gtk_entry_new ();
349   gtk_widget_set_size_request (fontsel->size_entry, 20, -1);
350   gtk_widget_show (fontsel->size_entry);
351   gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
352                     GTK_FILL, 0, 0, 0);
353   g_signal_connect (fontsel->size_entry, "activate",
354                     G_CALLBACK (gtk_font_selection_size_activate),
355                     fontsel);
356   g_signal_connect_after (fontsel->size_entry, "focus_out_event",
357                           G_CALLBACK (gtk_font_selection_size_focus_out),
358                           fontsel);
359   
360   font_label = gtk_label_new_with_mnemonic (_("_Family:"));
361   gtk_misc_set_alignment (GTK_MISC (font_label), 0.0, 0.5);
362   gtk_widget_show (font_label);
363   gtk_table_attach (GTK_TABLE (table), font_label, 0, 1, 0, 1,
364                     GTK_FILL, 0, 0, 0);  
365
366   style_label = gtk_label_new_with_mnemonic (_("_Style:"));
367   gtk_misc_set_alignment (GTK_MISC (style_label), 0.0, 0.5);
368   gtk_widget_show (style_label);
369   gtk_table_attach (GTK_TABLE (table), style_label, 1, 2, 0, 1,
370                     GTK_FILL, 0, 0, 0);
371   
372   label = gtk_label_new_with_mnemonic (_("Si_ze:"));
373   gtk_label_set_mnemonic_widget (GTK_LABEL (label),
374                                  fontsel->size_entry);
375   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
376   gtk_widget_show (label);
377   gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
378                     GTK_FILL, 0, 0, 0);
379   
380   
381   /* Create the lists  */
382
383   model = gtk_list_store_new (2,
384                               G_TYPE_OBJECT,  /* FAMILY_COLUMN */
385                               G_TYPE_STRING); /* FAMILY_NAME_COLUMN */
386   fontsel->family_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
387   g_object_unref (model);
388
389   g_signal_connect (fontsel->family_list, "row-activated",
390                     G_CALLBACK (list_row_activated), fontsel);
391
392   column = gtk_tree_view_column_new_with_attributes ("Family",
393                                                      gtk_cell_renderer_text_new (),
394                                                      "text", FAMILY_NAME_COLUMN,
395                                                      NULL);
396   gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
397   gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->family_list), column);
398
399   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->family_list), FALSE);
400   gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)),
401                                GTK_SELECTION_BROWSE);
402   
403   gtk_label_set_mnemonic_widget (GTK_LABEL (font_label), fontsel->family_list);
404
405   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
406   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
407   gtk_widget_set_size_request (scrolled_win,
408                                FONT_LIST_WIDTH, FONT_LIST_HEIGHT);
409   gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->family_list);
410   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
411                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
412   gtk_widget_show (fontsel->family_list);
413   gtk_widget_show (scrolled_win);
414
415   gtk_table_attach (GTK_TABLE (table), scrolled_win, 0, 1, 1, 3,
416                     GTK_EXPAND | GTK_FILL,
417                     GTK_EXPAND | GTK_FILL, 0, 0);
418   focus_chain = g_list_append (focus_chain, scrolled_win);
419   
420   model = gtk_list_store_new (2,
421                               G_TYPE_OBJECT,  /* FACE_COLUMN */
422                               G_TYPE_STRING); /* FACE_NAME_COLUMN */
423   fontsel->face_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
424   g_object_unref (model);
425   g_signal_connect (fontsel->face_list, "row-activated",
426                     G_CALLBACK (list_row_activated), fontsel);
427
428   gtk_label_set_mnemonic_widget (GTK_LABEL (style_label), fontsel->face_list);
429
430   column = gtk_tree_view_column_new_with_attributes ("Face",
431                                                      gtk_cell_renderer_text_new (),
432                                                      "text", FACE_NAME_COLUMN,
433                                                      NULL);
434   gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
435   gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->face_list), column);
436
437   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->face_list), FALSE);
438   gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)),
439                                GTK_SELECTION_BROWSE);
440   
441   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
442   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
443   gtk_widget_set_size_request (scrolled_win,
444                                FONT_STYLE_LIST_WIDTH, FONT_LIST_HEIGHT);
445   gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->face_list);
446   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
447                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
448   gtk_widget_show (fontsel->face_list);
449   gtk_widget_show (scrolled_win);
450   gtk_table_attach (GTK_TABLE (table), scrolled_win, 1, 2, 1, 3,
451                     GTK_EXPAND | GTK_FILL,
452                     GTK_EXPAND | GTK_FILL, 0, 0);
453   focus_chain = g_list_append (focus_chain, scrolled_win);
454   
455   focus_chain = g_list_append (focus_chain, fontsel->size_entry);
456
457   model = gtk_list_store_new (1, G_TYPE_INT);
458   fontsel->size_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
459   g_object_unref (model);
460   g_signal_connect (fontsel->size_list, "row-activated",
461                     G_CALLBACK (list_row_activated), fontsel);
462
463   column = gtk_tree_view_column_new_with_attributes ("Size",
464                                                      gtk_cell_renderer_text_new (),
465                                                      "text", SIZE_COLUMN,
466                                                      NULL);
467   gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
468   gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->size_list), column);
469
470   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->size_list), FALSE);
471   gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)),
472                                GTK_SELECTION_BROWSE);
473   
474   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
475   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
476   gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->size_list);
477   gtk_widget_set_size_request (scrolled_win, -1, FONT_LIST_HEIGHT);
478   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
479                                   GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
480   gtk_widget_show (fontsel->size_list);
481   gtk_widget_show (scrolled_win);
482   gtk_table_attach (GTK_TABLE (table), scrolled_win, 2, 3, 2, 3,
483                     GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
484   focus_chain = g_list_append (focus_chain, scrolled_win);
485
486   gtk_container_set_focus_chain (GTK_CONTAINER (table), focus_chain);
487   g_list_free (focus_chain);
488   
489   /* Insert the fonts. */
490   g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)), "changed",
491                     G_CALLBACK (gtk_font_selection_select_font), fontsel);
492
493   g_signal_connect_after (fontsel->family_list, "map",
494                           G_CALLBACK (gtk_font_selection_scroll_on_map),
495                           fontsel);
496   
497   g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)), "changed",
498                     G_CALLBACK (gtk_font_selection_select_style), fontsel);
499
500   g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)), "changed",
501                     G_CALLBACK (gtk_font_selection_select_size), fontsel);
502   atk_obj = gtk_widget_get_accessible (fontsel->size_list);
503   if (GTK_IS_ACCESSIBLE (atk_obj))
504     {
505       /* Accessibility support is enabled.
506        * Make the label ATK_RELATON_LABEL_FOR for the size list as well.
507        */
508       AtkObject *atk_label;
509       AtkRelationSet *relation_set;
510       AtkRelation *relation;
511       AtkObject *obj_array[1];
512       GPtrArray *array;
513
514       atk_label = gtk_widget_get_accessible (label);
515       relation_set = atk_object_ref_relation_set (atk_obj);
516       relation = atk_relation_set_get_relation_by_type (relation_set, ATK_RELATION_LABELLED_BY);
517       if (relation)
518         {
519           array = atk_relation_get_target (relation);
520           g_ptr_array_add (array, atk_label);
521         }
522       else 
523         {
524           obj_array[0] = atk_label;
525           relation = atk_relation_new (obj_array, 1, ATK_RELATION_LABELLED_BY);
526           atk_relation_set_add (relation_set, relation);
527         }
528       g_object_unref (relation_set);
529
530       relation_set = atk_object_ref_relation_set (atk_label);
531       relation = atk_relation_set_get_relation_by_type (relation_set, ATK_RELATION_LABEL_FOR);
532       if (relation)
533         {
534           array = atk_relation_get_target (relation);
535           g_ptr_array_add (array, atk_obj);
536         }
537       else 
538         {
539           obj_array[0] = atk_obj;
540           relation = atk_relation_new (obj_array, 1, ATK_RELATION_LABEL_FOR);
541           atk_relation_set_add (relation_set, relation);
542         }
543       g_object_unref (relation_set);
544     }    
545       
546
547   /* create the text entry widget */
548   label = gtk_label_new_with_mnemonic (_("_Preview:"));
549   gtk_widget_show (label);
550   
551   text_frame = gtk_frame_new (NULL);
552   gtk_frame_set_label_widget (GTK_FRAME (text_frame), label);
553   
554   gtk_widget_show (text_frame);
555   gtk_frame_set_shadow_type (GTK_FRAME (text_frame), GTK_SHADOW_ETCHED_IN);
556   gtk_box_pack_start (GTK_BOX (fontsel), text_frame,
557                       FALSE, TRUE, 0);
558   
559   /* This is just used to get a 4-pixel space around the preview entry. */
560   text_box = gtk_hbox_new (FALSE, 0);
561   gtk_widget_show (text_box);
562   gtk_container_add (GTK_CONTAINER (text_frame), text_box);
563   gtk_container_set_border_width (GTK_CONTAINER (text_box), 4);
564   
565   fontsel->preview_entry = gtk_entry_new ();
566   gtk_label_set_mnemonic_widget (GTK_LABEL (label), fontsel->preview_entry);
567   
568   gtk_widget_show (fontsel->preview_entry);
569   g_signal_connect (fontsel->preview_entry, "changed",
570                     G_CALLBACK (gtk_font_selection_preview_changed), fontsel);
571   gtk_widget_set_size_request (fontsel->preview_entry,
572                                -1, INITIAL_PREVIEW_HEIGHT);
573   gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
574                       TRUE, TRUE, 0);
575
576   gtk_widget_pop_composite_child();
577 }
578
579 GtkWidget *
580 gtk_font_selection_new (void)
581 {
582   GtkFontSelection *fontsel;
583   
584   fontsel = g_object_new (GTK_TYPE_FONT_SELECTION, NULL);
585   
586   return GTK_WIDGET (fontsel);
587 }
588
589 static void
590 gtk_font_selection_finalize (GObject *object)
591 {
592   GtkFontSelection *fontsel;
593   
594   g_return_if_fail (GTK_IS_FONT_SELECTION (object));
595   
596   fontsel = GTK_FONT_SELECTION (object);
597
598   if (fontsel->font)
599     gdk_font_unref (fontsel->font);
600   
601   (* G_OBJECT_CLASS (font_selection_parent_class)->finalize) (object);
602 }
603
604 static void
605 gtk_font_selection_screen_changed (GtkWidget *widget,
606                                    GdkScreen *previous_screen)
607 {
608   GtkFontSelection *fontsel = GTK_FONT_SELECTION (widget);
609
610   if (gtk_widget_has_screen (GTK_WIDGET (fontsel)))
611     {
612       gtk_font_selection_show_available_fonts (fontsel);
613       gtk_font_selection_show_available_sizes (fontsel, TRUE);
614       gtk_font_selection_show_available_styles (fontsel);
615     }
616 }
617
618 static void
619 gtk_font_selection_preview_changed (GtkWidget        *entry,
620                                     GtkFontSelection *fontsel)
621 {
622   g_object_notify (G_OBJECT (fontsel), "preview_text");
623 }
624
625 static void
626 scroll_to_selection (GtkTreeView *tree_view)
627 {
628   GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
629   GtkTreeModel *model;
630   GtkTreeIter iter;
631
632   if (gtk_tree_selection_get_selected (selection, &model, &iter))
633     {
634       GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
635       gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.5);
636       gtk_tree_path_free (path);
637     }
638 }
639
640 static void
641 set_cursor_to_iter (GtkTreeView *view,
642                     GtkTreeIter *iter)
643 {
644   GtkTreeModel *model = gtk_tree_view_get_model (view);
645   GtkTreePath *path = gtk_tree_model_get_path (model, iter);
646   
647   gtk_tree_view_set_cursor (view, path, NULL, FALSE);
648
649   gtk_tree_path_free (path);
650 }
651
652 /* This is called when the list is mapped. Here we scroll to the current
653    font if necessary. */
654 static void
655 gtk_font_selection_scroll_on_map (GtkWidget             *widget,
656                                   gpointer               data)
657 {
658   GtkFontSelection *fontsel;
659   
660 #ifdef FONTSEL_DEBUG
661   g_message ("In expose_list\n");
662 #endif
663   fontsel = GTK_FONT_SELECTION (data);
664   
665   /* Try to scroll the font family list to the selected item */
666   scroll_to_selection (GTK_TREE_VIEW (fontsel->family_list));
667       
668   /* Try to scroll the font family list to the selected item */
669   scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
670       
671   /* Try to scroll the font family list to the selected item */
672   scroll_to_selection (GTK_TREE_VIEW (fontsel->size_list));
673 }
674
675 /* This is called when a family is selected in the list. */
676 static void
677 gtk_font_selection_select_font (GtkTreeSelection *selection,
678                                 gpointer          data)
679 {
680   GtkFontSelection *fontsel;
681   GtkTreeModel *model;
682   GtkTreeIter iter;
683   const gchar *family_name;
684   
685   fontsel = GTK_FONT_SELECTION (data);
686
687   if (gtk_tree_selection_get_selected (selection, &model, &iter))
688     {
689       PangoFontFamily *family;
690       
691       gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
692       if (fontsel->family != family)
693         {
694           fontsel->family = family;
695           
696           family_name = pango_font_family_get_name (fontsel->family);
697           
698 #ifdef INCLUDE_FONT_ENTRIES
699           gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), family_name);
700 #endif
701           
702           gtk_font_selection_show_available_styles (fontsel);
703           gtk_font_selection_select_best_style (fontsel, TRUE);
704         }
705
706       g_object_unref (family);
707     }
708 }
709
710 static int
711 cmp_families (const void *a, const void *b)
712 {
713   const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a);
714   const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b);
715   
716   return g_utf8_collate (a_name, b_name);
717 }
718
719 static void
720 gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
721 {
722   GtkListStore *model;
723   PangoFontFamily **families;
724   PangoFontFamily *match_family = NULL;
725   gint n_families, i;
726   GtkTreeIter match_row;
727   
728   model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list)));
729   
730   pango_context_list_families (gtk_widget_get_pango_context (GTK_WIDGET (fontsel)),
731                                &families, &n_families);
732   qsort (families, n_families, sizeof (PangoFontFamily *), cmp_families);
733
734   gtk_list_store_clear (model);
735
736   for (i=0; i<n_families; i++)
737     {
738       const gchar *name = pango_font_family_get_name (families[i]);
739       GtkTreeIter iter;
740
741       gtk_list_store_append (model, &iter);
742       gtk_list_store_set (model, &iter,
743                           FAMILY_COLUMN, families[i],
744                           FAMILY_NAME_COLUMN, name,
745                           -1);
746       
747       if (i == 0 || !g_ascii_strcasecmp (name, "sans"))
748         {
749           match_family = families[i];
750           match_row = iter;
751         }
752     }
753
754   fontsel->family = match_family;
755   if (match_family)
756     {
757       set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &match_row);
758 #ifdef INCLUDE_FONT_ENTRIES
759       gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), 
760                           pango_font_family_get_name (match_family));
761 #endif /* INCLUDE_FONT_ENTRIES */
762     }
763
764   g_free (families);
765 }
766
767 static int
768 compare_font_descriptions (const PangoFontDescription *a, const PangoFontDescription *b)
769 {
770   int val = strcmp (pango_font_description_get_family (a), pango_font_description_get_family (b));
771   if (val != 0)
772     return val;
773
774   if (pango_font_description_get_weight (a) != pango_font_description_get_weight (b))
775     return pango_font_description_get_weight (a) - pango_font_description_get_weight (b);
776
777   if (pango_font_description_get_style (a) != pango_font_description_get_style (b))
778     return pango_font_description_get_style (a) - pango_font_description_get_style (b);
779   
780   if (pango_font_description_get_stretch (a) != pango_font_description_get_stretch (b))
781     return pango_font_description_get_stretch (a) - pango_font_description_get_stretch (b);
782
783   if (pango_font_description_get_variant (a) != pango_font_description_get_variant (b))
784     return pango_font_description_get_variant (a) - pango_font_description_get_variant (b);
785
786   return 0;
787 }
788
789 static int
790 faces_sort_func (const void *a, const void *b)
791 {
792   PangoFontDescription *desc_a = pango_font_face_describe (*(PangoFontFace **)a);
793   PangoFontDescription *desc_b = pango_font_face_describe (*(PangoFontFace **)b);
794   
795   int ord = compare_font_descriptions (desc_a, desc_b);
796
797   pango_font_description_free (desc_a);
798   pango_font_description_free (desc_b);
799
800   return ord;
801 }
802
803 static gboolean
804 font_description_style_equal (const PangoFontDescription *a,
805                               const PangoFontDescription *b)
806 {
807   return (pango_font_description_get_weight (a) == pango_font_description_get_weight (b) &&
808           pango_font_description_get_style (a) == pango_font_description_get_style (b) &&
809           pango_font_description_get_stretch (a) == pango_font_description_get_stretch (b) &&
810           pango_font_description_get_variant (a) == pango_font_description_get_variant (b));
811 }
812
813 /* This fills the font style list with all the possible style combinations
814    for the current font family. */
815 static void
816 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
817 {
818   gint n_faces, i;
819   PangoFontFace **faces;
820   PangoFontDescription *old_desc;
821   GtkListStore *model;
822   GtkTreeIter match_row;
823   PangoFontFace *match_face = NULL;
824   
825   model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list)));
826   
827   if (fontsel->face)
828     old_desc = pango_font_face_describe (fontsel->face);
829   else
830     old_desc= NULL;
831
832   pango_font_family_list_faces (fontsel->family, &faces, &n_faces);
833   qsort (faces, n_faces, sizeof (PangoFontFace *), faces_sort_func);
834
835   gtk_list_store_clear (model);
836
837   for (i=0; i < n_faces; i++)
838     {
839       GtkTreeIter iter;
840       const gchar *str = pango_font_face_get_face_name (faces[i]);
841
842       gtk_list_store_append (model, &iter);
843       gtk_list_store_set (model, &iter,
844                           FACE_COLUMN, faces[i],
845                           FACE_NAME_COLUMN, str,
846                           -1);
847
848       if (i == 0)
849         {
850           match_row = iter;
851           match_face = faces[i];
852         }
853       else if (old_desc)
854         {
855           PangoFontDescription *tmp_desc = pango_font_face_describe (faces[i]);
856           
857           if (font_description_style_equal (tmp_desc, old_desc))
858             {
859               match_row = iter;
860               match_face = faces[i];
861             }
862       
863           pango_font_description_free (tmp_desc);
864         }
865     }
866
867   if (old_desc)
868     pango_font_description_free (old_desc);
869
870   fontsel->face = match_face;
871   if (match_face)
872     {
873 #ifdef INCLUDE_FONT_ENTRIES
874       const gchar *str = pango_font_face_get_face_name (fontsel->face);
875
876       gtk_entry_set_text (GTK_ENTRY (fontsel->font_style_entry), str);
877 #endif      
878       set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_row);
879     }
880
881   g_free (faces);
882 }
883
884 /* This selects a style when the user selects a font. It just uses the first
885    available style at present. I was thinking of trying to maintain the
886    selected style, e.g. bold italic, when the user selects different fonts.
887    However, the interface is so easy to use now I'm not sure it's worth it.
888    Note: This will load a font. */
889 static void
890 gtk_font_selection_select_best_style (GtkFontSelection *fontsel,
891                                       gboolean          use_first)
892 {
893   GtkTreeIter iter;
894   GtkTreeModel *model;
895
896   model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
897
898   if (gtk_tree_model_get_iter_first (model, &iter))
899     {
900       set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &iter);
901       scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
902     }
903
904   gtk_font_selection_show_available_sizes (fontsel, FALSE);
905   gtk_font_selection_select_best_size (fontsel);
906 }
907
908
909 /* This is called when a style is selected in the list. */
910 static void
911 gtk_font_selection_select_style (GtkTreeSelection *selection,
912                                  gpointer          data)
913 {
914   GtkFontSelection *fontsel = GTK_FONT_SELECTION (data);
915   GtkTreeModel *model;
916   GtkTreeIter iter;
917   
918   if (gtk_tree_selection_get_selected (selection, &model, &iter))
919     {
920       PangoFontFace *face;
921       
922       gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
923       fontsel->face = face;
924
925       g_object_unref (face);
926     }
927
928   gtk_font_selection_show_available_sizes (fontsel, FALSE);
929   gtk_font_selection_select_best_size (fontsel);
930 }
931
932 static void
933 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel,
934                                          gboolean          first_time)
935 {
936   gint i;
937   GtkListStore *model;
938   GtkTreeSelection *selection;
939   gchar buffer[128];
940   gchar *p;
941       
942   model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->size_list)));
943   selection = gtk_tree_view_get_selection (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 gchar *
1171 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
1172 {
1173   gchar *result;
1174   
1175   PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1176   result = pango_font_description_to_string (font_desc);
1177   pango_font_description_free (font_desc);
1178
1179   return result;
1180 }
1181
1182
1183 /* This sets the current font, selecting the appropriate list rows.
1184    First we check the fontname is valid and try to find the font family
1185    - i.e. the name in the main list. If we can't find that, then just return.
1186    Next we try to set each of the properties according to the fontname.
1187    Finally we select the font family & style in the lists. */
1188 gboolean
1189 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
1190                                   const gchar      *fontname)
1191 {
1192   PangoFontFamily *new_family = NULL;
1193   PangoFontFace *new_face = NULL;
1194   PangoFontFace *fallback_face = NULL;
1195   PangoFontDescription *new_desc;
1196   GtkTreeModel *model;
1197   GtkTreeIter iter;
1198   GtkTreeIter match_iter;
1199   gboolean valid;
1200   
1201   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
1202   
1203   new_desc = pango_font_description_from_string (fontname);
1204
1205   /* Check to make sure that this is in the list of allowed fonts */
1206
1207   model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list));
1208   for (valid = gtk_tree_model_get_iter_first (model, &iter);
1209        valid;
1210        valid = gtk_tree_model_iter_next (model, &iter))
1211     {
1212       PangoFontFamily *family;
1213       
1214       gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
1215       
1216       if (g_ascii_strcasecmp (pango_font_family_get_name (family),
1217                               pango_font_description_get_family (new_desc)) == 0)
1218         new_family = family;
1219       
1220       g_object_unref (family);
1221       
1222       if (new_family)
1223         break;
1224     }
1225
1226   if (!new_family)
1227     return FALSE;
1228
1229   fontsel->family = new_family;
1230   set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &iter);
1231   gtk_font_selection_show_available_styles (fontsel);
1232
1233   model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
1234   for (valid = gtk_tree_model_get_iter_first (model, &iter);
1235        valid;
1236        valid = gtk_tree_model_iter_next (model, &iter))
1237     {
1238       PangoFontFace *face;
1239       PangoFontDescription *tmp_desc;
1240       
1241       gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
1242       tmp_desc = pango_font_face_describe (face);
1243       
1244       if (font_description_style_equal (tmp_desc, new_desc))
1245         new_face = face;
1246       
1247       if (!fallback_face)
1248         {
1249           fallback_face = face;
1250           match_iter = iter;
1251         }
1252       
1253       pango_font_description_free (tmp_desc);
1254       g_object_unref (face);
1255       
1256       if (new_face)
1257         {
1258           match_iter = iter;
1259           break;
1260         }
1261     }
1262
1263   if (!new_face)
1264     new_face = fallback_face;
1265
1266   fontsel->face = new_face;
1267   set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_iter);  
1268
1269   gtk_font_selection_set_size (fontsel, pango_font_description_get_size (new_desc));
1270   
1271   g_object_freeze_notify (G_OBJECT (fontsel));
1272   g_object_notify (G_OBJECT (fontsel), "font_name");
1273   g_object_notify (G_OBJECT (fontsel), "font");
1274   g_object_thaw_notify (G_OBJECT (fontsel));
1275
1276   pango_font_description_free (new_desc);
1277
1278   return TRUE;
1279 }
1280
1281
1282 /* This returns the text in the preview entry. You should copy the returned
1283    text if you need it. */
1284 G_CONST_RETURN gchar*
1285 gtk_font_selection_get_preview_text  (GtkFontSelection *fontsel)
1286 {
1287   return gtk_entry_get_text (GTK_ENTRY (fontsel->preview_entry));
1288 }
1289
1290
1291 /* This sets the text in the preview entry. */
1292 void
1293 gtk_font_selection_set_preview_text  (GtkFontSelection *fontsel,
1294                                       const gchar         *text)
1295 {
1296   gtk_entry_set_text (GTK_ENTRY (fontsel->preview_entry), text);
1297 }
1298
1299 /*****************************************************************************
1300  * GtkFontSelectionDialog
1301  *****************************************************************************/
1302
1303 GType
1304 gtk_font_selection_dialog_get_type (void)
1305 {
1306   static GType font_selection_dialog_type = 0;
1307   
1308   if (!font_selection_dialog_type)
1309     {
1310       static const GTypeInfo fontsel_diag_info =
1311       {
1312         sizeof (GtkFontSelectionDialogClass),
1313         NULL,           /* base_init */
1314         NULL,           /* base_finalize */
1315         (GClassInitFunc) gtk_font_selection_dialog_class_init,
1316         NULL,           /* class_finalize */
1317         NULL,           /* class_data */
1318         sizeof (GtkFontSelectionDialog),
1319         0,              /* n_preallocs */
1320         (GInstanceInitFunc) gtk_font_selection_dialog_init,
1321       };
1322       
1323       font_selection_dialog_type =
1324         g_type_register_static (GTK_TYPE_DIALOG, "GtkFontSelectionDialog",
1325                                 &fontsel_diag_info, 0);
1326     }
1327   
1328   return font_selection_dialog_type;
1329 }
1330
1331 static void
1332 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
1333 {
1334   font_selection_dialog_parent_class = g_type_class_peek_parent (klass);
1335 }
1336
1337 static void
1338 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
1339 {
1340   GtkDialog *dialog;
1341
1342   gtk_widget_push_composite_child ();
1343
1344   dialog = GTK_DIALOG (fontseldiag);
1345   
1346   gtk_container_set_border_width (GTK_CONTAINER (fontseldiag), 4);
1347   gtk_window_set_resizable (GTK_WINDOW (fontseldiag), TRUE);
1348   
1349   fontseldiag->main_vbox = dialog->vbox;
1350   
1351   fontseldiag->fontsel = gtk_font_selection_new ();
1352   gtk_container_set_border_width (GTK_CONTAINER (fontseldiag->fontsel), 4);
1353   gtk_widget_show (fontseldiag->fontsel);
1354   gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
1355                       fontseldiag->fontsel, TRUE, TRUE, 0);
1356   
1357   /* Create the action area */
1358   fontseldiag->action_area = dialog->action_area;
1359
1360   fontseldiag->cancel_button = gtk_dialog_add_button (dialog,
1361                                                       GTK_STOCK_CANCEL,
1362                                                       GTK_RESPONSE_CANCEL);
1363
1364   fontseldiag->apply_button = gtk_dialog_add_button (dialog,
1365                                                      GTK_STOCK_APPLY,
1366                                                      GTK_RESPONSE_APPLY);
1367   gtk_widget_hide (fontseldiag->apply_button);
1368
1369   fontseldiag->ok_button = gtk_dialog_add_button (dialog,
1370                                                   GTK_STOCK_OK,
1371                                                   GTK_RESPONSE_OK);
1372   gtk_widget_grab_default (fontseldiag->ok_button);
1373   
1374   gtk_dialog_set_alternative_button_order (GTK_DIALOG (fontseldiag),
1375                                            GTK_RESPONSE_OK,
1376                                            GTK_RESPONSE_APPLY,
1377                                            GTK_RESPONSE_CANCEL,
1378                                            -1);
1379
1380
1381   gtk_window_set_title (GTK_WINDOW (fontseldiag),
1382                         _("Font Selection"));
1383
1384   gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
1385   
1386   gtk_widget_pop_composite_child ();
1387 }
1388
1389 GtkWidget*
1390 gtk_font_selection_dialog_new (const gchar *title)
1391 {
1392   GtkFontSelectionDialog *fontseldiag;
1393   
1394   fontseldiag = g_object_new (GTK_TYPE_FONT_SELECTION_DIALOG, NULL);
1395
1396   if (title)
1397     gtk_window_set_title (GTK_WINDOW (fontseldiag), title);
1398   
1399   return GTK_WIDGET (fontseldiag);
1400 }
1401
1402 gchar*
1403 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
1404 {
1405   return gtk_font_selection_get_font_name (GTK_FONT_SELECTION (fsd->fontsel));
1406 }
1407
1408 GdkFont*
1409 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
1410 {
1411   return gtk_font_selection_get_font (GTK_FONT_SELECTION (fsd->fontsel));
1412 }
1413
1414 gboolean
1415 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
1416                                          const gchar      *fontname)
1417 {
1418   return gtk_font_selection_set_font_name (GTK_FONT_SELECTION (fsd->fontsel), fontname);
1419 }
1420
1421 G_CONST_RETURN gchar*
1422 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
1423 {
1424   return gtk_font_selection_get_preview_text (GTK_FONT_SELECTION (fsd->fontsel));
1425 }
1426
1427 void
1428 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
1429                                             const gchar            *text)
1430 {
1431   gtk_font_selection_set_preview_text (GTK_FONT_SELECTION (fsd->fontsel), text);
1432 }