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