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