source: trunk/third/gtk/gtk/gtkfontsel.c @ 16369

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