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