]> Pileus Git - ~andy/gtk/blob - gtk/gtkfontsel.c
eliminated some queue_draws when invoking gtk_widget_set_state, since that
[~andy/gtk] / gtk / gtkfontsel.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * GtkFontSelection widget for Gtk+, by Damon Chaplin, May 1998.
5  * Based on the GnomeFontSelector widget, by Elliot Lee, but major changes.
6  * The GnomeFontSelector was derived from app/text_tool.c in the GIMP.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 /*
25  * Limits:
26  *
27  *  Fontnames    - A maximum of MAX_FONTS (32767) fontnames will be retrieved
28  *                 from X Windows with XListFonts(). Any more are ignored.
29  *                 I think this limit may have been set because of a limit in
30  *                 GtkList. It could possibly be increased since we are using
31  *                 GtkClists now, but I'd be surprised if it was reached.
32  *  Field length - XLFD_MAX_FIELD_LEN is the maximum length that any field of a
33  *                 fontname can be for it to be considered valid. Others are
34  *                 ignored.
35  *  Properties   - Maximum of 65535 choices for each font property - guint16's
36  *                 are used as indices, e.g. in the FontInfo struct.
37  *  Combinations - Maximum of 65535 combinations of properties for each font
38  *                 family - a guint16 is used in the FontInfo struct.
39  *  Font size    - Minimum font size of 2 pixels/points, since trying to load
40  *                 some fonts with a size of 1 can cause X to hang.
41  *                 (e.g. the Misc Fixed fonts).
42  */
43
44 /*
45  * Possible Improvements:
46  *
47  *  Font Styles  - could sort the styles into a reasonable order - regular
48  *                 first, then bold, bold italic etc.
49  *
50  *  I18N         - the default preview text is not useful for international
51  *                 fonts. Maybe the first few characters of the font could be
52  *                 displayed instead.
53  *               - fontsets? should these be handled by the font dialog?
54  */
55
56 /*
57  * Debugging: compile with -DFONTSEL_DEBUG for lots of debugging output.
58  */
59
60
61 #include <stdlib.h>
62 #include <stdio.h>
63 #include <string.h>
64 #include <ctype.h>
65 #include <X11/Xlib.h>
66
67 #include "gdk/gdkx.h"
68 #include "gdk/gdkkeysyms.h"
69
70 #include "gtkbutton.h"
71 #include "gtkcheckbutton.h"
72 #include "gtkclist.h"
73 #include "gtkentry.h"
74 #include "gtkfontsel.h"
75 #include "gtkframe.h"
76 #include "gtkhbbox.h"
77 #include "gtkhbox.h"
78 #include "gtklabel.h"
79 #include "gtknotebook.h"
80 #include "gtkradiobutton.h"
81 #include "gtksignal.h"
82 #include "gtktable.h"
83 #include "gtkvbox.h"
84 #include "gtkscrolledwindow.h"
85 #include "gtkintl.h"
86
87 /* The maximum number of fontnames requested with XListFonts(). */
88 #define MAX_FONTS 32767
89
90 /* This is the largest field length we will accept. If a fontname has a field
91    larger than this we will skip it. */
92 #define XLFD_MAX_FIELD_LEN 64
93
94 /* These are what we use as the standard font sizes, for the size clist.
95    Note that when using points we still show these integer point values but
96    we work internally in decipoints (and decipoint values can be typed in). */
97 static const guint16 font_sizes[] = {
98   8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28,
99   32, 36, 40, 48, 56, 64, 72
100 };
101
102 /* Initial font metric & size (Remember point sizes are in decipoints).
103    The font size should match one of those in the font_sizes array. */
104 #define INITIAL_METRIC            GTK_FONT_METRIC_POINTS
105 #define INITIAL_FONT_SIZE         140
106
107 /* This is the default text shown in the preview entry, though the user
108    can set it. Remember that some fonts only have capital letters. */
109 #define PREVIEW_TEXT "abcdefghijk ABCDEFGHIJK"
110
111 /* This is the initial and maximum height of the preview entry (it expands
112    when large font sizes are selected). Initial height is also the minimum. */
113 #define INITIAL_PREVIEW_HEIGHT 44
114 #define MAX_PREVIEW_HEIGHT 300
115
116 /* These are the sizes of the font, style & size clists. */
117 #define FONT_LIST_HEIGHT        136
118 #define FONT_LIST_WIDTH         190
119 #define FONT_STYLE_LIST_WIDTH   170
120 #define FONT_SIZE_LIST_WIDTH    60
121
122 /* This is the number of fields in an X Logical Font Description font name.
123    Note that we count the registry & encoding as 1. */
124 #define GTK_XLFD_NUM_FIELDS 13
125
126 typedef struct _GtkFontSelInfo GtkFontSelInfo;
127 typedef struct _FontInfo FontInfo;
128 typedef struct _FontStyle FontStyle;
129
130 /* This struct represents one family of fonts (with one foundry), e.g. adobe
131    courier or sony fixed. It stores the family name, the index of the foundry
132    name, and the index of and number of available styles. */
133 struct _FontInfo
134 {
135   gchar   *family;
136   guint16  foundry;
137   gint     style_index;
138   guint16  nstyles;
139 };
140
141 /* This represents one style, as displayed in the Font Style clist. It can
142    have a number of available pixel sizes and point sizes. The indexes point
143    into the two big fontsel_info->pixel_sizes & fontsel_info->point_sizes
144    arrays. The displayed flag is used when displaying styles to remember which
145    styles have already been displayed. Note that it is combined with the
146    GtkFontType in the flags field. */
147 #define  GTK_FONT_DISPLAYED     (1 << 7)
148 struct _FontStyle
149 {
150   guint16  properties[GTK_NUM_STYLE_PROPERTIES];
151   gint     pixel_sizes_index;
152   guint16  npixel_sizes;
153   gint     point_sizes_index;
154   guint16  npoint_sizes;
155   guint8   flags;
156 };
157
158 struct _GtkFontSelInfo {
159   
160   /* This is a table with each FontInfo representing one font family+foundry */
161   FontInfo *font_info;
162   gint nfonts;
163   
164   /* This stores all the valid combinations of properties for every family.
165      Each FontInfo holds an index into its own space in this one big array. */
166   FontStyle *font_styles;
167   gint nstyles;
168   
169   /* This stores all the font sizes available for every style.
170      Each style holds an index into these arrays. */
171   guint16 *pixel_sizes;
172   guint16 *point_sizes;
173   
174   /* These are the arrays of strings of all possible weights, slants, 
175      set widths, spacings, charsets & foundries, and the amount of space
176      allocated for each array. */
177   gchar **properties[GTK_NUM_FONT_PROPERTIES];
178   guint16 nproperties[GTK_NUM_FONT_PROPERTIES];
179   guint16 space_allocated[GTK_NUM_FONT_PROPERTIES];
180 };
181
182 /* These are the field numbers in the X Logical Font Description fontnames,
183    e.g. -adobe-courier-bold-o-normal--25-180-100-100-m-150-iso8859-1 */
184 typedef enum
185 {
186   XLFD_FOUNDRY          = 0,
187   XLFD_FAMILY           = 1,
188   XLFD_WEIGHT           = 2,
189   XLFD_SLANT            = 3,
190   XLFD_SET_WIDTH        = 4,
191   XLFD_ADD_STYLE        = 5,
192   XLFD_PIXELS           = 6,
193   XLFD_POINTS           = 7,
194   XLFD_RESOLUTION_X     = 8,
195   XLFD_RESOLUTION_Y     = 9,
196   XLFD_SPACING          = 10,
197   XLFD_AVERAGE_WIDTH    = 11,
198   XLFD_CHARSET          = 12
199 } FontField;
200
201 /* These are the names of the fields, used on the info & filter page. */
202 static const gchar* xlfd_field_names[GTK_XLFD_NUM_FIELDS] = {
203   N_("Foundry:"),
204   N_("Family:"),
205   N_("Weight:"),
206   N_("Slant:"),
207   N_("Set Width:"),
208   N_("Add Style:"),
209   N_("Pixel Size:"),
210   N_("Point Size:"),
211   N_("Resolution X:"),
212   N_("Resolution Y:"),
213   N_("Spacing:"),
214   N_("Average Width:"),
215   N_("Charset:"),
216 };
217
218 /* These are the array indices of the font properties used in several arrays,
219    and should match the xlfd_index array below. */
220 typedef enum
221 {
222   WEIGHT        = 0,
223   SLANT         = 1,
224   SET_WIDTH     = 2,
225   SPACING       = 3,
226   CHARSET       = 4,
227   FOUNDRY       = 5
228 } PropertyIndexType;
229
230 /* This is used to look up a field in a fontname given one of the above
231    property indices. */
232 static const FontField xlfd_index[GTK_NUM_FONT_PROPERTIES] = {
233   XLFD_WEIGHT,
234   XLFD_SLANT,
235   XLFD_SET_WIDTH,
236   XLFD_SPACING,
237   XLFD_CHARSET,
238   XLFD_FOUNDRY
239 };
240
241 /* These are the positions of the properties in the filter table - x, y. */
242 static const gint filter_positions[GTK_NUM_FONT_PROPERTIES][2] = {
243   { 1, 0 }, { 0, 2 }, { 1, 2 }, { 2, 2 }, { 2, 0 }, { 0, 0 }
244 };
245 static const gint filter_heights[GTK_NUM_FONT_PROPERTIES] = {
246   100, 70, 70, 40, 100, 100
247 };
248
249 /* This is returned by gtk_font_selection_filter_state to describe if a
250    property value is filtered. e.g. if 'bold' has been selected on the filter
251    page, then that will return 'FILTERED' and 'black' will be 'NOT_FILTERED'.
252    If none of the weight values are selected, they all return 'NOT_SET'. */
253 typedef enum
254 {
255   FILTERED,
256   NOT_FILTERED,
257   NOT_SET
258 } GtkFontPropertyFilterState;
259
260 static GtkFontSelInfo *fontsel_info = NULL;
261
262 /* The initial size and increment of each of the arrays of property values. */
263 #define PROPERTY_ARRAY_INCREMENT        16
264
265 static void    gtk_font_selection_class_init         (GtkFontSelectionClass *klass);
266 static void    gtk_font_selection_init               (GtkFontSelection *fontsel);
267 static void    gtk_font_selection_destroy            (GtkObject      *object);
268
269 /* These are all used for class initialization - loading in the fonts etc. */
270 static void    gtk_font_selection_get_fonts          (void);
271 static void    gtk_font_selection_insert_font        (GSList         *fontnames[],
272                                                       gint           *ntable,
273                                                       gchar          *fontname);
274 static gint    gtk_font_selection_insert_field       (gchar          *fontname,
275                                                       gint            prop);
276
277 /* These are the callbacks & related functions. */
278 static void    gtk_font_selection_select_font        (GtkWidget      *w,
279                                                       gint            row,
280                                                       gint            column,
281                                                       GdkEventButton *bevent,
282                                                       gpointer        data);
283 static gint    gtk_font_selection_on_clist_key_press (GtkWidget      *clist,
284                                                       GdkEventKey    *event,
285                                                       GtkFontSelection *fs);
286 static gboolean gtk_font_selection_select_next       (GtkFontSelection *fs,
287                                                       GtkWidget        *clist,
288                                                       gint              step);
289 static void    gtk_font_selection_show_available_styles
290 (GtkFontSelection *fs);
291 static void    gtk_font_selection_select_best_style  (GtkFontSelection *fs,
292                                                       gboolean         use_first);
293
294 static void    gtk_font_selection_select_style       (GtkWidget      *w,
295                                                       gint            row,
296                                                       gint            column,
297                                                       GdkEventButton *bevent,
298                                                       gpointer        data);
299 static void    gtk_font_selection_show_available_sizes
300 (GtkFontSelection *fs);
301 static gint    gtk_font_selection_size_key_press     (GtkWidget      *w,
302                                                       GdkEventKey    *event,
303                                                       gpointer        data);
304 static void    gtk_font_selection_select_best_size   (GtkFontSelection *fs);
305 static void    gtk_font_selection_select_size        (GtkWidget      *w,
306                                                       gint            row,
307                                                       gint            column,
308                                                       GdkEventButton *bevent,
309                                                       gpointer        data);
310
311 static void    gtk_font_selection_metric_callback    (GtkWidget      *w,
312                                                       gpointer        data);
313 static void    gtk_font_selection_expose_list        (GtkWidget      *w,
314                                                       GdkEventExpose *event,
315                                                       gpointer        data);
316 static void    gtk_font_selection_realize_list       (GtkWidget      *widget,
317                                                       gpointer        data);
318
319 static void    gtk_font_selection_switch_page        (GtkWidget      *w,
320                                                       GtkNotebookPage *page,
321                                                       gint             page_num,
322                                                       gpointer         data);
323 static void    gtk_font_selection_show_font_info     (GtkFontSelection *fs);
324
325 static void    gtk_font_selection_select_filter      (GtkWidget      *w,
326                                                       gint            row,
327                                                       gint            column,
328                                                       GdkEventButton *bevent,
329                                                       GtkFontSelection *fs);
330 static void    gtk_font_selection_unselect_filter    (GtkWidget      *w,
331                                                       gint            row,
332                                                       gint            column,
333                                                       GdkEventButton *bevent,
334                                                       GtkFontSelection *fs);
335 static void    gtk_font_selection_update_filter      (GtkFontSelection *fs);
336 static gboolean gtk_font_selection_style_visible     (GtkFontSelection *fs,
337                                                       FontInfo       *font,
338                                                       gint            style);
339 static void    gtk_font_selection_reset_filter       (GtkWidget      *w,
340                                                       GtkFontSelection *fs);
341 static void    gtk_font_selection_on_clear_filter    (GtkWidget      *w,
342                                                       GtkFontSelection *fs);
343 static void    gtk_font_selection_show_available_fonts
344                                                      (GtkFontSelection *fs);
345 static void    gtk_font_selection_clear_filter       (GtkFontSelection *fs);
346 static void    gtk_font_selection_update_filter_lists(GtkFontSelection *fs);
347 static GtkFontPropertyFilterState gtk_font_selection_filter_state
348                                                      (GtkFontSelection *fs,
349                                                       GtkFontFilterType filter_type,
350                                                       gint              property,
351                                                       gint              index);
352
353 /* Misc. utility functions. */
354 static gboolean gtk_font_selection_load_font         (GtkFontSelection *fs);
355 static void    gtk_font_selection_update_preview     (GtkFontSelection *fs);
356
357 static gint    gtk_font_selection_find_font          (GtkFontSelection *fs,
358                                                       gchar          *family,
359                                                       guint16         foundry);
360 static guint16 gtk_font_selection_field_to_index     (gchar         **table,
361                                                       gint            ntable,
362                                                       gchar          *field);
363
364 static gchar*  gtk_font_selection_expand_slant_code  (gchar          *slant);
365 static gchar*  gtk_font_selection_expand_spacing_code(gchar          *spacing);
366
367 /* Functions for handling X Logical Font Description fontnames. */
368 static gboolean gtk_font_selection_is_xlfd_font_name (const gchar    *fontname);
369 static char*   gtk_font_selection_get_xlfd_field     (const gchar    *fontname,
370                                                       FontField       field_num,
371                                                       gchar          *buffer);
372 static gchar * gtk_font_selection_create_xlfd        (gint            size,
373                                                       GtkFontMetricType metric,
374                                                       gchar          *foundry,
375                                                       gchar          *family,
376                                                       gchar          *weight,
377                                                       gchar          *slant,
378                                                       gchar          *set_width,
379                                                       gchar          *spacing,
380                                                       gchar          *charset);
381
382
383 /* FontSelectionDialog */
384 static void    gtk_font_selection_dialog_class_init  (GtkFontSelectionDialogClass *klass);
385 static void    gtk_font_selection_dialog_init        (GtkFontSelectionDialog *fontseldiag);
386
387 static gint    gtk_font_selection_dialog_on_configure(GtkWidget      *widget,
388                                                       GdkEventConfigure *event,
389                                                       GtkFontSelectionDialog *fsd);
390
391 static GtkWindowClass *font_selection_parent_class = NULL;
392 static GtkNotebookClass *font_selection_dialog_parent_class = NULL;
393
394 GtkType
395 gtk_font_selection_get_type()
396 {
397   static GtkType font_selection_type = 0;
398   
399   if(!font_selection_type)
400     {
401       static const GtkTypeInfo fontsel_type_info =
402       {
403         "GtkFontSelection",
404         sizeof (GtkFontSelection),
405         sizeof (GtkFontSelectionClass),
406         (GtkClassInitFunc) gtk_font_selection_class_init,
407         (GtkObjectInitFunc) gtk_font_selection_init,
408         /* reserved_1 */ NULL,
409         /* reserved_2 */ NULL,
410         (GtkClassInitFunc) NULL,
411       };
412       
413       font_selection_type = gtk_type_unique (GTK_TYPE_NOTEBOOK,
414                                              &fontsel_type_info);
415     }
416   
417   return font_selection_type;
418 }
419
420 static void
421 gtk_font_selection_class_init(GtkFontSelectionClass *klass)
422 {
423   GtkObjectClass *object_class;
424   
425   object_class = (GtkObjectClass *) klass;
426   
427   font_selection_parent_class = gtk_type_class (GTK_TYPE_NOTEBOOK);
428   
429   object_class->destroy = gtk_font_selection_destroy;
430   
431   gtk_font_selection_get_fonts ();
432 }
433
434 static void
435 gtk_font_selection_init(GtkFontSelection *fontsel)
436 {
437   GtkWidget *scrolled_win;
438   GtkWidget *text_frame;
439   GtkWidget *text_box, *frame;
440   GtkWidget *table, *label, *hbox, *hbox2, *clist, *button, *vbox, *alignment;
441   gint i, prop, row;
442   gchar *titles[] = { NULL, NULL, NULL };
443   gchar buffer[128];
444   gchar *size;
445   gint size_to_match;
446   gchar *row_text[3];
447   gchar *property, *text;
448   gboolean inserted;
449   
450   /* Number of internationalized titles here must match number
451      of NULL initializers above */
452   titles[0] = _("Font Property");
453   titles[1] = _("Requested Value");
454   titles[2] = _("Actual Value");
455
456   /* Initialize the GtkFontSelection struct. We do this here in case any
457      callbacks are triggered while creating the interface. */
458   fontsel->font = NULL;
459   fontsel->font_index = -1;
460   fontsel->style = -1;
461   fontsel->metric = INITIAL_METRIC;
462   fontsel->size = INITIAL_FONT_SIZE;
463   fontsel->selected_size = INITIAL_FONT_SIZE;
464
465   fontsel->filters[GTK_FONT_FILTER_BASE].font_type = GTK_FONT_ALL;
466   fontsel->filters[GTK_FONT_FILTER_USER].font_type = GTK_FONT_BITMAP
467     | GTK_FONT_SCALABLE;
468
469   
470   for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
471     {
472       fontsel->filters[GTK_FONT_FILTER_BASE].property_filters[prop] = NULL;
473       fontsel->filters[GTK_FONT_FILTER_BASE].property_nfilters[prop] = 0;
474       fontsel->filters[GTK_FONT_FILTER_USER].property_filters[prop] = NULL;
475       fontsel->filters[GTK_FONT_FILTER_USER].property_nfilters[prop] = 0;
476     }
477   
478   for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
479     fontsel->property_values[prop] = 0;
480   
481   /* Create the main notebook page. */
482   gtk_notebook_set_homogeneous_tabs (GTK_NOTEBOOK (fontsel), TRUE);
483   gtk_notebook_set_tab_hborder (GTK_NOTEBOOK (fontsel), 8);
484   fontsel->main_vbox = gtk_vbox_new (FALSE, 4);
485   gtk_widget_show (fontsel->main_vbox);
486   gtk_container_set_border_width (GTK_CONTAINER (fontsel->main_vbox), 6);
487   label = gtk_label_new(_("Font"));
488   gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
489                             fontsel->main_vbox, label);
490   
491   /* Create the table of font, style & size. */
492   table = gtk_table_new (3, 3, FALSE);
493   gtk_widget_show (table);
494   gtk_table_set_col_spacings(GTK_TABLE(table), 8);
495   gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), table, TRUE, TRUE, 0);
496   
497   fontsel->font_label = gtk_label_new(_("Font:"));
498   gtk_misc_set_alignment (GTK_MISC (fontsel->font_label), 0.0, 0.5);
499   gtk_widget_show (fontsel->font_label);
500   gtk_table_attach (GTK_TABLE (table), fontsel->font_label, 0, 1, 0, 1,
501                     GTK_FILL, 0, 0, 0);
502   label = gtk_label_new(_("Font Style:"));
503   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
504   gtk_widget_show (label);
505   gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1,
506                     GTK_FILL, 0, 0, 0);
507   label = gtk_label_new(_("Size:"));
508   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
509   gtk_widget_show (label);
510   gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
511                     GTK_FILL, 0, 0, 0);
512   
513   fontsel->font_entry = gtk_entry_new();
514   gtk_entry_set_editable(GTK_ENTRY(fontsel->font_entry), FALSE);
515   gtk_widget_set_usize (fontsel->font_entry, 20, -1);
516   gtk_widget_show (fontsel->font_entry);
517   gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
518                     GTK_FILL, 0, 0, 0);
519   fontsel->font_style_entry = gtk_entry_new();
520   gtk_entry_set_editable(GTK_ENTRY(fontsel->font_style_entry), FALSE);
521   gtk_widget_set_usize (fontsel->font_style_entry, 20, -1);
522   gtk_widget_show (fontsel->font_style_entry);
523   gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
524                     GTK_FILL, 0, 0, 0);
525   fontsel->size_entry = gtk_entry_new();
526   gtk_widget_set_usize (fontsel->size_entry, 20, -1);
527   gtk_widget_show (fontsel->size_entry);
528   gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
529                     GTK_FILL, 0, 0, 0);
530   gtk_signal_connect (GTK_OBJECT (fontsel->size_entry), "key_press_event",
531                       (GtkSignalFunc) gtk_font_selection_size_key_press,
532                       fontsel);
533   
534   /* Create the clists  */
535   fontsel->font_clist = gtk_clist_new(1);
536   gtk_clist_column_titles_hide (GTK_CLIST(fontsel->font_clist));
537   gtk_clist_set_column_auto_resize (GTK_CLIST (fontsel->font_clist), 0, TRUE);
538   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
539   gtk_widget_set_usize (scrolled_win, FONT_LIST_WIDTH, FONT_LIST_HEIGHT);
540   gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->font_clist);
541   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
542                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
543   gtk_widget_show(fontsel->font_clist);
544   gtk_widget_show(scrolled_win);
545
546   gtk_table_attach (GTK_TABLE (table), scrolled_win, 0, 1, 2, 3,
547                     GTK_EXPAND | GTK_FILL,
548                     GTK_EXPAND | GTK_FILL, 0, 0);
549   
550   fontsel->font_style_clist = gtk_clist_new(1);
551   gtk_clist_column_titles_hide (GTK_CLIST(fontsel->font_style_clist));
552   gtk_clist_set_column_auto_resize (GTK_CLIST (fontsel->font_style_clist),
553                                     0, TRUE);
554   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
555   gtk_widget_set_usize (scrolled_win, FONT_STYLE_LIST_WIDTH, -1);
556   gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->font_style_clist);
557   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
558                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
559   gtk_widget_show(fontsel->font_style_clist);
560   gtk_widget_show(scrolled_win);
561   gtk_table_attach (GTK_TABLE (table), scrolled_win, 1, 2, 2, 3,
562                     GTK_EXPAND | GTK_FILL,
563                     GTK_EXPAND | GTK_FILL, 0, 0);
564   
565   fontsel->size_clist = gtk_clist_new(1);
566   gtk_clist_column_titles_hide (GTK_CLIST(fontsel->size_clist));
567   gtk_clist_set_column_width (GTK_CLIST(fontsel->size_clist), 0, 20);
568   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
569   gtk_widget_set_usize (scrolled_win, FONT_SIZE_LIST_WIDTH, -1);
570   gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->size_clist);
571   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
572                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
573   gtk_widget_show(fontsel->size_clist);
574   gtk_widget_show(scrolled_win);
575   gtk_table_attach (GTK_TABLE (table), scrolled_win, 2, 3, 2, 3,
576                     GTK_FILL, GTK_FILL, 0, 0);
577   
578   
579   /* Insert the fonts. If there exist fonts with the same family but
580      different foundries, then the foundry name is appended in brackets. */
581   gtk_font_selection_show_available_fonts(fontsel);
582   
583   gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "select_row",
584                       GTK_SIGNAL_FUNC(gtk_font_selection_select_font),
585                       fontsel);
586   GTK_WIDGET_SET_FLAGS (fontsel->font_clist, GTK_CAN_FOCUS);
587   gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "key_press_event",
588                       GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
589                       fontsel);
590   gtk_signal_connect_after (GTK_OBJECT (fontsel->font_clist), "expose_event",
591                             GTK_SIGNAL_FUNC(gtk_font_selection_expose_list),
592                             fontsel);
593   
594   gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist), "select_row",
595                       GTK_SIGNAL_FUNC(gtk_font_selection_select_style),
596                       fontsel);
597   GTK_WIDGET_SET_FLAGS (fontsel->font_style_clist, GTK_CAN_FOCUS);
598   gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist),
599                       "key_press_event",
600                       GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
601                       fontsel);
602   gtk_signal_connect_after (GTK_OBJECT (fontsel->font_style_clist),
603                             "realize",
604                             GTK_SIGNAL_FUNC(gtk_font_selection_realize_list),
605                             fontsel);
606   
607   /* Insert the standard font sizes */
608   gtk_clist_freeze (GTK_CLIST(fontsel->size_clist));
609   size_to_match = INITIAL_FONT_SIZE;
610   if (INITIAL_METRIC == GTK_FONT_METRIC_POINTS)
611     size_to_match = size_to_match / 10;
612   for (i = 0; i < sizeof(font_sizes) / sizeof(font_sizes[0]); i++)
613     {
614       sprintf(buffer, "%i", font_sizes[i]);
615       size = buffer;
616       gtk_clist_append(GTK_CLIST(fontsel->size_clist), &size);
617       if (font_sizes[i] == size_to_match)
618         {
619           gtk_clist_select_row(GTK_CLIST(fontsel->size_clist), i, 0);
620           gtk_entry_set_text(GTK_ENTRY(fontsel->size_entry), buffer);
621         }
622     }
623   gtk_clist_thaw (GTK_CLIST(fontsel->size_clist));
624   
625   gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "select_row",
626                       GTK_SIGNAL_FUNC(gtk_font_selection_select_size),
627                       fontsel);
628   GTK_WIDGET_SET_FLAGS (fontsel->size_clist, GTK_CAN_FOCUS);
629   gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "key_press_event",
630                       GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
631                       fontsel);
632   
633   
634   /* create the Reset Filter & Metric buttons */
635   hbox = gtk_hbox_new(FALSE, 8);
636   gtk_widget_show (hbox);
637   gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), hbox, FALSE, TRUE, 0);
638   
639   fontsel->filter_button = gtk_button_new_with_label(_("Reset Filter"));
640   gtk_misc_set_padding (GTK_MISC (GTK_BIN (fontsel->filter_button)->child),
641                         16, 0);
642   gtk_widget_show(fontsel->filter_button);
643   gtk_box_pack_start (GTK_BOX (hbox), fontsel->filter_button, FALSE, FALSE, 0);
644   gtk_widget_set_sensitive (fontsel->filter_button, FALSE);
645   gtk_signal_connect (GTK_OBJECT (fontsel->filter_button), "clicked",
646                       GTK_SIGNAL_FUNC(gtk_font_selection_on_clear_filter),
647                       fontsel);
648   
649   hbox2 = gtk_hbox_new(FALSE, 0);
650   gtk_widget_show (hbox2);
651   gtk_box_pack_end (GTK_BOX (hbox), hbox2, FALSE, FALSE, 0);
652   
653   label = gtk_label_new(_("Metric:"));
654   gtk_widget_show (label);
655   gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 8);
656   
657   fontsel->points_button = gtk_radio_button_new_with_label(NULL, _("Points"));
658   gtk_widget_show (fontsel->points_button);
659   gtk_box_pack_start (GTK_BOX (hbox2), fontsel->points_button, FALSE, TRUE, 0);
660   if (INITIAL_METRIC == GTK_FONT_METRIC_POINTS)
661     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fontsel->points_button),
662                                 TRUE);
663   
664   fontsel->pixels_button = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(fontsel->points_button), _("Pixels"));
665   gtk_widget_show (fontsel->pixels_button);
666   gtk_box_pack_start (GTK_BOX (hbox2), fontsel->pixels_button, FALSE, TRUE, 0);
667   if (INITIAL_METRIC == GTK_FONT_METRIC_PIXELS)
668     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fontsel->pixels_button),
669                                 TRUE);
670   
671   gtk_signal_connect(GTK_OBJECT(fontsel->points_button), "toggled",
672                      (GtkSignalFunc) gtk_font_selection_metric_callback,
673                      fontsel);
674   gtk_signal_connect(GTK_OBJECT(fontsel->pixels_button), "toggled",
675                      (GtkSignalFunc) gtk_font_selection_metric_callback,
676                      fontsel);
677   
678   
679   /* create the text entry widget */
680   text_frame = gtk_frame_new (_("Preview:"));
681   gtk_widget_show (text_frame);
682   gtk_frame_set_shadow_type(GTK_FRAME(text_frame), GTK_SHADOW_ETCHED_IN);
683   gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), text_frame,
684                       FALSE, TRUE, 0);
685   
686   /* This is just used to get a 4-pixel space around the preview entry. */
687   text_box = gtk_hbox_new (FALSE, 0);
688   gtk_widget_show (text_box);
689   gtk_container_add (GTK_CONTAINER (text_frame), text_box);
690   gtk_container_set_border_width (GTK_CONTAINER (text_box), 4);
691   
692   fontsel->preview_entry = gtk_entry_new ();
693   gtk_widget_show (fontsel->preview_entry);
694   gtk_widget_set_usize (fontsel->preview_entry, -1, INITIAL_PREVIEW_HEIGHT);
695   gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
696                       TRUE, TRUE, 0);
697   
698   /* Create the message area */
699   fontsel->message_label = gtk_label_new("");
700   gtk_widget_show (fontsel->message_label);
701   gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), fontsel->message_label, 
702                       FALSE, FALSE, 0);
703   
704   
705   /* Create the font info page */
706   fontsel->info_vbox = gtk_vbox_new (FALSE, 4);
707   gtk_widget_show (fontsel->info_vbox);
708   gtk_container_set_border_width (GTK_CONTAINER (fontsel->info_vbox), 2);
709   label = gtk_label_new(_("Font Information"));
710   gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
711                             fontsel->info_vbox, label);
712   
713   fontsel->info_clist = gtk_clist_new_with_titles (3, titles);
714   gtk_widget_set_usize (fontsel->info_clist, 390, 150);
715   gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 0, 130);
716   gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 1, 130);
717   gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 2, 130);
718   gtk_clist_column_titles_passive(GTK_CLIST(fontsel->info_clist));
719   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
720   gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->info_clist);
721   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
722                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
723   gtk_widget_show(fontsel->info_clist);
724   gtk_widget_show(scrolled_win);
725   gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), scrolled_win,
726                       TRUE, TRUE, 0);
727   
728   /* Insert the property names */
729   gtk_clist_freeze (GTK_CLIST(fontsel->info_clist));
730   row_text[1] = "";
731   row_text[2] = "";
732   for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
733     {
734       row_text[0] = gettext(xlfd_field_names[i]);
735       gtk_clist_append(GTK_CLIST(fontsel->info_clist), row_text);
736       gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 0, 0, 4);
737       gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 1, 0, 4);
738       gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 2, 0, 4);
739     }
740   gtk_clist_thaw (GTK_CLIST(fontsel->info_clist));
741   
742   label = gtk_label_new(_("Requested Font Name:"));
743   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
744   gtk_widget_show (label);
745   gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, TRUE, 0);
746   
747   fontsel->requested_font_name = gtk_entry_new();
748   gtk_entry_set_editable(GTK_ENTRY(fontsel->requested_font_name), FALSE);
749   gtk_widget_show (fontsel->requested_font_name);
750   gtk_box_pack_start (GTK_BOX (fontsel->info_vbox),
751                       fontsel->requested_font_name, FALSE, TRUE, 0);
752   
753   label = gtk_label_new(_("Actual Font Name:"));
754   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
755   gtk_widget_show (label);
756   gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, TRUE, 0);
757   
758   fontsel->actual_font_name = gtk_entry_new();
759   gtk_entry_set_editable(GTK_ENTRY(fontsel->actual_font_name), FALSE);
760   gtk_widget_show (fontsel->actual_font_name);
761   gtk_box_pack_start (GTK_BOX (fontsel->info_vbox),
762                       fontsel->actual_font_name, FALSE, TRUE, 0);
763   
764   sprintf(buffer, _("%i fonts available with a total of %i styles."),
765           fontsel_info->nfonts, fontsel_info->nstyles);
766   label = gtk_label_new(buffer);
767   gtk_widget_show (label);
768   gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, FALSE, 0);
769   
770   gtk_signal_connect (GTK_OBJECT (fontsel), "switch_page",
771                       GTK_SIGNAL_FUNC(gtk_font_selection_switch_page),
772                       fontsel);
773   
774   
775   /* Create the Filter page. */
776   fontsel->filter_vbox = gtk_vbox_new (FALSE, 4);
777   gtk_widget_show (fontsel->filter_vbox);
778   gtk_container_set_border_width (GTK_CONTAINER (fontsel->filter_vbox), 2);
779   label = gtk_label_new(_("Filter"));
780   gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
781                             fontsel->filter_vbox, label);
782   
783   /* Create the font type checkbuttons. */
784   frame = gtk_frame_new (NULL);
785   gtk_widget_show (frame);
786   gtk_box_pack_start (GTK_BOX (fontsel->filter_vbox), frame, FALSE, TRUE, 0);
787
788   hbox = gtk_hbox_new (FALSE, 20);
789   gtk_widget_show (hbox);
790   gtk_container_add (GTK_CONTAINER (frame), hbox);
791
792   label = gtk_label_new(_("Font Types:"));
793   gtk_widget_show (label);
794   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 10);
795
796   hbox2 = gtk_hbox_new (TRUE, 0);
797   gtk_widget_show (hbox2);
798   gtk_box_pack_start (GTK_BOX (hbox), hbox2, FALSE, TRUE, 0);
799
800   fontsel->type_bitmaps_button = gtk_check_button_new_with_label (_("Bitmap"));
801   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), TRUE);
802   gtk_widget_show (fontsel->type_bitmaps_button);
803   gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_bitmaps_button,
804                       FALSE, TRUE, 0);
805
806   fontsel->type_scalable_button = gtk_check_button_new_with_label (_("Scalable"));
807   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), TRUE);
808   gtk_widget_show (fontsel->type_scalable_button);
809   gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_scalable_button,
810                       FALSE, TRUE, 0);
811
812   fontsel->type_scaled_bitmaps_button = gtk_check_button_new_with_label (_("Scaled Bitmap"));
813   gtk_widget_show (fontsel->type_scaled_bitmaps_button);
814   gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_scaled_bitmaps_button,
815                       FALSE, TRUE, 0);
816
817   table = gtk_table_new (4, 3, FALSE);
818   gtk_table_set_col_spacings(GTK_TABLE(table), 2);
819   gtk_widget_show (table);
820   gtk_box_pack_start (GTK_BOX (fontsel->filter_vbox), table, TRUE, TRUE, 0);
821   
822   for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
823     {
824       gint left = filter_positions[prop][0];
825       gint top = filter_positions[prop][1];
826       
827       label = gtk_label_new(gettext(xlfd_field_names[xlfd_index[prop]]));
828       gtk_misc_set_alignment (GTK_MISC (label), 0.0, 1.0);
829       gtk_misc_set_padding (GTK_MISC (label), 0, 2);
830       gtk_widget_show(label);
831       gtk_table_attach (GTK_TABLE (table), label, left, left + 1,
832                         top, top + 1, GTK_FILL, GTK_FILL, 0, 0);
833       
834       clist = gtk_clist_new(1);
835       gtk_widget_set_usize (clist, 100, filter_heights[prop]);
836       gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_MULTIPLE);
837       gtk_clist_column_titles_hide(GTK_CLIST(clist));
838       gtk_clist_set_column_auto_resize (GTK_CLIST (clist), 0, TRUE);
839       scrolled_win = gtk_scrolled_window_new (NULL, NULL);
840       gtk_container_add (GTK_CONTAINER (scrolled_win), clist);
841       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
842                                       GTK_POLICY_AUTOMATIC,
843                                       GTK_POLICY_AUTOMATIC);
844       gtk_widget_show(clist);
845       gtk_widget_show(scrolled_win);
846       
847       /* For the bottom-right cell we add the 'Reset Filter' button. */
848       if (top == 2 && left == 2)
849         {
850           vbox = gtk_vbox_new(FALSE, 0);
851           gtk_widget_show(vbox);
852           gtk_table_attach (GTK_TABLE (table), vbox, left, left + 1,
853                             top + 1, top + 2, GTK_FILL, GTK_FILL, 0, 0);
854           
855           gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0);
856           
857           alignment = gtk_alignment_new(0.5, 0.0, 0.8, 0.0);
858           gtk_widget_show(alignment);
859           gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, TRUE, 4);
860           
861           button = gtk_button_new_with_label(_("Reset Filter"));
862           gtk_widget_show(button);
863           gtk_container_add(GTK_CONTAINER(alignment), button);
864           gtk_signal_connect (GTK_OBJECT (button), "clicked",
865                               GTK_SIGNAL_FUNC(gtk_font_selection_reset_filter),
866                               fontsel);
867         }
868       else
869         gtk_table_attach (GTK_TABLE (table), scrolled_win,
870                           left, left + 1, top + 1, top + 2,
871                           GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
872       
873       gtk_signal_connect (GTK_OBJECT (clist), "select_row",
874                           GTK_SIGNAL_FUNC(gtk_font_selection_select_filter),
875                           fontsel);
876       gtk_signal_connect (GTK_OBJECT (clist), "unselect_row",
877                           GTK_SIGNAL_FUNC(gtk_font_selection_unselect_filter),
878                           fontsel);
879       
880       /* Insert the property names, expanded, and in sorted order.
881          But we make sure that the wildcard '*' is first. */
882       gtk_clist_freeze (GTK_CLIST(clist));
883       property = "*";
884       gtk_clist_append(GTK_CLIST(clist), &property);
885       
886       for (i = 1; i < fontsel_info->nproperties[prop]; i++) {
887         property = fontsel_info->properties[prop][i];
888         if (prop == SLANT)
889           property = gtk_font_selection_expand_slant_code(property);
890         else if (prop == SPACING)
891           property = gtk_font_selection_expand_spacing_code(property);
892         
893         inserted = FALSE;
894         for (row = 1; row < GTK_CLIST(clist)->rows; row++)
895           {
896             gtk_clist_get_text(GTK_CLIST(clist), row, 0, &text);
897             if (strcmp(property, text) < 0)
898               {
899                 inserted = TRUE;
900                 gtk_clist_insert(GTK_CLIST(clist), row, &property);
901                 break;
902               }
903           }
904         if (!inserted)
905           row = gtk_clist_append(GTK_CLIST(clist), &property);
906         gtk_clist_set_row_data(GTK_CLIST(clist), row, GINT_TO_POINTER (i));
907       }
908       gtk_clist_select_row(GTK_CLIST(clist), 0, 0);
909       gtk_clist_thaw (GTK_CLIST(clist));
910       fontsel->filter_clists[prop] = clist;
911     }
912 }
913
914 GtkWidget *
915 gtk_font_selection_new()
916 {
917   GtkFontSelection *fontsel;
918   
919   fontsel = gtk_type_new (GTK_TYPE_FONT_SELECTION);
920   
921   return GTK_WIDGET (fontsel);
922 }
923
924 static void
925 gtk_font_selection_destroy (GtkObject *object)
926 {
927   GtkFontSelection *fontsel;
928   
929   g_return_if_fail (object != NULL);
930   g_return_if_fail (GTK_IS_FONT_SELECTION (object));
931   
932   fontsel = GTK_FONT_SELECTION (object);
933   
934   /* All we have to do is unref the font, if we have one. */
935   if (fontsel->font)
936     gdk_font_unref (fontsel->font);
937   
938   if (GTK_OBJECT_CLASS (font_selection_parent_class)->destroy)
939     (* GTK_OBJECT_CLASS (font_selection_parent_class)->destroy) (object);
940 }
941
942
943 /* This is called when the clist is exposed. Here we scroll to the current
944    font if necessary. */
945 static void
946 gtk_font_selection_expose_list (GtkWidget               *widget,
947                                 GdkEventExpose          *event,
948                                 gpointer                 data)
949 {
950   GtkFontSelection *fontsel;
951   FontInfo *font_info;
952   GList *selection;
953   gint index;
954   
955 #ifdef FONTSEL_DEBUG
956   g_message("In expose_list\n");
957 #endif
958   fontsel = GTK_FONT_SELECTION(data);
959   
960   font_info = fontsel_info->font_info;
961       
962   /* Try to scroll the font family clist to the selected item */
963   selection = GTK_CLIST(fontsel->font_clist)->selection;
964   if (selection)
965     {
966       index = GPOINTER_TO_INT (selection->data);
967       if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_clist), index)
968           != GTK_VISIBILITY_FULL)
969         gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), index, -1, 0.5, 0);
970     }
971       
972   /* Try to scroll the font style clist to the selected item */
973   selection = GTK_CLIST(fontsel->font_style_clist)->selection;
974   if (selection)
975     {
976       index = GPOINTER_TO_INT (selection->data);
977       if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_style_clist), index)
978           != GTK_VISIBILITY_FULL)
979         gtk_clist_moveto(GTK_CLIST(fontsel->font_style_clist), index, -1,
980                          0.5, 0);
981     }
982       
983   /* Try to scroll the font size clist to the selected item */
984   selection = GTK_CLIST(fontsel->size_clist)->selection;
985   if (selection)
986     {
987       index = GPOINTER_TO_INT (selection->data);
988       if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->size_clist), index)
989           != GTK_VISIBILITY_FULL)
990       gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), index, -1, 0.5, 0);
991     }
992 }
993
994
995 /* This is called when the style clist is realized. We need to set any
996    charset rows to insensitive colours. */
997 static void
998 gtk_font_selection_realize_list (GtkWidget              *widget,
999                                  gpointer                data)
1000 {
1001   GtkFontSelection *fontsel;
1002   gint row;
1003   GdkColor *inactive_fg, *inactive_bg;
1004
1005 #ifdef FONTSEL_DEBUG
1006   g_message("In realize_list\n");
1007 #endif
1008   fontsel = GTK_FONT_SELECTION (data);
1009
1010   /* Set the colours for any charset rows to insensitive. */
1011   inactive_fg = &fontsel->font_style_clist->style->fg[GTK_STATE_INSENSITIVE];
1012   inactive_bg = &fontsel->font_style_clist->style->bg[GTK_STATE_INSENSITIVE];
1013
1014   for (row = 0; row < GTK_CLIST (fontsel->font_style_clist)->rows; row++)
1015     {
1016       if (GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_style_clist), row)) == -1)
1017         {
1018           gtk_clist_set_foreground (GTK_CLIST (fontsel->font_style_clist),
1019                                     row, inactive_fg);
1020           gtk_clist_set_background (GTK_CLIST (fontsel->font_style_clist),
1021                                     row, inactive_bg);
1022         }
1023     }
1024 }
1025
1026
1027 /* This is called when a family is selected in the list. */
1028 static void
1029 gtk_font_selection_select_font (GtkWidget      *w,
1030                                 gint            row,
1031                                 gint            column,
1032                                 GdkEventButton *bevent,
1033                                 gpointer        data)
1034 {
1035   GtkFontSelection *fontsel;
1036   FontInfo *font_info;
1037   FontInfo *font;
1038   
1039 #ifdef FONTSEL_DEBUG
1040   g_message("In select_font\n");
1041 #endif
1042   fontsel = GTK_FONT_SELECTION(data);
1043   font_info = fontsel_info->font_info;
1044   
1045   if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1046     gtk_widget_grab_focus (w);
1047   
1048   row = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_clist), row));
1049   font = &font_info[row];
1050   gtk_entry_set_text(GTK_ENTRY(fontsel->font_entry), font->family);
1051   
1052   /* If it is already the current font, just return. */
1053   if (fontsel->font_index == row)
1054     return;
1055   
1056   fontsel->font_index = row;
1057   gtk_font_selection_show_available_styles (fontsel);
1058   gtk_font_selection_select_best_style (fontsel, TRUE);
1059 }
1060
1061
1062 static gint
1063 gtk_font_selection_on_clist_key_press (GtkWidget        *clist,
1064                                        GdkEventKey      *event,
1065                                        GtkFontSelection *fontsel)
1066 {
1067 #ifdef FONTSEL_DEBUG
1068   g_message("In on_clist_key_press\n");
1069 #endif
1070   if (event->keyval == GDK_Up)
1071     return gtk_font_selection_select_next (fontsel, clist, -1);
1072   else if (event->keyval == GDK_Down)
1073     return gtk_font_selection_select_next (fontsel, clist, 1);
1074   else
1075     return FALSE;
1076 }
1077
1078
1079 static gboolean
1080 gtk_font_selection_select_next (GtkFontSelection *fontsel,
1081                                 GtkWidget        *clist,
1082                                 gint              step)
1083 {
1084   GList *selection;
1085   gint current_row, row;
1086   
1087   selection = GTK_CLIST(clist)->selection;
1088   if (!selection)
1089     return FALSE;
1090   current_row = GPOINTER_TO_INT (selection->data);
1091   
1092   /* Stop the normal clist key handler from being run. */
1093   gtk_signal_emit_stop_by_name (GTK_OBJECT (clist), "key_press_event");
1094
1095   for (row = current_row + step;
1096        row >= 0 && row < GTK_CLIST(clist)->rows;
1097        row += step)
1098     {
1099       /* If this is the style clist, make sure that the item is not a charset
1100          entry. */
1101       if (clist == fontsel->font_style_clist)
1102         if (GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(clist), row)) == -1)
1103           continue;
1104       
1105       /* Now we've found the row to select. */
1106       if (gtk_clist_row_is_visible(GTK_CLIST(clist), row)
1107           != GTK_VISIBILITY_FULL)
1108         gtk_clist_moveto(GTK_CLIST(clist), row, -1, (step < 0) ? 0 : 1, 0);
1109       gtk_clist_select_row(GTK_CLIST(clist), row, 0);
1110       break;
1111     }
1112   return TRUE;
1113 }
1114
1115
1116 /* This fills the font style clist with all the possible style combinations
1117    for the current font family. */
1118 static void
1119 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
1120 {
1121   FontInfo *font;
1122   FontStyle *styles;
1123   gint style, tmpstyle, row;
1124   gint weight_index, slant_index, set_width_index, spacing_index;
1125   gint charset_index;
1126   gchar *weight, *slant, *set_width, *spacing;
1127   gchar *charset = NULL;
1128   gchar *new_item;
1129   gchar buffer[XLFD_MAX_FIELD_LEN * 6 + 2];
1130   GdkColor *inactive_fg, *inactive_bg;
1131   gboolean show_charset;
1132   
1133 #ifdef FONTSEL_DEBUG
1134   g_message("In show_available_styles\n");
1135 #endif
1136   font = &fontsel_info->font_info[fontsel->font_index];
1137   styles = &fontsel_info->font_styles[font->style_index];
1138   
1139   gtk_clist_freeze (GTK_CLIST(fontsel->font_style_clist));
1140   gtk_clist_clear (GTK_CLIST(fontsel->font_style_clist));
1141   
1142   /* First we mark all visible styles as not having been displayed yet,
1143      and check if every style has the same charset. If not then we will
1144      display the charset in the list before the styles. */
1145   show_charset = FALSE;
1146   charset_index = -1;
1147   for (style = 0; style < font->nstyles; style++)
1148     {
1149       if (gtk_font_selection_style_visible(fontsel, font, style))
1150         {
1151           styles[style].flags &= ~GTK_FONT_DISPLAYED;
1152           
1153           if (charset_index == -1)
1154             charset_index  = styles[style].properties[CHARSET];
1155           else if (charset_index != styles[style].properties[CHARSET])
1156             show_charset = TRUE;
1157         }
1158       else
1159         styles[style].flags |= GTK_FONT_DISPLAYED;
1160     }
1161   
1162   /* Step through the undisplayed styles, finding the next charset which
1163      hasn't been displayed yet. Then display the charset on one line, if
1164      necessary, and the visible styles indented beneath it. */
1165   inactive_fg = &fontsel->font_style_clist->style->fg[GTK_STATE_INSENSITIVE];
1166   inactive_bg = &fontsel->font_style_clist->style->bg[GTK_STATE_INSENSITIVE];
1167   
1168   for (style = 0; style < font->nstyles; style++)
1169     {
1170       if (styles[style].flags & GTK_FONT_DISPLAYED)
1171         continue;
1172       
1173       if (show_charset)
1174         {
1175           charset_index  = styles[style].properties[CHARSET];
1176           charset  = fontsel_info->properties[CHARSET] [charset_index];
1177           row = gtk_clist_append(GTK_CLIST(fontsel->font_style_clist),
1178                                  &charset);
1179           gtk_clist_set_row_data(GTK_CLIST(fontsel->font_style_clist), row,
1180                                  (gpointer) -1);
1181           if (GTK_WIDGET_REALIZED (fontsel->font_style_clist))
1182             {
1183               gtk_clist_set_foreground(GTK_CLIST(fontsel->font_style_clist),
1184                                        row, inactive_fg);
1185               gtk_clist_set_background(GTK_CLIST(fontsel->font_style_clist),
1186                                        row, inactive_bg);
1187             }
1188         }
1189       
1190       for (tmpstyle = style; tmpstyle < font->nstyles; tmpstyle++)
1191         {
1192           if (styles[tmpstyle].flags & GTK_FONT_DISPLAYED
1193               || charset_index != styles[tmpstyle].properties[CHARSET])
1194             continue;
1195           
1196           styles[tmpstyle].flags |= GTK_FONT_DISPLAYED;
1197           
1198           weight_index    = styles[tmpstyle].properties[WEIGHT];
1199           slant_index     = styles[tmpstyle].properties[SLANT];
1200           set_width_index = styles[tmpstyle].properties[SET_WIDTH];
1201           spacing_index   = styles[tmpstyle].properties[SPACING];
1202           weight    = fontsel_info->properties[WEIGHT]   [weight_index];
1203           slant     = fontsel_info->properties[SLANT]    [slant_index];
1204           set_width = fontsel_info->properties[SET_WIDTH][set_width_index];
1205           spacing   = fontsel_info->properties[SPACING]  [spacing_index];
1206           
1207           /* Convert '(nil)' weights to 'regular', since it looks nicer. */
1208           if      (!g_strcasecmp(weight, "(nil)"))      weight = _("regular");
1209           
1210           /* We don't show default values or (nil) in the other properties. */
1211           if      (!g_strcasecmp(slant, "r"))        slant = NULL;
1212           else if (!g_strcasecmp(slant, "(nil)"))    slant = NULL;
1213           else if (!g_strcasecmp(slant, "i"))        slant = _("italic");
1214           else if (!g_strcasecmp(slant, "o"))        slant = _("oblique");
1215           else if (!g_strcasecmp(slant, "ri"))       slant = _("reverse italic");
1216           else if (!g_strcasecmp(slant, "ro"))       slant = _("reverse oblique");
1217           else if (!g_strcasecmp(slant, "ot"))       slant = _("other");
1218           
1219           if      (!g_strcasecmp(set_width, "normal")) set_width = NULL;
1220           else if (!g_strcasecmp(set_width, "(nil)"))  set_width = NULL;
1221           
1222           if      (!g_strcasecmp(spacing, "p"))        spacing = NULL;
1223           else if (!g_strcasecmp(spacing, "(nil)"))    spacing = NULL;
1224           else if (!g_strcasecmp(spacing, "m"))        spacing = _("[M]");
1225           else if (!g_strcasecmp(spacing, "c"))        spacing = _("[C]");
1226           
1227           /* Add the strings together, making sure there is 1 space between
1228              them */
1229           strcpy(buffer, weight);
1230           if (slant)
1231             {
1232               strcat(buffer, " ");
1233               strcat(buffer, slant);
1234             }
1235           if (set_width)
1236             {
1237               strcat(buffer, " ");
1238               strcat(buffer, set_width);
1239             }
1240           if (spacing)
1241             {
1242               strcat(buffer, " ");
1243               strcat(buffer, spacing);
1244             }
1245           
1246           new_item = buffer;
1247           row = gtk_clist_append(GTK_CLIST(fontsel->font_style_clist),
1248                                  &new_item);
1249           if (show_charset)
1250             gtk_clist_set_shift(GTK_CLIST(fontsel->font_style_clist), row, 0,
1251                                 0, 4);
1252           gtk_clist_set_row_data(GTK_CLIST(fontsel->font_style_clist), row,
1253                                  GINT_TO_POINTER (tmpstyle));
1254         }
1255     }
1256   
1257   gtk_clist_thaw (GTK_CLIST(fontsel->font_style_clist));
1258 }
1259
1260
1261 /* This selects a style when the user selects a font. It just uses the first
1262    available style at present. I was thinking of trying to maintain the
1263    selected style, e.g. bold italic, when the user selects different fonts.
1264    However, the interface is so easy to use now I'm not sure it's worth it.
1265    Note: This will load a font. */
1266 static void
1267 gtk_font_selection_select_best_style(GtkFontSelection *fontsel,
1268                                      gboolean          use_first)
1269 {
1270   FontInfo *font;
1271   FontStyle *styles;
1272   gint row, prop, style, matched;
1273   gint best_matched = -1, best_style = -1, best_row = -1;
1274   
1275 #ifdef FONTSEL_DEBUG
1276   g_message("In select_best_style\n");
1277 #endif
1278   font = &fontsel_info->font_info[fontsel->font_index];
1279   styles = &fontsel_info->font_styles[font->style_index];
1280   
1281   for (row = 0; row < GTK_CLIST(fontsel->font_style_clist)->rows; row++)
1282     {
1283       style = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_style_clist), row));
1284       /* Skip charset rows. */
1285       if (style == -1)
1286         continue;
1287
1288       /* If we just want the first style, we've got it. */
1289       if (use_first)
1290         {
1291           best_style = style;
1292           best_row = row;
1293           break;
1294         }
1295
1296       matched = 0;
1297       for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1298         {
1299           if (fontsel->property_values[prop] == styles[style].properties[prop])
1300             matched++;
1301         }
1302       if (matched > best_matched)
1303         {
1304           best_matched = matched;
1305           best_style = style;
1306           best_row = row;
1307         }
1308     }
1309   g_return_if_fail (best_style != -1);
1310   g_return_if_fail (best_row != -1);
1311
1312   fontsel->style = best_style;
1313
1314   for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1315     fontsel->property_values[prop] = styles[fontsel->style].properties[prop];
1316
1317   gtk_clist_select_row(GTK_CLIST(fontsel->font_style_clist), best_row, 0);
1318   if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_style_clist), best_row)
1319       != GTK_VISIBILITY_FULL)
1320     gtk_clist_moveto(GTK_CLIST(fontsel->font_style_clist), best_row, -1,
1321                      0.5, 0);
1322   gtk_font_selection_show_available_sizes (fontsel);
1323   gtk_font_selection_select_best_size (fontsel);
1324 }
1325
1326
1327 /* This is called when a style is selected in the list. */
1328 static void
1329 gtk_font_selection_select_style (GtkWidget      *w,
1330                                  gint           row,
1331                                  gint           column,
1332                                  GdkEventButton *bevent,
1333                                  gpointer        data)
1334 {
1335   GtkFontSelection *fontsel;
1336   FontInfo *font_info;
1337   FontInfo *font;
1338   FontStyle *styles;
1339   gint style, prop;
1340   gchar *text;
1341   
1342 #ifdef FONTSEL_DEBUG
1343   g_message("In select_style\n");
1344 #endif
1345   fontsel = GTK_FONT_SELECTION(data);
1346   font_info = fontsel_info->font_info;
1347   font = &font_info[fontsel->font_index];
1348   styles = &fontsel_info->font_styles[font->style_index];
1349   
1350   if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1351     gtk_widget_grab_focus (w);
1352   
1353   /* The style index is stored in the row data, so we just need to copy
1354      the style values into the fontsel and reload the font. */
1355   style = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(fontsel->font_style_clist), row));
1356   
1357   /* Don't allow selection of charset rows. */
1358   if (style == -1)
1359     {
1360       gtk_clist_unselect_row(GTK_CLIST(fontsel->font_style_clist), row, 0);
1361       return;
1362     }
1363   
1364   gtk_clist_get_text(GTK_CLIST(fontsel->font_style_clist), row, 0, &text);
1365   gtk_entry_set_text(GTK_ENTRY(fontsel->font_style_entry), text);
1366   
1367   for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1368     fontsel->property_values[prop] = styles[style].properties[prop];
1369   
1370   if (fontsel->style == style)
1371     return;
1372   
1373   fontsel->style = style;
1374   gtk_font_selection_show_available_sizes (fontsel);
1375   gtk_font_selection_select_best_size (fontsel);
1376 }
1377
1378
1379 /* This shows all the available sizes in the size clist, according to the
1380    current metric and the current font & style. */
1381 static void
1382 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel)
1383 {
1384   FontInfo *font;
1385   FontStyle *styles, *style;
1386   const guint16 *standard_sizes;
1387   guint16 *bitmapped_sizes, bitmap_size;
1388   gint nstandard_sizes, nbitmapped_sizes;
1389   gchar buffer[16], *size;
1390   gfloat bitmap_size_float;
1391   gboolean can_match;
1392   gint type_filter;
1393   
1394 #ifdef FONTSEL_DEBUG
1395   g_message("In show_available_sizes\n");
1396 #endif
1397   font = &fontsel_info->font_info[fontsel->font_index];
1398   styles = &fontsel_info->font_styles[font->style_index];
1399   style = &styles[fontsel->style];
1400   
1401   standard_sizes = font_sizes;
1402   nstandard_sizes = sizeof(font_sizes) / sizeof(font_sizes[0]);
1403   if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1404     {
1405       bitmapped_sizes = &fontsel_info->point_sizes[style->point_sizes_index];
1406       nbitmapped_sizes = style->npoint_sizes;
1407     }
1408   else
1409     {
1410       bitmapped_sizes = &fontsel_info->pixel_sizes[style->pixel_sizes_index];
1411       nbitmapped_sizes = style->npixel_sizes;
1412     }
1413   
1414   /* Only show the standard sizes if a scalable font is available. */
1415   type_filter = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
1416     & fontsel->filters[GTK_FONT_FILTER_USER].font_type;
1417
1418   if (!((style->flags & GTK_FONT_SCALABLE_BITMAP
1419          && type_filter & GTK_FONT_SCALABLE_BITMAP)
1420         || (style->flags & GTK_FONT_SCALABLE
1421             && type_filter & GTK_FONT_SCALABLE)))
1422     nstandard_sizes = 0;
1423   
1424   gtk_clist_freeze (GTK_CLIST(fontsel->size_clist));
1425   gtk_clist_clear (GTK_CLIST(fontsel->size_clist));
1426   
1427   /* Interleave the standard sizes with the bitmapped sizes so we get a list
1428      of ascending sizes. If the metric is points, we have to convert the
1429      decipoints to points. */
1430   while (nstandard_sizes || nbitmapped_sizes)
1431     {
1432       can_match = TRUE;
1433       if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1434         {
1435           if (*bitmapped_sizes % 10 != 0)
1436             can_match = FALSE;
1437           bitmap_size = *bitmapped_sizes / 10;
1438           bitmap_size_float = *bitmapped_sizes / 10;
1439         }
1440       else
1441         {
1442           bitmap_size = *bitmapped_sizes;
1443           bitmap_size_float = *bitmapped_sizes;
1444         }
1445       
1446       if (can_match && nstandard_sizes && nbitmapped_sizes
1447           && *standard_sizes == bitmap_size)
1448         {
1449           sprintf(buffer, "%i *", *standard_sizes);
1450           standard_sizes++;
1451           nstandard_sizes--;
1452           bitmapped_sizes++;
1453           nbitmapped_sizes--;
1454         }
1455       else if (nstandard_sizes
1456                && (!nbitmapped_sizes
1457                    || (gfloat)*standard_sizes < bitmap_size_float))
1458         {
1459           sprintf(buffer, "%i", *standard_sizes);
1460           standard_sizes++;
1461           nstandard_sizes--;
1462         }
1463       else
1464         {
1465           if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1466             {
1467               if (*bitmapped_sizes % 10 == 0)
1468                 sprintf(buffer, "%i *", *bitmapped_sizes / 10);
1469               else
1470                 sprintf(buffer, "%i.%i *", *bitmapped_sizes / 10,
1471                         *bitmapped_sizes % 10);
1472             }
1473           else
1474             {
1475               sprintf(buffer, "%i *", *bitmapped_sizes);
1476             }
1477           bitmapped_sizes++;
1478           nbitmapped_sizes--;
1479         }
1480       size = buffer;
1481       gtk_clist_append(GTK_CLIST(fontsel->size_clist), &size);
1482     }
1483   gtk_clist_thaw (GTK_CLIST(fontsel->size_clist));
1484 }
1485
1486
1487 /* If the user hits return in the font size entry, we change to the new font
1488    size. */
1489 static gint
1490 gtk_font_selection_size_key_press (GtkWidget   *w,
1491                                    GdkEventKey *event,
1492                                    gpointer     data)
1493 {
1494   GtkFontSelection *fontsel;
1495   gint new_size;
1496   gfloat new_size_float;
1497   gchar *text;
1498   
1499 #ifdef FONTSEL_DEBUG
1500   g_message("In size_key_press\n");
1501 #endif
1502   fontsel = GTK_FONT_SELECTION(data);
1503   
1504   if (event->keyval == GDK_Return)
1505     {
1506       text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1507       if (fontsel->metric == GTK_FONT_METRIC_PIXELS)
1508         {
1509           new_size = atoi (text);
1510           if (new_size < 2)
1511             new_size = 2;
1512         }
1513       else
1514         {
1515           new_size_float = atof (text) * 10;
1516           new_size = (gint) new_size_float;
1517           if (new_size < 20)
1518             new_size = 20;
1519         }
1520       
1521       /* Remember that this size was set explicitly. */
1522       fontsel->selected_size = new_size;
1523       
1524       /* Check if the font size has changed, and return if it hasn't. */
1525       if (fontsel->size == new_size)
1526         return TRUE;
1527       
1528       fontsel->size = new_size;
1529       gtk_font_selection_select_best_size (fontsel);
1530       return TRUE;
1531     }
1532   
1533   return FALSE;
1534 }
1535
1536
1537 /* This tries to select the closest size to the current size, though it
1538    may have to change the size if only unscaled bitmaps are available.
1539    Note: this will load a font. */
1540 static void
1541 gtk_font_selection_select_best_size(GtkFontSelection *fontsel)
1542 {
1543   FontInfo *font;
1544   FontStyle *styles, *style;
1545   gchar *text;
1546   gint row, best_row = 0, size, size_fraction, best_size = 0, nmatched;
1547   gboolean found = FALSE;
1548   gchar buffer[32];
1549   GList *selection;
1550   gint type_filter;
1551   
1552 #ifdef FONTSEL_DEBUG
1553   g_message("In select_best_size\n");
1554 #endif
1555   font = &fontsel_info->font_info[fontsel->font_index];
1556   styles = &fontsel_info->font_styles[font->style_index];
1557   style = &styles[fontsel->style];
1558   
1559   /* Find the closest size available in the size clist. If the exact size is
1560      in the list set found to TRUE. */
1561   for (row = 0; row < GTK_CLIST(fontsel->size_clist)->rows; row++)
1562     {
1563       gtk_clist_get_text(GTK_CLIST(fontsel->size_clist), row, 0, &text);
1564       nmatched = sscanf(text, "%i.%i", &size, &size_fraction);
1565       if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1566         {
1567           size *= 10;
1568           if (nmatched == 2)
1569             size += size_fraction;
1570         }
1571       
1572       if (size == fontsel->selected_size)
1573         {
1574           found = TRUE;
1575           best_size = size;
1576           best_row = row;
1577           break;
1578         }
1579       else if (best_size == 0
1580                || abs(size - fontsel->selected_size)
1581                < (abs(best_size - fontsel->selected_size)))
1582         {
1583           best_size = size;
1584           best_row = row;
1585         }
1586     }
1587   
1588   /* If we aren't scaling bitmapped fonts and this is a bitmapped font, we
1589      need to use the closest size found. */
1590   type_filter = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
1591     & fontsel->filters[GTK_FONT_FILTER_USER].font_type;
1592
1593   if (!((style->flags & GTK_FONT_SCALABLE_BITMAP
1594          && type_filter & GTK_FONT_SCALABLE_BITMAP)
1595         || (style->flags & GTK_FONT_SCALABLE
1596             && type_filter & GTK_FONT_SCALABLE)))
1597     found = TRUE;
1598   
1599   if (found)
1600     {
1601       fontsel->size = best_size;
1602       gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), best_row, -1, 0.5, 0);
1603       gtk_clist_select_row(GTK_CLIST(fontsel->size_clist), best_row, 0);
1604     }
1605   else
1606     {
1607       fontsel->size = fontsel->selected_size;
1608       selection = GTK_CLIST(fontsel->size_clist)->selection;
1609       if (selection)
1610         gtk_clist_unselect_row(GTK_CLIST(fontsel->size_clist),
1611                                GPOINTER_TO_INT (selection->data), 0);
1612       gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), best_row, -1, 0.5, 0);
1613       
1614       /* Show the size in the size entry. */
1615       if (fontsel->metric == GTK_FONT_METRIC_PIXELS)
1616         sprintf(buffer, "%i", fontsel->size);
1617       else
1618         {
1619           if (fontsel->size % 10 == 0)
1620             sprintf(buffer, "%i", fontsel->size / 10);
1621           else
1622             sprintf(buffer, "%i.%i", fontsel->size / 10, fontsel->size % 10);
1623         }
1624       gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
1625     }
1626   gtk_font_selection_load_font (fontsel);
1627 }
1628
1629
1630 /* This is called when a size is selected in the list. */
1631 static void
1632 gtk_font_selection_select_size (GtkWidget      *w,
1633                                 gint            row,
1634                                 gint            column,
1635                                 GdkEventButton *bevent,
1636                                 gpointer        data)
1637 {
1638   GtkFontSelection *fontsel;
1639   gint new_size;
1640   gchar *text;
1641   gchar buffer[16];
1642   gint i;
1643   
1644 #ifdef FONTSEL_DEBUG
1645   g_message("In select_size\n");
1646 #endif
1647   fontsel = GTK_FONT_SELECTION(data);
1648   
1649   if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1650     gtk_widget_grab_focus (w);
1651   
1652   /* Copy the size from the clist to the size entry, but without the bitmapped
1653      marker ('*'). */
1654   gtk_clist_get_text(GTK_CLIST(fontsel->size_clist), row, 0, &text);
1655   i = 0;
1656   while (i < 15 && (text[i] == '.' || (text[i] >= '0' && text[i] <= '9')))
1657     {
1658       buffer[i] = text[i];
1659       i++;
1660     }
1661   buffer[i] = '\0';
1662   gtk_entry_set_text(GTK_ENTRY(fontsel->size_entry), buffer);
1663   
1664   /* Check if the font size has changed, and return if it hasn't. */
1665   new_size = atoi(text);
1666   if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1667     new_size *= 10;
1668   
1669   if (fontsel->size == new_size)
1670     return;
1671   
1672   /* If the size was selected by the user we set the selected_size. */
1673   fontsel->selected_size = new_size;
1674   
1675   fontsel->size = new_size;
1676   gtk_font_selection_load_font (fontsel);
1677 }
1678
1679
1680 /* This is called when the pixels or points radio buttons are pressed. */
1681 static void
1682 gtk_font_selection_metric_callback (GtkWidget *w,
1683                                     gpointer   data)
1684 {
1685   GtkFontSelection *fontsel = GTK_FONT_SELECTION(data);
1686   
1687 #ifdef FONTSEL_DEBUG
1688   g_message("In metric_callback\n");
1689 #endif
1690   if (GTK_TOGGLE_BUTTON(fontsel->pixels_button)->active)
1691     {
1692       if (fontsel->metric == GTK_FONT_METRIC_PIXELS)
1693         return;
1694       fontsel->metric = GTK_FONT_METRIC_PIXELS;
1695       fontsel->size = (fontsel->size + 5) / 10;
1696       fontsel->selected_size = (fontsel->selected_size + 5) / 10;
1697     }
1698   else
1699     {
1700       if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1701         return;
1702       fontsel->metric = GTK_FONT_METRIC_POINTS;
1703       fontsel->size *= 10;
1704       fontsel->selected_size *= 10;
1705     }
1706   if (fontsel->font_index != -1)
1707     {
1708       gtk_font_selection_show_available_sizes (fontsel);
1709       gtk_font_selection_select_best_size (fontsel);
1710     }
1711 }
1712
1713
1714 /* This searches the given property table and returns the index of the given
1715    string, or 0, which is the wildcard '*' index, if it's not found. */
1716 static guint16
1717 gtk_font_selection_field_to_index (gchar **table,
1718                                    gint    ntable,
1719                                    gchar  *field)
1720 {
1721   gint i;
1722   
1723   for (i = 0; i < ntable; i++)
1724     if (strcmp (field, table[i]) == 0)
1725       return i;
1726   
1727   return 0;
1728 }
1729
1730
1731
1732 /* This attempts to load the current font, and returns TRUE if it succeeds. */
1733 static gboolean
1734 gtk_font_selection_load_font (GtkFontSelection *fontsel)
1735 {
1736   GdkFont *font;
1737   gchar *fontname, *label_text;
1738   
1739   if (fontsel->font)
1740     gdk_font_unref (fontsel->font);
1741   fontsel->font = NULL;
1742   
1743   /* If no family has been selected yet, just return FALSE. */
1744   if (fontsel->font_index == -1)
1745     return FALSE;
1746   
1747   fontname = gtk_font_selection_get_font_name (fontsel);
1748   if (fontname)
1749     {
1750 #ifdef FONTSEL_DEBUG
1751       g_message("Loading: %s\n", fontname);
1752 #endif
1753       font = gdk_font_load (fontname);
1754       g_free(fontname);
1755       
1756       if (font)
1757         {
1758           fontsel->font = font;
1759           /* Make sure the message label is empty, but don't change it unless
1760              it's necessary as it results in a resize of the whole window! */
1761           gtk_label_get(GTK_LABEL(fontsel->message_label), &label_text);
1762           if (strcmp(label_text, ""))
1763             gtk_label_set_text(GTK_LABEL(fontsel->message_label), "");
1764           gtk_font_selection_update_preview (fontsel);
1765           return TRUE;
1766         }
1767       else 
1768         {
1769           gtk_label_set_text(GTK_LABEL(fontsel->message_label),
1770                              _("The selected font is not available."));
1771         }
1772     }
1773   else
1774     {
1775       gtk_label_set_text(GTK_LABEL(fontsel->message_label),
1776                          _("The selected font is not a valid font."));
1777     }
1778   
1779   return FALSE;
1780 }
1781
1782
1783 /* This sets the font in the preview entry to the selected font, and tries to
1784    make sure that the preview entry is a reasonable size, i.e. so that the
1785    text can be seen with a bit of space to spare. But it tries to avoid
1786    resizing the entry every time the font changes.
1787    This also used to shrink the preview if the font size was decreased, but
1788    that made it awkward if the user wanted to resize the window themself. */
1789 static void
1790 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1791 {
1792   GtkWidget *preview_entry;
1793   GtkStyle *style;
1794   gint text_height, new_height;
1795   gchar *text;
1796   XFontStruct *xfs;
1797   
1798 #ifdef FONTSEL_DEBUG
1799   g_message("In update_preview\n");
1800 #endif
1801   style = gtk_style_new ();
1802   gdk_font_unref (style->font);
1803   style->font = fontsel->font;
1804   gdk_font_ref (style->font);
1805   
1806   preview_entry = fontsel->preview_entry;
1807   gtk_widget_set_style (preview_entry, style);
1808   gtk_style_unref(style);
1809   
1810   text_height = preview_entry->style->font->ascent
1811     + preview_entry->style->font->descent;
1812   /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1813   new_height = text_height + 20;
1814   if (new_height < INITIAL_PREVIEW_HEIGHT)
1815     new_height = INITIAL_PREVIEW_HEIGHT;
1816   if (new_height > MAX_PREVIEW_HEIGHT)
1817     new_height = MAX_PREVIEW_HEIGHT;
1818   
1819   if ((preview_entry->requisition.height < text_height + 10)
1820       || (preview_entry->requisition.height > text_height + 40))
1821     gtk_widget_set_usize(preview_entry, -1, new_height);
1822   
1823   /* This sets the preview text, if it hasn't been set already. */
1824   text = gtk_entry_get_text(GTK_ENTRY(fontsel->preview_entry));
1825   if (strlen(text) == 0)
1826     gtk_entry_set_text(GTK_ENTRY(fontsel->preview_entry), PREVIEW_TEXT);
1827   gtk_entry_set_position(GTK_ENTRY(fontsel->preview_entry), 0);
1828   
1829   /* If this is a 2-byte font display a message to say it may not be
1830      displayed properly. */
1831   xfs = GDK_FONT_XFONT(fontsel->font);
1832   if (xfs->min_byte1 != 0 || xfs->max_byte1 != 0)
1833     gtk_label_set_text(GTK_LABEL(fontsel->message_label),
1834                        _("This is a 2-byte font and may not be displayed correctly."));
1835 }
1836
1837
1838 static void
1839 gtk_font_selection_switch_page (GtkWidget       *w,
1840                                 GtkNotebookPage *page,
1841                                 gint             page_num,
1842                                 gpointer         data)
1843 {
1844   GtkFontSelection *fontsel = GTK_FONT_SELECTION(data);
1845   
1846   /* This function strangely gets called when the window is destroyed,
1847      so we check here to see if the notebook is visible. */
1848   if (!GTK_WIDGET_VISIBLE(w))
1849     return;
1850   
1851   if (page_num == 0)
1852     gtk_font_selection_update_filter(fontsel);
1853   else if (page_num == 1)
1854     gtk_font_selection_show_font_info(fontsel);
1855 }
1856
1857
1858 static void
1859 gtk_font_selection_show_font_info (GtkFontSelection *fontsel)
1860 {
1861   Atom font_atom, atom;
1862   Bool status;
1863   char *name;
1864   gchar *fontname;
1865   gchar field_buffer[XLFD_MAX_FIELD_LEN];
1866   gchar *field;
1867   gint i;
1868   gboolean shown_actual_fields = FALSE;
1869   
1870   fontname = gtk_font_selection_get_font_name(fontsel);
1871   gtk_entry_set_text(GTK_ENTRY(fontsel->requested_font_name),
1872                      fontname ? fontname : "");
1873   
1874   gtk_clist_freeze (GTK_CLIST(fontsel->info_clist));
1875   for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1876     {
1877       if (fontname)
1878         field = gtk_font_selection_get_xlfd_field (fontname, i, field_buffer);
1879       else
1880         field = NULL;
1881       if (field)
1882         {
1883           if (i == XLFD_SLANT)
1884             field = gtk_font_selection_expand_slant_code(field);
1885           else if (i == XLFD_SPACING)
1886             field = gtk_font_selection_expand_spacing_code(field);
1887         }
1888       gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 1,
1889                          field ? field : "");
1890     }
1891   
1892   if (fontsel->font)
1893     {
1894       font_atom = XInternAtom(GDK_DISPLAY(), "FONT", True);
1895       if (font_atom != None)
1896         {
1897           status = XGetFontProperty(GDK_FONT_XFONT(fontsel->font), font_atom,
1898                                     &atom);
1899           if (status == True)
1900             {
1901               name = XGetAtomName(GDK_DISPLAY(), atom);
1902               gtk_entry_set_text(GTK_ENTRY(fontsel->actual_font_name), name);
1903               
1904               for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1905                 {
1906                   field = gtk_font_selection_get_xlfd_field (name, i,
1907                                                              field_buffer);
1908                   if (i == XLFD_SLANT)
1909                     field = gtk_font_selection_expand_slant_code(field);
1910                   else if (i == XLFD_SPACING)
1911                     field = gtk_font_selection_expand_spacing_code(field);
1912                   gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 2,
1913                                      field ? field : "");
1914                 }
1915               shown_actual_fields = TRUE;
1916               XFree(name);
1917             }
1918         }
1919     }
1920   if (!shown_actual_fields)
1921     {
1922       gtk_entry_set_text(GTK_ENTRY(fontsel->actual_font_name), "");
1923       for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1924         {
1925           gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 2,
1926                              fontname ? _("(unknown)") : "");
1927         }
1928     }
1929   gtk_clist_thaw (GTK_CLIST(fontsel->info_clist));
1930   g_free(fontname);
1931 }
1932
1933
1934 static gchar*
1935 gtk_font_selection_expand_slant_code(gchar *slant)
1936 {
1937   if      (!g_strcasecmp(slant, "r"))   return(_("roman"));
1938   else if (!g_strcasecmp(slant, "i"))   return(_("italic"));
1939   else if (!g_strcasecmp(slant, "o"))   return(_("oblique"));
1940   else if (!g_strcasecmp(slant, "ri"))  return(_("reverse italic"));
1941   else if (!g_strcasecmp(slant, "ro"))  return(_("reverse oblique"));
1942   else if (!g_strcasecmp(slant, "ot"))  return(_("other"));
1943   return slant;
1944 }
1945
1946 static gchar*
1947 gtk_font_selection_expand_spacing_code(gchar *spacing)
1948 {
1949   if      (!g_strcasecmp(spacing, "p")) return(_("proportional"));
1950   else if (!g_strcasecmp(spacing, "m")) return(_("monospaced"));
1951   else if (!g_strcasecmp(spacing, "c")) return(_("char cell"));
1952   return spacing;
1953 }
1954
1955
1956 /*****************************************************************************
1957  * These functions all deal with the Filter page and filtering the fonts.
1958  *****************************************************************************/
1959
1960 /* This is called when an item is selected in one of the filter clists.
1961    We make sure that the first row of the clist, i.e. the wildcard '*', is
1962    selected if and only if none of the other items are selected.
1963    Also doesn't allow selections of values filtered out by base filter.
1964    We may need to be careful about triggering other signals. */
1965 static void
1966 gtk_font_selection_select_filter             (GtkWidget      *w,
1967                                               gint            row,
1968                                               gint            column,
1969                                               GdkEventButton *bevent,
1970                                               GtkFontSelection *fontsel)
1971 {
1972   gint i, prop, index;
1973   
1974   if (row == 0)
1975     {
1976       for (i = 1; i < GTK_CLIST(w)->rows; i++)
1977         gtk_clist_unselect_row(GTK_CLIST(w), i, 0);
1978     }
1979   else
1980     {
1981       /* Find out which property this is. */
1982       for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
1983         if (fontsel->filter_clists[prop] == w)
1984           break;
1985       index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(w), row));
1986       if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_BASE,
1987                                            prop, index) == NOT_FILTERED)
1988         gtk_clist_unselect_row(GTK_CLIST(w), row, 0);
1989       else
1990         gtk_clist_unselect_row(GTK_CLIST(w), 0, 0);
1991     }
1992 }
1993
1994
1995 /* Here a filter item is being deselected. If there are now no items selected
1996    we select the first '*' item, unless that it is the item being deselected,
1997    in which case we select all of the other items. This makes it easy to
1998    select all items in the list except one or two. */
1999 static void
2000 gtk_font_selection_unselect_filter           (GtkWidget      *w,
2001                                               gint            row,
2002                                               gint            column,
2003                                               GdkEventButton *bevent,
2004                                               GtkFontSelection *fontsel)
2005 {
2006   gint i, prop, index;
2007
2008   if (!GTK_CLIST(w)->selection)
2009     {
2010       if (row == 0)
2011         {
2012           /* Find out which property this is. */
2013           for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2014             if (fontsel->filter_clists[prop] == w)
2015               break;
2016
2017           for (i = 1; i < GTK_CLIST(w)->rows; i++)
2018             {
2019               index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(w),
2020                                                               i));
2021               if (gtk_font_selection_filter_state (fontsel,
2022                                                    GTK_FONT_FILTER_BASE,
2023                                                    prop, index)
2024                   != NOT_FILTERED)
2025                 gtk_clist_select_row(GTK_CLIST(w), i, 0);
2026             }
2027         }
2028       else
2029         {
2030           gtk_clist_select_row(GTK_CLIST(w), 0, 0);
2031         }
2032     }
2033 }
2034
2035
2036 /* This is called when the main notebook page is selected. It checks if the
2037    filter has changed, an if so it creates the filter settings, and filters the
2038    fonts shown. If an empty filter (all '*'s) is applied, then filtering is
2039    turned off. */
2040 static void
2041 gtk_font_selection_update_filter     (GtkFontSelection *fontsel)
2042 {
2043   GtkWidget *clist;
2044   GList *selection;
2045   gboolean default_filter = TRUE, filter_changed = FALSE;
2046   gint prop, nselected, i, row, index;
2047   GtkFontFilter *filter = &fontsel->filters[GTK_FONT_FILTER_USER];
2048   gint base_font_type, user_font_type, new_font_type;
2049   
2050 #ifdef FONTSEL_DEBUG
2051   g_message("In update_filter\n");
2052 #endif
2053   
2054   /* Check if the user filter has changed, and also if it is the default
2055      filter, i.e. bitmap & scalable fonts and all '*'s selected.
2056      We only look at the bits which are not already filtered out by the base
2057      filter, since that overrides the user filter. */
2058   base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
2059     & GTK_FONT_ALL;
2060   user_font_type = fontsel->filters[GTK_FONT_FILTER_USER].font_type
2061     & GTK_FONT_ALL;
2062   new_font_type = GTK_TOGGLE_BUTTON(fontsel->type_bitmaps_button)->active
2063     ? GTK_FONT_BITMAP : 0;
2064   new_font_type |= (GTK_TOGGLE_BUTTON(fontsel->type_scalable_button)->active
2065     ? GTK_FONT_SCALABLE : 0);
2066   new_font_type |= (GTK_TOGGLE_BUTTON(fontsel->type_scaled_bitmaps_button)->active ? GTK_FONT_SCALABLE_BITMAP : 0);
2067   new_font_type &= base_font_type;
2068   new_font_type |= (~base_font_type & user_font_type);
2069   if (new_font_type != (GTK_FONT_BITMAP | GTK_FONT_SCALABLE))
2070     default_filter = FALSE;
2071
2072   if (new_font_type != user_font_type)
2073     filter_changed = TRUE;
2074   fontsel->filters[GTK_FONT_FILTER_USER].font_type = new_font_type;
2075
2076   for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2077     {
2078       clist = fontsel->filter_clists[prop];
2079       selection = GTK_CLIST(clist)->selection;
2080       nselected = g_list_length(selection);
2081       if (nselected != 1 || GPOINTER_TO_INT (selection->data) != 0)
2082         {
2083           default_filter = FALSE;
2084           
2085           if (filter->property_nfilters[prop] != nselected)
2086             filter_changed = TRUE;
2087           else
2088             {
2089               for (i = 0; i < nselected; i++)
2090                 {
2091                   row = GPOINTER_TO_INT (selection->data);
2092                   index = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (clist), row));
2093                   if (filter->property_filters[prop][i] != index)
2094                     filter_changed = TRUE;
2095                   selection = selection->next;
2096                 }
2097             }
2098         }
2099       else
2100         {
2101           if (filter->property_nfilters[prop] != 0)
2102             filter_changed = TRUE;
2103         }
2104     }
2105   
2106   /* If the filter hasn't changed we just return. */
2107   if (!filter_changed)
2108     return;
2109   
2110 #ifdef FONTSEL_DEBUG
2111   g_message("   update_fonts: filter has changed\n");
2112 #endif
2113   
2114   /* Free the old filter data and create the new arrays. */
2115   for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2116     {
2117       g_free(filter->property_filters[prop]);
2118
2119       clist = fontsel->filter_clists[prop];
2120       selection = GTK_CLIST(clist)->selection;
2121       nselected = g_list_length(selection);
2122       if (nselected == 1 && GPOINTER_TO_INT (selection->data) == 0)
2123         {
2124           filter->property_filters[prop] = NULL;
2125           filter->property_nfilters[prop] = 0;
2126         }
2127       else
2128         {
2129           filter->property_filters[prop] = g_new(guint16, nselected);
2130           filter->property_nfilters[prop] = nselected;
2131           for (i = 0; i < nselected; i++)
2132             {
2133               row = GPOINTER_TO_INT (selection->data);
2134               index = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (clist), row));
2135               filter->property_filters[prop][i] = index;
2136               selection = selection->next;
2137             }
2138         }
2139     }
2140
2141   /* Set the 'Reset Filter' button sensitive if a filter is in effect, and
2142      also set the label above the font list to show this as well. */
2143   if (default_filter)
2144     {
2145       gtk_widget_set_sensitive(fontsel->filter_button, FALSE);
2146       gtk_label_set_text(GTK_LABEL(fontsel->font_label), _("Font:"));
2147     }
2148   else
2149     {
2150       gtk_widget_set_sensitive(fontsel->filter_button, TRUE);
2151       gtk_label_set_text(GTK_LABEL(fontsel->font_label), _("Font: (Filter Applied)"));
2152     }
2153   gtk_font_selection_show_available_fonts(fontsel);
2154 }  
2155
2156
2157 /* This shows all the available fonts in the font clist. */
2158 static void
2159 gtk_font_selection_show_available_fonts     (GtkFontSelection *fontsel)
2160 {
2161   FontInfo *font_info, *font;
2162   GtkFontFilter *filter;
2163   gint nfonts, i, j, k, row, style, font_row = -1;
2164   gchar font_buffer[XLFD_MAX_FIELD_LEN * 2 + 4];
2165   gchar *font_item;
2166   gboolean matched, matched_style;
2167   
2168 #ifdef FONTSEL_DEBUG
2169   g_message("In show_available_fonts\n");
2170 #endif
2171   font_info = fontsel_info->font_info;
2172   nfonts = fontsel_info->nfonts;
2173   
2174   /* Filter the list of fonts. */
2175   gtk_clist_freeze (GTK_CLIST(fontsel->font_clist));
2176   gtk_clist_clear (GTK_CLIST(fontsel->font_clist));
2177   for (i = 0; i < nfonts; i++)
2178     {
2179       font = &font_info[i];
2180       
2181       /* Check if the foundry passes through all filters. */
2182       matched = TRUE;
2183       for (k = 0; k < GTK_NUM_FONT_FILTERS; k++)
2184         {
2185           filter = &fontsel->filters[k];
2186
2187           if (filter->property_nfilters[FOUNDRY] != 0)
2188             {
2189               matched = FALSE;
2190               for (j = 0; j < filter->property_nfilters[FOUNDRY]; j++)
2191                 {
2192                   if (font->foundry == filter->property_filters[FOUNDRY][j])
2193                     {
2194                       matched = TRUE;
2195                       break;
2196                     }
2197                 }
2198               if (!matched)
2199                 break;
2200             }
2201         }
2202       
2203       if (!matched)
2204         continue;
2205
2206
2207       /* Now check if the other properties are matched in at least one style.*/
2208       matched_style = FALSE;
2209       for (style = 0; style < font->nstyles; style++)
2210         {
2211           if (gtk_font_selection_style_visible(fontsel, font, style))
2212             {
2213               matched_style = TRUE;
2214               break;
2215             }
2216         }
2217       if (!matched_style)
2218         continue;
2219       
2220       /* Insert the font in the clist. */
2221       if ((i > 0 && font->family == font_info[i-1].family)
2222           || (i < nfonts - 1 && font->family == font_info[i+1].family))
2223         {
2224           sprintf(font_buffer, "%s (%s)", font->family,
2225                   fontsel_info->properties[FOUNDRY][font->foundry]);
2226           font_item = font_buffer;
2227           row = gtk_clist_append(GTK_CLIST(fontsel->font_clist), &font_item);
2228         }
2229       else
2230         {
2231           row = gtk_clist_append(GTK_CLIST(fontsel->font_clist),
2232                                  &font->family);
2233         }
2234       gtk_clist_set_row_data(GTK_CLIST(fontsel->font_clist), row,
2235                              GINT_TO_POINTER (i));
2236       if (fontsel->font_index == i)
2237         font_row = row;
2238     }
2239   gtk_clist_thaw (GTK_CLIST(fontsel->font_clist));
2240   
2241   /* If the currently-selected font isn't in the new list, reset the
2242      selection. */
2243   if (font_row == -1)
2244     {
2245       fontsel->font_index = -1;
2246       if (fontsel->font)
2247         gdk_font_unref(fontsel->font);
2248       fontsel->font = NULL;
2249       gtk_entry_set_text(GTK_ENTRY(fontsel->font_entry), "");
2250       gtk_clist_clear (GTK_CLIST(fontsel->font_style_clist));
2251       gtk_entry_set_text(GTK_ENTRY(fontsel->font_style_entry), "");
2252       return;
2253     }
2254
2255   gtk_clist_select_row(GTK_CLIST(fontsel->font_clist), font_row, 0);
2256   if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_clist), font_row)
2257       != GTK_VISIBILITY_FULL)
2258     gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), font_row, -1, 0.5, 0);
2259
2260   gtk_font_selection_show_available_styles (fontsel);
2261   gtk_font_selection_select_best_style (fontsel, FALSE);
2262 }
2263
2264
2265 /* Returns TRUE if the style is not currently filtered out. */
2266 static gboolean
2267 gtk_font_selection_style_visible(GtkFontSelection *fontsel,
2268                                  FontInfo         *font,
2269                                  gint              style_index)
2270 {
2271   FontStyle *styles, *style;
2272   GtkFontFilter *filter;
2273   guint16 value;
2274   gint prop, i, j;
2275   gboolean matched;
2276   gint type_filter;
2277
2278   styles = &fontsel_info->font_styles[font->style_index];
2279   style = &styles[style_index];
2280
2281   /* Check if font_type of style is filtered. */
2282   type_filter = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
2283     & fontsel->filters[GTK_FONT_FILTER_USER].font_type;
2284   if (!(style->flags & type_filter))
2285     return FALSE;
2286   
2287   for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2288     {
2289       value = style->properties[prop];
2290       
2291       /* Check each filter. */
2292       for (i = 0; i < GTK_NUM_FONT_FILTERS; i++)
2293         {
2294           filter = &fontsel->filters[i];
2295
2296           if (filter->property_nfilters[prop] != 0)
2297             {
2298               matched = FALSE;
2299               for (j = 0; j < filter->property_nfilters[prop]; j++)
2300                 {
2301                   if (value == filter->property_filters[prop][j])
2302                     {
2303                       matched = TRUE;
2304                       break;
2305                     }
2306                 }
2307               if (!matched)
2308                 return FALSE;
2309             }
2310         }
2311     }
2312   return TRUE;
2313 }
2314
2315
2316 /* This resets the font type to bitmap or scalable, and sets all the filter
2317    clists to the wildcard '*' options. */
2318 static void
2319 gtk_font_selection_reset_filter      (GtkWidget      *w,
2320                                       GtkFontSelection *fontsel)
2321 {
2322   gint prop, base_font_type;
2323   
2324   fontsel->filters[GTK_FONT_FILTER_USER].font_type = GTK_FONT_BITMAP
2325     | GTK_FONT_SCALABLE;
2326
2327   base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type;
2328   if (base_font_type & GTK_FONT_BITMAP)
2329     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), TRUE);
2330   if (base_font_type & GTK_FONT_SCALABLE)
2331     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), TRUE);
2332   if (base_font_type & GTK_FONT_SCALABLE_BITMAP)
2333     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), FALSE);
2334   
2335   for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2336     gtk_clist_select_row(GTK_CLIST(fontsel->filter_clists[prop]), 0, 0);
2337 }
2338
2339
2340 /* This clears the filter, showing all fonts and styles again. */
2341 static void
2342 gtk_font_selection_on_clear_filter     (GtkWidget      *w,
2343                                         GtkFontSelection *fontsel)
2344 {
2345   gtk_font_selection_clear_filter(fontsel);
2346 }
2347
2348
2349 /* This resets the user filter, showing all fonts and styles which pass the
2350    base filter again. Note that the font type is set to bitmaps and scalable
2351    fonts - scaled bitmaps are not shown. */
2352 static void
2353 gtk_font_selection_clear_filter     (GtkFontSelection *fontsel)
2354 {
2355   GtkFontFilter *filter;
2356   gint prop;
2357   
2358 #ifdef FONTSEL_DEBUG
2359   g_message("In clear_filter\n");
2360 #endif
2361   /* Clear the filter data. */
2362   filter = &fontsel->filters[GTK_FONT_FILTER_USER];
2363   filter->font_type = GTK_FONT_BITMAP | GTK_FONT_SCALABLE;
2364   for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2365     {
2366       g_free(filter->property_filters[prop]);
2367       filter->property_filters[prop] = NULL;
2368       filter->property_nfilters[prop] = 0;
2369     }
2370   
2371   /* Select all the '*'s on the filter page. */
2372   gtk_font_selection_reset_filter(NULL, fontsel);
2373   
2374   /* Update the main notebook page. */
2375   gtk_widget_set_sensitive(fontsel->filter_button, FALSE);
2376   gtk_label_set_text(GTK_LABEL(fontsel->font_label), _("Font:"));
2377   
2378   gtk_font_selection_show_available_fonts(fontsel);
2379 }
2380   
2381   
2382 void
2383 gtk_font_selection_set_filter   (GtkFontSelection *fontsel,
2384                                  GtkFontFilterType filter_type,
2385                                  GtkFontType       font_type,
2386                                  gchar           **foundries,
2387                                  gchar           **weights,
2388                                  gchar           **slants,
2389                                  gchar           **setwidths,
2390                                  gchar           **spacings,
2391                                  gchar           **charsets)
2392 {
2393   GtkFontFilter *filter;
2394   gchar **filter_strings [GTK_NUM_FONT_PROPERTIES];
2395   gchar *filter_string;
2396   gchar *property, *property_alt;
2397   gint prop, nfilters, i, j, num_found;
2398   gint base_font_type, user_font_type;
2399   gboolean filter_set;
2400
2401   /* Put them into an array so we can use a simple loop. */
2402   filter_strings[FOUNDRY]   = foundries;
2403   filter_strings[WEIGHT]    = weights;
2404   filter_strings[SLANT]     = slants;
2405   filter_strings[SET_WIDTH] = setwidths;
2406   filter_strings[SPACING]   = spacings;
2407   filter_strings[CHARSET]   = charsets;
2408
2409   filter = &fontsel->filters[filter_type];
2410   filter->font_type = font_type;
2411       
2412   /* Free the old filter data, and insert the new. */
2413   for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2414     {
2415       g_free(filter->property_filters[prop]);
2416       filter->property_filters[prop] = NULL;
2417       filter->property_nfilters[prop] = 0;
2418       
2419       if (filter_strings[prop])
2420         {
2421           /* Count how many items in the new array. */
2422           nfilters = 0;
2423           while (filter_strings[prop][nfilters])
2424             nfilters++;
2425
2426           filter->property_filters[prop] = g_new(guint16, nfilters);
2427           filter->property_nfilters[prop] = 0;
2428
2429           /* Now convert the strings to property indices. */
2430           num_found = 0;
2431           for (i = 0; i < nfilters; i++)
2432             {
2433               filter_string = filter_strings[prop][i];
2434               for (j = 0; j < fontsel_info->nproperties[prop]; j++)
2435                 {
2436                   property = fontsel_info->properties[prop][j];
2437                   property_alt = NULL;
2438                   if (prop == SLANT)
2439                     property_alt = gtk_font_selection_expand_slant_code(property);
2440                   else if (prop == SPACING)
2441                     property_alt = gtk_font_selection_expand_spacing_code(property);
2442                   if (!strcmp (filter_string, property)
2443                       || (property_alt && !strcmp (filter_string, property_alt)))
2444                     {
2445                       filter->property_filters[prop][num_found] = j;
2446                       num_found++;
2447                       break;
2448                     }
2449                 }
2450             }
2451           filter->property_nfilters[prop] = num_found;
2452         }
2453     }
2454
2455   /* Now set the clists on the filter page according to the new filter. */
2456   gtk_font_selection_update_filter_lists (fontsel);
2457
2458   if (filter_type == GTK_FONT_FILTER_BASE)
2459     {
2460       user_font_type = fontsel->filters[GTK_FONT_FILTER_USER].font_type;
2461       if (font_type & GTK_FONT_BITMAP)
2462         {
2463           gtk_widget_set_sensitive (fontsel->type_bitmaps_button, TRUE);
2464           gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), user_font_type & GTK_FONT_BITMAP);
2465         }
2466       else
2467         {
2468           gtk_widget_set_sensitive (fontsel->type_bitmaps_button, FALSE);
2469           gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), FALSE);
2470         }
2471       
2472       if (font_type & GTK_FONT_SCALABLE)
2473         {
2474           gtk_widget_set_sensitive (fontsel->type_scalable_button, TRUE);
2475           gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), user_font_type & GTK_FONT_SCALABLE);
2476         }
2477       else
2478         {
2479           gtk_widget_set_sensitive (fontsel->type_scalable_button, FALSE);
2480           gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), FALSE);
2481         }
2482
2483       if (font_type & GTK_FONT_SCALABLE_BITMAP)
2484         {
2485           gtk_widget_set_sensitive (fontsel->type_scaled_bitmaps_button, TRUE);
2486           gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), user_font_type & GTK_FONT_SCALABLE_BITMAP);
2487         }
2488       else
2489         {
2490           gtk_widget_set_sensitive (fontsel->type_scaled_bitmaps_button, FALSE);
2491           gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), FALSE);
2492         }
2493     }
2494   else
2495     {
2496       base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type;
2497       if (base_font_type & GTK_FONT_BITMAP)
2498         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), font_type & GTK_FONT_BITMAP);
2499
2500       if (base_font_type & GTK_FONT_SCALABLE)
2501         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), font_type & GTK_FONT_SCALABLE);
2502
2503       if (base_font_type & GTK_FONT_SCALABLE_BITMAP)
2504         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), font_type & GTK_FONT_SCALABLE_BITMAP);
2505
2506       /* If the user filter is not the default, make the 'Reset Filter' button
2507          sensitive. */
2508       filter_set = FALSE;
2509       if (font_type != (GTK_FONT_BITMAP | GTK_FONT_SCALABLE))
2510         filter_set = TRUE;
2511       for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2512         {
2513           if (filter->property_nfilters[prop] != 0)
2514             filter_set = TRUE;
2515         }
2516       if (filter_set)
2517         gtk_widget_set_sensitive (fontsel->filter_button, TRUE);
2518     }
2519
2520   gtk_font_selection_show_available_fonts (fontsel);
2521 }
2522
2523
2524 /* This sets the colour of each property in the filter clists according to
2525    the base filter. i.e. Filtered properties are shown as insensitive. */
2526 static void
2527 gtk_font_selection_update_filter_lists (GtkFontSelection *fontsel)
2528 {
2529   GtkWidget *clist;
2530   GdkColor *inactive_fg, *inactive_bg, *fg, *bg;
2531   gint prop, row, index;
2532
2533   /* We have to make sure the clist is realized to use the colours. */
2534   for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2535     {
2536       clist = fontsel->filter_clists[prop];
2537       gtk_widget_realize (clist);
2538       inactive_fg = &clist->style->fg[GTK_STATE_INSENSITIVE];
2539       inactive_bg = &clist->style->bg[GTK_STATE_INSENSITIVE];
2540       for (row = 1; row < GTK_CLIST(clist)->rows; row++)
2541         {
2542           index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(clist),
2543                                                            row));
2544           /* Set the colour according to the base filter. */
2545           if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_BASE,
2546                                                prop, index) == NOT_FILTERED)
2547             {
2548               fg = inactive_fg;
2549               bg = inactive_bg;
2550             }
2551           else
2552             {
2553               fg = NULL;
2554               bg = NULL;
2555             }
2556           gtk_clist_set_foreground(GTK_CLIST(clist), row, fg);
2557           gtk_clist_set_background(GTK_CLIST(clist), row, bg);
2558
2559           /* Set the selection state according to the user filter. */
2560           if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_USER,
2561                                                prop, index) == FILTERED
2562               && fg == NULL)
2563             gtk_clist_select_row (GTK_CLIST (clist), row, 0);
2564           else
2565             gtk_clist_unselect_row (GTK_CLIST (clist), row, 0);
2566         }
2567     }
2568 }
2569
2570
2571 /* Returns whether a property value is in the filter or not, or if the
2572    property has no filter set. */
2573 static GtkFontPropertyFilterState
2574 gtk_font_selection_filter_state (GtkFontSelection *fontsel,
2575                                  GtkFontFilterType filter_type,
2576                                  gint             property,
2577                                  gint             index)
2578 {
2579   GtkFontFilter *filter;
2580   gint i;
2581
2582   filter = &fontsel->filters[filter_type];
2583   if (filter->property_nfilters[property] == 0)
2584     return NOT_SET;
2585
2586   for (i = 0; i < filter->property_nfilters[property]; i++)
2587     {
2588       if (filter->property_filters[property][i] == index)
2589         return FILTERED;
2590     }
2591   return NOT_FILTERED;
2592 }
2593
2594
2595 /*****************************************************************************
2596  * These functions all deal with creating the main class arrays containing
2597  * the data about all available fonts.
2598  *****************************************************************************/
2599 static void
2600 gtk_font_selection_get_fonts (void)
2601 {
2602   gchar **xfontnames;
2603   GSList **fontnames;
2604   gchar *fontname;
2605   GSList * temp_list;
2606   gint num_fonts;
2607   gint i, prop, style, size;
2608   gint npixel_sizes = 0, npoint_sizes = 0;
2609   FontInfo *font;
2610   FontStyle *current_style, *prev_style, *tmp_style;
2611   gboolean matched_style, found_size;
2612   gint pixels, points, res_x, res_y;
2613   gchar field_buffer[XLFD_MAX_FIELD_LEN];
2614   gchar *field;
2615   guint8 flags;
2616   guint16 *pixel_sizes, *point_sizes, *tmp_sizes;
2617   
2618   fontsel_info = g_new (GtkFontSelInfo, 1);
2619   
2620   /* Get a maximum of MAX_FONTS fontnames from the X server.
2621      Use "-*" as the pattern rather than "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" since
2622      the latter may result in fonts being returned which don't actually exist.
2623      xlsfonts also uses "*" so I think it's OK. "-*" gets rid of aliases. */
2624   xfontnames = XListFonts (GDK_DISPLAY(), "-*", MAX_FONTS, &num_fonts);
2625   /* Output a warning if we actually get MAX_FONTS fonts. */
2626   if (num_fonts == MAX_FONTS)
2627     g_warning(_("MAX_FONTS exceeded. Some fonts may be missing."));
2628   
2629   /* The maximum size of all these tables is the number of font names
2630      returned. We realloc them later when we know exactly how many
2631      unique entries there are. */
2632   fontsel_info->font_info = g_new (FontInfo, num_fonts);
2633   fontsel_info->font_styles = g_new (FontStyle, num_fonts);
2634   fontsel_info->pixel_sizes = g_new (guint16, num_fonts);
2635   fontsel_info->point_sizes = g_new (guint16, num_fonts);
2636   
2637   fontnames = g_new (GSList*, num_fonts);
2638   
2639   /* Create the initial arrays for the property value strings, though they
2640      may be realloc'ed later. Put the wildcard '*' in the first elements. */
2641   for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2642     {
2643       fontsel_info->properties[prop] = g_new(gchar*, PROPERTY_ARRAY_INCREMENT);
2644       fontsel_info->space_allocated[prop] = PROPERTY_ARRAY_INCREMENT;
2645       fontsel_info->nproperties[prop] = 1;
2646       fontsel_info->properties[prop][0] = "*";
2647     }
2648   
2649   
2650   /* Insert the font families into the main table, sorted by family and
2651      foundry (fonts with different foundries are placed in seaparate FontInfos.
2652      All fontnames in each family + foundry are placed into the fontnames
2653      array of lists. */
2654   fontsel_info->nfonts = 0;
2655   for (i = 0; i < num_fonts; i++)
2656     {
2657 #ifdef FONTSEL_DEBUG
2658       g_message("%s\n", xfontnames[i]);
2659 #endif
2660       if (gtk_font_selection_is_xlfd_font_name (xfontnames[i]))
2661         gtk_font_selection_insert_font (fontnames, &fontsel_info->nfonts, xfontnames[i]);
2662       else
2663         {
2664 #ifdef FONTSEL_DEBUG
2665           g_warning("Skipping invalid font: %s", xfontnames[i]);
2666 #endif
2667         }
2668     }
2669   
2670   
2671   /* Since many font names will be in the same FontInfo not all of the
2672      allocated FontInfo table will be used, so we will now reallocate it
2673      with the real size. */
2674   fontsel_info->font_info = g_realloc(fontsel_info->font_info,
2675                                       sizeof(FontInfo) * fontsel_info->nfonts);
2676   
2677   
2678   /* Now we work out which choices of weight/slant etc. are valid for each
2679      font. */
2680   fontsel_info->nstyles = 0;
2681   current_style = fontsel_info->font_styles;
2682   for (i = 0; i < fontsel_info->nfonts; i++)
2683     {
2684       font = &fontsel_info->font_info[i];
2685       
2686       /* Use the next free position in the styles array. */
2687       font->style_index = fontsel_info->nstyles;
2688       
2689       /* Now step through each of the fontnames with this family, and create
2690          a style for each fontname. Each style contains the index into the
2691          weights/slants etc. arrays, and a number of pixel/point sizes. */
2692       style = 0;
2693       temp_list = fontnames[i];
2694       while (temp_list)
2695         {
2696           fontname = temp_list->data;
2697           temp_list = temp_list->next;
2698           
2699           for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2700             {
2701               current_style->properties[prop]
2702                 = gtk_font_selection_insert_field (fontname, prop);
2703             }
2704           current_style->pixel_sizes_index = npixel_sizes;
2705           current_style->npixel_sizes = 0;
2706           current_style->point_sizes_index = npoint_sizes;
2707           current_style->npoint_sizes = 0;
2708           current_style->flags = 0;
2709           
2710           
2711           field = gtk_font_selection_get_xlfd_field (fontname, XLFD_PIXELS,
2712                                                      field_buffer);
2713           pixels = atoi(field);
2714           
2715           field = gtk_font_selection_get_xlfd_field (fontname, XLFD_POINTS,
2716                                                      field_buffer);
2717           points = atoi(field);
2718           
2719           field = gtk_font_selection_get_xlfd_field (fontname,
2720                                                      XLFD_RESOLUTION_X,
2721                                                      field_buffer);
2722           res_x = atoi(field);
2723           
2724           field = gtk_font_selection_get_xlfd_field (fontname,
2725                                                      XLFD_RESOLUTION_Y,
2726                                                      field_buffer);
2727           res_y = atoi(field);
2728           
2729           if (pixels == 0 && points == 0)
2730             {
2731               if (res_x == 0 && res_y == 0)
2732                 flags = GTK_FONT_SCALABLE;
2733               else
2734                 flags = GTK_FONT_SCALABLE_BITMAP;
2735             }
2736           else
2737             flags = GTK_FONT_BITMAP;
2738           
2739           /* Now we check to make sure that the style is unique. If it isn't
2740              we forget it. */
2741           prev_style = fontsel_info->font_styles + font->style_index;
2742           matched_style = FALSE;
2743           while (prev_style < current_style)
2744             {
2745               matched_style = TRUE;
2746               for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2747                 {
2748                   if (prev_style->properties[prop]
2749                       != current_style->properties[prop])
2750                     {
2751                       matched_style = FALSE;
2752                       break;
2753                     }
2754                 }
2755               if (matched_style)
2756                 break;
2757               prev_style++;
2758             }
2759           
2760           /* If we matched an existing style, we need to add the pixels &
2761              point sizes to the style. If not, we insert the pixel & point
2762              sizes into our new style. Note that we don't add sizes for
2763              scalable fonts. */
2764           if (matched_style)
2765             {
2766               prev_style->flags |= flags;
2767               if (flags == GTK_FONT_BITMAP)
2768                 {
2769                   pixel_sizes = fontsel_info->pixel_sizes
2770                     + prev_style->pixel_sizes_index;
2771                   found_size = FALSE;
2772                   for (size = 0; size < prev_style->npixel_sizes; size++)
2773                     {
2774                       if (pixels == *pixel_sizes)
2775                         {
2776                           found_size = TRUE;
2777                           break;
2778                         }
2779                       else if (pixels < *pixel_sizes)
2780                         break;
2781                       pixel_sizes++;
2782                     }
2783                   /* We need to move all the following pixel sizes up, and also
2784                      update the indexes of any following styles. */
2785                   if (!found_size)
2786                     {
2787                       for (tmp_sizes = fontsel_info->pixel_sizes + npixel_sizes;
2788                            tmp_sizes > pixel_sizes; tmp_sizes--)
2789                         *tmp_sizes = *(tmp_sizes - 1);
2790                       
2791                       *pixel_sizes = pixels;
2792                       npixel_sizes++;
2793                       prev_style->npixel_sizes++;
2794                       
2795                       tmp_style = prev_style + 1;
2796                       while (tmp_style < current_style)
2797                         {
2798                           tmp_style->pixel_sizes_index++;
2799                           tmp_style++;
2800                         }
2801                     }
2802                   
2803                   point_sizes = fontsel_info->point_sizes
2804                     + prev_style->point_sizes_index;
2805                   found_size = FALSE;
2806                   for (size = 0; size < prev_style->npoint_sizes; size++)
2807                     {
2808                       if (points == *point_sizes)
2809                         {
2810                           found_size = TRUE;
2811                           break;
2812                         }
2813                       else if (points < *point_sizes)
2814                         break;
2815                       point_sizes++;
2816                     }
2817                   /* We need to move all the following point sizes up, and also
2818                      update the indexes of any following styles. */
2819                   if (!found_size)
2820                     {
2821                       for (tmp_sizes = fontsel_info->point_sizes + npoint_sizes;
2822                            tmp_sizes > point_sizes; tmp_sizes--)
2823                         *tmp_sizes = *(tmp_sizes - 1);
2824                       
2825                       *point_sizes = points;
2826                       npoint_sizes++;
2827                       prev_style->npoint_sizes++;
2828                       
2829                       tmp_style = prev_style + 1;
2830                       while (tmp_style < current_style)
2831                         {
2832                           tmp_style->point_sizes_index++;
2833                           tmp_style++;
2834                         }
2835                     }
2836                 }
2837             }
2838           else
2839             {
2840               current_style->flags = flags;
2841               if (flags == GTK_FONT_BITMAP)
2842                 {
2843                   fontsel_info->pixel_sizes[npixel_sizes++] = pixels;
2844                   current_style->npixel_sizes = 1;
2845                   fontsel_info->point_sizes[npoint_sizes++] = points;
2846                   current_style->npoint_sizes = 1;
2847                 }
2848               style++;
2849               fontsel_info->nstyles++;
2850               current_style++;
2851             }
2852         }
2853       g_slist_free(fontnames[i]);
2854       
2855       /* Set nstyles to the real value, minus duplicated fontnames.
2856          Note that we aren't using all the allocated memory if fontnames are
2857          duplicated. */
2858       font->nstyles = style;
2859     }
2860   
2861   /* Since some repeated styles may be skipped we won't have used all the
2862      allocated space, so we will now reallocate it with the real size. */
2863   fontsel_info->font_styles = g_realloc(fontsel_info->font_styles,
2864                                         sizeof(FontStyle) * fontsel_info->nstyles);
2865   fontsel_info->pixel_sizes = g_realloc(fontsel_info->pixel_sizes,
2866                                         sizeof(guint16) * npixel_sizes);
2867   fontsel_info->point_sizes = g_realloc(fontsel_info->point_sizes,
2868                                         sizeof(guint16) * npoint_sizes);
2869   g_free(fontnames);
2870   XFreeFontNames (xfontnames);
2871   
2872   
2873   /* Debugging Output */
2874   /* This outputs all FontInfos. */
2875 #ifdef FONTSEL_DEBUG
2876   g_message("\n\n Font Family           Weight    Slant     Set Width Spacing   Charset\n\n");
2877   for (i = 0; i < fontsel_info->nfonts; i++)
2878     {
2879       FontInfo *font = &fontsel_info->font_info[i];
2880       FontStyle *styles = fontsel_info->font_styles + font->style_index;
2881       for (style = 0; style < font->nstyles; style++)
2882         {
2883           g_message("%5i %-16.16s ", i, font->family);
2884           for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2885             g_message("%-9.9s ",
2886                       fontsel_info->properties[prop][styles->properties[prop]]);
2887           g_message("\n      ");
2888           
2889           if (styles->flags & GTK_FONT_BITMAP)
2890             g_message("Bitmapped font  ");
2891           if (styles->flags & GTK_FONT_SCALABLE)
2892             g_message("Scalable font  ");
2893           if (styles->flags & GTK_FONT_SCALABLE_BITMAP)
2894             g_message("Scalable-Bitmapped font  ");
2895           g_message("\n");
2896           
2897           if (styles->npixel_sizes)
2898             {
2899               g_message("      Pixel sizes: ");
2900               tmp_sizes = fontsel_info->pixel_sizes + styles->pixel_sizes_index;
2901               for (size = 0; size < styles->npixel_sizes; size++)
2902                 g_message("%i ", *tmp_sizes++);
2903               g_message("\n");
2904             }
2905           
2906           if (styles->npoint_sizes)
2907             {
2908               g_message("      Point sizes: ");
2909               tmp_sizes = fontsel_info->point_sizes + styles->point_sizes_index;
2910               for (size = 0; size < styles->npoint_sizes; size++)
2911                 g_message("%i ", *tmp_sizes++);
2912               g_message("\n");
2913             }
2914           
2915           g_message("\n");
2916           styles++;
2917         }
2918     }
2919   /* This outputs all available properties. */
2920   for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2921     {
2922       g_message("Property: %s\n", xlfd_field_names[xlfd_index[prop]]);
2923       for (i = 0; i < fontsel_info->nproperties[prop]; i++)
2924         g_message("  %s\n", fontsel_info->properties[prop][i]);
2925     }
2926 #endif
2927 }
2928
2929 /* This inserts the given fontname into the FontInfo table.
2930    If a FontInfo already exists with the same family and foundry, then the
2931    fontname is added to the FontInfos list of fontnames, else a new FontInfo
2932    is created and inserted in alphabetical order in the table. */
2933 static void
2934 gtk_font_selection_insert_font (GSList                *fontnames[],
2935                                 gint                  *ntable,
2936                                 gchar                 *fontname)
2937 {
2938   FontInfo *table;
2939   FontInfo temp_info;
2940   GSList *temp_fontname;
2941   gchar *family;
2942   gboolean family_exists = FALSE;
2943   gint foundry;
2944   gint lower, upper;
2945   gint middle, cmp;
2946   gchar family_buffer[XLFD_MAX_FIELD_LEN];
2947   
2948   table = fontsel_info->font_info;
2949   
2950   /* insert a fontname into a table */
2951   family = gtk_font_selection_get_xlfd_field (fontname, XLFD_FAMILY,
2952                                               family_buffer);
2953   if (!family)
2954     return;
2955   
2956   foundry = gtk_font_selection_insert_field (fontname, FOUNDRY);
2957   
2958   lower = 0;
2959   if (*ntable > 0)
2960     {
2961       /* Do a binary search to determine if we have already encountered
2962        *  a font with this family & foundry. */
2963       upper = *ntable;
2964       while (lower < upper)
2965         {
2966           middle = (lower + upper) >> 1;
2967           
2968           cmp = strcmp (family, table[middle].family);
2969           /* If the family matches we sort by the foundry. */
2970           if (cmp == 0)
2971             {
2972               family_exists = TRUE;
2973               family = table[middle].family;
2974               cmp = strcmp(fontsel_info->properties[FOUNDRY][foundry],
2975                            fontsel_info->properties[FOUNDRY][table[middle].foundry]);
2976             }
2977           
2978           if (cmp == 0)
2979             {
2980               fontnames[middle] = g_slist_prepend (fontnames[middle],
2981                                                    fontname);
2982               return;
2983             }
2984           else if (cmp < 0)
2985             upper = middle;
2986           else
2987             lower = middle+1;
2988         }
2989     }
2990   
2991   /* Add another entry to the table for this new font family */
2992   temp_info.family = family_exists ? family : g_strdup(family);
2993   temp_info.foundry = foundry;
2994   temp_fontname = g_slist_prepend (NULL, fontname);
2995   
2996   (*ntable)++;
2997   
2998   /* Quickly insert the entry into the table in sorted order
2999    *  using a modification of insertion sort and the knowledge
3000    *  that the entries proper position in the table was determined
3001    *  above in the binary search and is contained in the "lower"
3002    *  variable. */
3003   if (*ntable > 1)
3004     {
3005       upper = *ntable - 1;
3006       while (lower != upper)
3007         {
3008           table[upper] = table[upper-1];
3009           fontnames[upper] = fontnames[upper-1];
3010           upper--;
3011         }
3012     }
3013   table[lower] = temp_info;
3014   fontnames[lower] = temp_fontname;
3015 }
3016
3017
3018 /* This checks that the specified field of the given fontname is in the
3019    appropriate properties array. If not it is added. Thus eventually we get
3020    arrays of all possible weights/slants etc. It returns the array index. */
3021 static gint
3022 gtk_font_selection_insert_field (gchar                 *fontname,
3023                                  gint                   prop)
3024 {
3025   gchar field_buffer[XLFD_MAX_FIELD_LEN];
3026   gchar *field;
3027   guint16 index;
3028   
3029   field = gtk_font_selection_get_xlfd_field (fontname, xlfd_index[prop],
3030                                              field_buffer);
3031   if (!field)
3032     return 0;
3033   
3034   /* If the field is already in the array just return its index. */
3035   for (index = 0; index < fontsel_info->nproperties[prop]; index++)
3036     if (!strcmp(field, fontsel_info->properties[prop][index]))
3037       return index;
3038   
3039   /* Make sure we have enough space to add the field. */
3040   if (fontsel_info->nproperties[prop] == fontsel_info->space_allocated[prop])
3041     {
3042       fontsel_info->space_allocated[prop] += PROPERTY_ARRAY_INCREMENT;
3043       fontsel_info->properties[prop] = g_realloc(fontsel_info->properties[prop],
3044                                                  sizeof(gchar*)
3045                                                  * fontsel_info->space_allocated[prop]);
3046     }
3047   
3048   /* Add the new field. */
3049   index = fontsel_info->nproperties[prop];
3050   fontsel_info->properties[prop][index] = g_strdup(field);
3051   fontsel_info->nproperties[prop]++;
3052   return index;
3053 }
3054
3055
3056 /*****************************************************************************
3057  * These functions are the main public interface for getting/setting the font.
3058  *****************************************************************************/
3059
3060 GdkFont*
3061 gtk_font_selection_get_font (GtkFontSelection *fontsel)
3062 {
3063   g_return_val_if_fail (fontsel != NULL, NULL);
3064   return fontsel->font;
3065 }
3066
3067
3068 gchar *
3069 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
3070 {
3071   FontInfo *font;
3072   gchar *family_str, *foundry_str;
3073   gchar *property_str[GTK_NUM_STYLE_PROPERTIES];
3074   gint prop;
3075   
3076   g_return_val_if_fail (fontsel != NULL, NULL);
3077   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
3078   
3079   /* If no family has been selected return NULL. */
3080   if (fontsel->font_index == -1)
3081     return NULL;
3082   
3083   font = &fontsel_info->font_info[fontsel->font_index];
3084   family_str = font->family;
3085   foundry_str = fontsel_info->properties[FOUNDRY][font->foundry];
3086   
3087   for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
3088     {
3089       property_str[prop]
3090         = fontsel_info->properties[prop][fontsel->property_values[prop]];
3091       if (strcmp (property_str[prop], "(nil)") == 0)
3092         property_str[prop] = "";
3093     }
3094   
3095   return gtk_font_selection_create_xlfd (fontsel->size,
3096                                          fontsel->metric,
3097                                          foundry_str,
3098                                          family_str,
3099                                          property_str[WEIGHT],
3100                                          property_str[SLANT],
3101                                          property_str[SET_WIDTH],
3102                                          property_str[SPACING],
3103                                          property_str[CHARSET]);
3104 }
3105
3106
3107 /* This sets the current font, selecting the appropriate clist rows.
3108    First we check the fontname is valid and try to find the font family
3109    - i.e. the name in the main list. If we can't find that, then just return.
3110    Next we try to set each of the properties according to the fontname.
3111    Finally we select the font family & style in the clists. */
3112 gboolean
3113 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
3114                                   const gchar      *fontname)
3115 {
3116   gchar *family, *field;
3117   gint index, prop, size;
3118   guint16 foundry, value;
3119   gchar family_buffer[XLFD_MAX_FIELD_LEN];
3120   gchar field_buffer[XLFD_MAX_FIELD_LEN];
3121   gchar buffer[16];
3122   
3123   g_return_val_if_fail (fontsel != NULL, FALSE);
3124   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
3125   g_return_val_if_fail (fontname != NULL, FALSE);
3126   
3127   /* Check it is a valid fontname. */
3128   if (!gtk_font_selection_is_xlfd_font_name(fontname))
3129     return FALSE;
3130   
3131   family = gtk_font_selection_get_xlfd_field (fontname, XLFD_FAMILY,
3132                                               family_buffer);
3133   if (!family)
3134     return FALSE;
3135   
3136   field = gtk_font_selection_get_xlfd_field (fontname, XLFD_FOUNDRY,
3137                                              field_buffer);
3138   foundry = gtk_font_selection_field_to_index (fontsel_info->properties[FOUNDRY],
3139                                                fontsel_info->nproperties[FOUNDRY],
3140                                                field);
3141   
3142   index = gtk_font_selection_find_font(fontsel, family, foundry);
3143   if (index == -1)
3144     return FALSE;
3145   
3146   /* Convert the property fields into indices and set them. */
3147   for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++) 
3148     {
3149       field = gtk_font_selection_get_xlfd_field (fontname, xlfd_index[prop],
3150                                                  field_buffer);
3151       value = gtk_font_selection_field_to_index (fontsel_info->properties[prop],
3152                                                  fontsel_info->nproperties[prop],
3153                                                  field);
3154       fontsel->property_values[prop] = value;
3155     }
3156   
3157   field = gtk_font_selection_get_xlfd_field (fontname, XLFD_POINTS,
3158                                              field_buffer);
3159   size = atoi(field);
3160   if (size > 0)
3161     {
3162       if (size < 20)
3163         size = 20;
3164       fontsel->size = fontsel->selected_size = size;
3165       fontsel->metric = GTK_FONT_METRIC_POINTS;
3166       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fontsel->points_button),
3167                                   TRUE);
3168       if (size % 10 == 0)
3169         sprintf (buffer, "%i", size / 10);
3170       else
3171         sprintf (buffer, "%i.%i", size / 10, size % 10);
3172     }
3173   else
3174     {
3175       field = gtk_font_selection_get_xlfd_field (fontname, XLFD_PIXELS,
3176                                                  field_buffer);
3177       size = atoi(field);
3178       if (size < 2)
3179         size = 2;
3180       fontsel->size = fontsel->selected_size = size;
3181       fontsel->metric = GTK_FONT_METRIC_PIXELS;
3182       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fontsel->pixels_button),
3183                                   TRUE);
3184       sprintf (buffer, "%i", size);
3185     }
3186   gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
3187   
3188   /* Clear any current filter. */
3189   gtk_font_selection_clear_filter(fontsel);
3190   
3191   /* Now find the best style match. */
3192   fontsel->font_index = index;
3193   gtk_clist_select_row(GTK_CLIST(fontsel->font_clist), index, 0);
3194   if (GTK_WIDGET_MAPPED (fontsel->font_clist))
3195     gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), index, -1, 0.5, 0);
3196   
3197   gtk_font_selection_show_available_styles (fontsel);
3198   /* This will load the font. */
3199   gtk_font_selection_select_best_style (fontsel, FALSE);
3200   
3201   return TRUE;
3202 }
3203
3204
3205 /* Returns the index of the given family, or -1 if not found */
3206 static gint
3207 gtk_font_selection_find_font (GtkFontSelection *fontsel,
3208                               gchar            *family,
3209                               guint16           foundry)
3210 {
3211   FontInfo *font_info;
3212   gint lower, upper, middle = -1, cmp, nfonts;
3213   gint found_family = -1;
3214   
3215   font_info = fontsel_info->font_info;
3216   nfonts = fontsel_info->nfonts;
3217   if (nfonts == 0)
3218     return -1;
3219   
3220   /* Do a binary search to find the font family. */
3221   lower = 0;
3222   upper = nfonts;
3223   while (lower < upper)
3224     {
3225       middle = (lower + upper) >> 1;
3226       
3227       cmp = strcmp (family, font_info[middle].family);
3228       if (cmp == 0)
3229         {
3230           found_family = middle;
3231           cmp = strcmp(fontsel_info->properties[FOUNDRY][foundry],
3232                        fontsel_info->properties[FOUNDRY][font_info[middle].foundry]);
3233         }
3234
3235       if (cmp == 0)
3236         return middle;
3237       else if (cmp < 0)
3238         upper = middle;
3239       else if (cmp > 0)
3240         lower = middle+1;
3241     }
3242   
3243   /* We couldn't find the family and foundry, but we may have just found the
3244      family, so we return that. */
3245   return found_family;
3246 }
3247
3248
3249 /* This returns the text in the preview entry. You should copy the returned
3250    text if you need it. */
3251 gchar*
3252 gtk_font_selection_get_preview_text  (GtkFontSelection *fontsel)
3253 {
3254   return gtk_entry_get_text(GTK_ENTRY(fontsel->preview_entry));
3255 }
3256
3257
3258 /* This sets the text in the preview entry. */
3259 void
3260 gtk_font_selection_set_preview_text  (GtkFontSelection *fontsel,
3261                                       const gchar         *text)
3262 {
3263   gtk_entry_set_text(GTK_ENTRY(fontsel->preview_entry), text);
3264 }
3265
3266
3267 /*****************************************************************************
3268  * These functions all deal with X Logical Font Description (XLFD) fontnames.
3269  * See the freely available documentation about this.
3270  *****************************************************************************/
3271
3272 /*
3273  * Returns TRUE if the fontname is a valid XLFD.
3274  * (It just checks if the number of dashes is 14, and that each
3275  * field < XLFD_MAX_FIELD_LEN  characters long - that's not in the XLFD but it
3276  * makes it easier for me).
3277  */
3278 static gboolean
3279 gtk_font_selection_is_xlfd_font_name (const gchar *fontname)
3280 {
3281   gint i = 0;
3282   gint field_len = 0;
3283   
3284   while (*fontname)
3285     {
3286       if (*fontname++ == '-')
3287         {
3288           if (field_len > XLFD_MAX_FIELD_LEN) return FALSE;
3289           field_len = 0;
3290           i++;
3291         }
3292       else
3293         field_len++;
3294     }
3295   
3296   return (i == 14) ? TRUE : FALSE;
3297 }
3298
3299 /*
3300  * This fills the buffer with the specified field from the X Logical Font
3301  * Description name, and returns it. If fontname is NULL or the field is
3302  * longer than XFLD_MAX_FIELD_LEN it returns NULL.
3303  * Note: For the charset field, we also return the encoding, e.g. 'iso8859-1'.
3304  */
3305 static gchar*
3306 gtk_font_selection_get_xlfd_field (const gchar *fontname,
3307                                    FontField    field_num,
3308                                    gchar       *buffer)
3309 {
3310   const gchar *t1, *t2;
3311   gint countdown, len, num_dashes;
3312   
3313   if (!fontname)
3314     return NULL;
3315   
3316   /* we assume this is a valid fontname...that is, it has 14 fields */
3317   
3318   countdown = field_num;
3319   t1 = fontname;
3320   while (*t1 && (countdown >= 0))
3321     if (*t1++ == '-')
3322       countdown--;
3323   
3324   num_dashes = (field_num == XLFD_CHARSET) ? 2 : 1;
3325   for (t2 = t1; *t2; t2++)
3326     { 
3327       if (*t2 == '-' && --num_dashes == 0)
3328         break;
3329     }
3330   
3331   if (t1 != t2)
3332     {
3333       /* Check we don't overflow the buffer */
3334       len = (long) t2 - (long) t1;
3335       if (len > XLFD_MAX_FIELD_LEN - 1)
3336         return NULL;
3337       strncpy (buffer, t1, len);
3338       buffer[len] = 0;
3339
3340       /* Convert to lower case. */
3341       g_strdown (buffer);
3342     }
3343   else
3344     strcpy(buffer, "(nil)");
3345   
3346   return buffer;
3347 }
3348
3349 /*
3350  * This returns a X Logical Font Description font name, given all the pieces.
3351  * Note: this retval must be freed by the caller.
3352  */
3353 static gchar *
3354 gtk_font_selection_create_xlfd (gint              size,
3355                                 GtkFontMetricType metric,
3356                                 gchar             *foundry,
3357                                 gchar             *family,
3358                                 gchar             *weight,
3359                                 gchar             *slant,
3360                                 gchar             *set_width,
3361                                 gchar             *spacing,
3362                                 gchar             *charset)
3363 {
3364   gchar buffer[16];
3365   gchar *pixel_size = "*", *point_size = "*", *fontname;
3366   gint length;
3367   
3368   if (size <= 0)
3369     return NULL;
3370   
3371   sprintf (buffer, "%d", (int) size);
3372   if (metric == GTK_FONT_METRIC_PIXELS)
3373     pixel_size = buffer;
3374   else
3375     point_size = buffer;
3376   
3377   /* Note: be careful here - don't overrun the allocated memory. */
3378   length = strlen(foundry) + strlen(family) + strlen(weight) + strlen(slant)
3379     + strlen(set_width) + strlen(pixel_size) + strlen(point_size)
3380     + strlen(spacing) + strlen(charset)
3381     + 1 + 1 + 1 + 1 + 1 + 3 + 1 + 5 + 3
3382     + 1 /* for the terminating '\0'. */;
3383   
3384   fontname = g_new(gchar, length);
3385   /* **NOTE**: If you change this string please change length above! */
3386   sprintf(fontname, "-%s-%s-%s-%s-%s-*-%s-%s-*-*-%s-*-%s",
3387           foundry, family, weight, slant, set_width, pixel_size,
3388           point_size, spacing, charset);
3389   return fontname;
3390 }
3391
3392
3393
3394 /*****************************************************************************
3395  * GtkFontSelectionDialog
3396  *****************************************************************************/
3397
3398 guint
3399 gtk_font_selection_dialog_get_type (void)
3400 {
3401   static guint font_selection_dialog_type = 0;
3402   
3403   if (!font_selection_dialog_type)
3404     {
3405       GtkTypeInfo fontsel_diag_info =
3406       {
3407         "GtkFontSelectionDialog",
3408         sizeof (GtkFontSelectionDialog),
3409         sizeof (GtkFontSelectionDialogClass),
3410         (GtkClassInitFunc) gtk_font_selection_dialog_class_init,
3411         (GtkObjectInitFunc) gtk_font_selection_dialog_init,
3412         /* reserved_1 */ NULL,
3413         /* reserved_2 */ NULL,
3414         (GtkClassInitFunc) NULL,
3415       };
3416       
3417       font_selection_dialog_type = gtk_type_unique (GTK_TYPE_WINDOW, &fontsel_diag_info);
3418     }
3419   
3420   return font_selection_dialog_type;
3421 }
3422
3423 static void
3424 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
3425 {
3426   GtkObjectClass *object_class;
3427   
3428   object_class = (GtkObjectClass*) klass;
3429   
3430   font_selection_dialog_parent_class = gtk_type_class (GTK_TYPE_WINDOW);
3431 }
3432
3433 static void
3434 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
3435 {
3436   fontseldiag->dialog_width = -1;
3437   fontseldiag->auto_resize = TRUE;
3438   
3439   gtk_widget_set_events(GTK_WIDGET(fontseldiag), GDK_STRUCTURE_MASK);
3440   gtk_signal_connect (GTK_OBJECT (fontseldiag), "configure_event",
3441                       (GtkSignalFunc) gtk_font_selection_dialog_on_configure,
3442                       fontseldiag);
3443   
3444   gtk_container_set_border_width (GTK_CONTAINER (fontseldiag), 4);
3445   gtk_window_set_policy(GTK_WINDOW(fontseldiag), FALSE, TRUE, TRUE);
3446   
3447   fontseldiag->main_vbox = gtk_vbox_new (FALSE, 4);
3448   gtk_widget_show (fontseldiag->main_vbox);
3449   gtk_container_add (GTK_CONTAINER (fontseldiag), fontseldiag->main_vbox);
3450   
3451   fontseldiag->fontsel = gtk_font_selection_new();
3452   gtk_widget_show (fontseldiag->fontsel);
3453   gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
3454                       fontseldiag->fontsel, TRUE, TRUE, 0);
3455   
3456   /* Create the action area */
3457   fontseldiag->action_area = gtk_hbutton_box_new ();
3458   gtk_button_box_set_layout(GTK_BUTTON_BOX(fontseldiag->action_area),
3459                             GTK_BUTTONBOX_END);
3460   gtk_button_box_set_spacing(GTK_BUTTON_BOX(fontseldiag->action_area), 5);
3461   gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
3462                       fontseldiag->action_area, FALSE, FALSE, 0);
3463   gtk_widget_show (fontseldiag->action_area);
3464   
3465   fontseldiag->ok_button = gtk_button_new_with_label(_("OK"));
3466   GTK_WIDGET_SET_FLAGS (fontseldiag->ok_button, GTK_CAN_DEFAULT);
3467   gtk_widget_show(fontseldiag->ok_button);
3468   gtk_box_pack_start (GTK_BOX (fontseldiag->action_area),
3469                       fontseldiag->ok_button, TRUE, TRUE, 0);
3470   gtk_widget_grab_default (fontseldiag->ok_button);
3471   
3472   fontseldiag->apply_button = gtk_button_new_with_label(_("Apply"));
3473   GTK_WIDGET_SET_FLAGS (fontseldiag->apply_button, GTK_CAN_DEFAULT);
3474   /*gtk_widget_show(fontseldiag->apply_button);*/
3475   gtk_box_pack_start (GTK_BOX(fontseldiag->action_area),
3476                       fontseldiag->apply_button, TRUE, TRUE, 0);
3477   
3478   fontseldiag->cancel_button = gtk_button_new_with_label(_("Cancel"));
3479   GTK_WIDGET_SET_FLAGS (fontseldiag->cancel_button, GTK_CAN_DEFAULT);
3480   gtk_widget_show(fontseldiag->cancel_button);
3481   gtk_box_pack_start (GTK_BOX(fontseldiag->action_area),
3482                       fontseldiag->cancel_button, TRUE, TRUE, 0);
3483   
3484   
3485 }
3486
3487 GtkWidget*
3488 gtk_font_selection_dialog_new   (const gchar      *title)
3489 {
3490   GtkFontSelectionDialog *fontseldiag;
3491   
3492   fontseldiag = gtk_type_new (GTK_TYPE_FONT_SELECTION_DIALOG);
3493   gtk_window_set_title (GTK_WINDOW (fontseldiag),
3494                         title ? title : _("Font Selection"));
3495   
3496   return GTK_WIDGET (fontseldiag);
3497 }
3498
3499 gchar*
3500 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
3501 {
3502   return gtk_font_selection_get_font_name(GTK_FONT_SELECTION(fsd->fontsel));
3503 }
3504
3505 GdkFont*
3506 gtk_font_selection_dialog_get_font      (GtkFontSelectionDialog *fsd)
3507 {
3508   return gtk_font_selection_get_font(GTK_FONT_SELECTION(fsd->fontsel));
3509 }
3510
3511 gboolean
3512 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
3513                                          const gchar      *fontname)
3514 {
3515   return gtk_font_selection_set_font_name(GTK_FONT_SELECTION(fsd->fontsel),
3516                                           fontname);
3517 }
3518
3519 void
3520 gtk_font_selection_dialog_set_filter    (GtkFontSelectionDialog *fsd,
3521                                          GtkFontFilterType filter_type,
3522                                          GtkFontType       font_type,
3523                                          gchar           **foundries,
3524                                          gchar           **weights,
3525                                          gchar           **slants,
3526                                          gchar           **setwidths,
3527                                          gchar           **spacings,
3528                                          gchar           **charsets)
3529 {
3530   gtk_font_selection_set_filter (GTK_FONT_SELECTION (fsd->fontsel),
3531                                  filter_type, font_type,
3532                                  foundries, weights, slants, setwidths,
3533                                  spacings, charsets);
3534 }
3535
3536 gchar*
3537 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
3538 {
3539   return gtk_font_selection_get_preview_text(GTK_FONT_SELECTION(fsd->fontsel));
3540 }
3541
3542 void
3543 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
3544                                             const gchar   *text)
3545 {
3546   gtk_font_selection_set_preview_text(GTK_FONT_SELECTION(fsd->fontsel), text);
3547 }
3548
3549
3550 /* This turns auto-shrink off if the user resizes the width of the dialog.
3551    It also turns it back on again if the user resizes it back to its normal
3552    width. */
3553 static gint
3554 gtk_font_selection_dialog_on_configure (GtkWidget         *widget,
3555                                         GdkEventConfigure *event,
3556                                         GtkFontSelectionDialog *fsd)
3557 {
3558   /* This sets the initial width. */
3559   if (fsd->dialog_width == -1)
3560     fsd->dialog_width = event->width;
3561   else if (fsd->auto_resize && fsd->dialog_width != event->width)
3562     {
3563       fsd->auto_resize = FALSE;
3564       gtk_window_set_policy(GTK_WINDOW(fsd), FALSE, TRUE, FALSE);
3565     }
3566   else if (!fsd->auto_resize && fsd->dialog_width == event->width)
3567     {
3568       fsd->auto_resize = TRUE;
3569       gtk_window_set_policy(GTK_WINDOW(fsd), FALSE, TRUE, TRUE);
3570     }
3571   
3572   return FALSE;
3573 }