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