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