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