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

Revision 15781, 114.3 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r15780, which included commits to RCS files with non-trunk default branches.
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  gint 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 = atoi(text);
1677  if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1678    new_size *= 10;
1679 
1680  if (fontsel->size == new_size)
1681    return;
1682 
1683  /* If the size was selected by the user we set the selected_size. */
1684  fontsel->selected_size = new_size;
1685 
1686  fontsel->size = new_size;
1687  gtk_font_selection_load_font (fontsel);
1688}
1689
1690
1691/* This is called when the pixels or points radio buttons are pressed. */
1692static void
1693gtk_font_selection_metric_callback (GtkWidget *w,
1694                                    gpointer   data)
1695{
1696  GtkFontSelection *fontsel = GTK_FONT_SELECTION(data);
1697 
1698#ifdef FONTSEL_DEBUG
1699  g_message("In metric_callback\n");
1700#endif
1701  if (GTK_TOGGLE_BUTTON(fontsel->pixels_button)->active)
1702    {
1703      if (fontsel->metric == GTK_FONT_METRIC_PIXELS)
1704        return;
1705      fontsel->metric = GTK_FONT_METRIC_PIXELS;
1706      fontsel->size = (fontsel->size + 5) / 10;
1707      fontsel->selected_size = (fontsel->selected_size + 5) / 10;
1708    }
1709  else
1710    {
1711      if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1712        return;
1713      fontsel->metric = GTK_FONT_METRIC_POINTS;
1714      fontsel->size *= 10;
1715      fontsel->selected_size *= 10;
1716    }
1717  if (fontsel->font_index != -1)
1718    {
1719      gtk_font_selection_show_available_sizes (fontsel);
1720      gtk_font_selection_select_best_size (fontsel);
1721    }
1722}
1723
1724
1725/* This searches the given property table and returns the index of the given
1726   string, or 0, which is the wildcard '*' index, if it's not found. */
1727static guint16
1728gtk_font_selection_field_to_index (gchar **table,
1729                                   gint    ntable,
1730                                   gchar  *field)
1731{
1732  gint i;
1733 
1734  for (i = 0; i < ntable; i++)
1735    if (strcmp (field, table[i]) == 0)
1736      return i;
1737 
1738  return 0;
1739}
1740
1741
1742
1743/* This attempts to load the current font, and returns TRUE if it succeeds. */
1744static gboolean
1745gtk_font_selection_load_font (GtkFontSelection *fontsel)
1746{
1747  GdkFont *font;
1748  gchar *fontname, *label_text;
1749  XFontStruct *xfs;
1750 
1751  if (fontsel->font)
1752    gdk_font_unref (fontsel->font);
1753  fontsel->font = NULL;
1754 
1755  /* If no family has been selected yet, just return FALSE. */
1756  if (fontsel->font_index == -1)
1757    return FALSE;
1758 
1759  fontname = gtk_font_selection_get_font_name (fontsel);
1760  if (fontname)
1761    {
1762#ifdef FONTSEL_DEBUG
1763      g_message("Loading: %s\n", fontname);
1764#endif
1765      font = gdk_font_load (fontname);
1766      xfs = font ? GDK_FONT_XFONT (font) : NULL;
1767      if (xfs && (xfs->min_byte1 != 0 || xfs->max_byte1 != 0))
1768        {
1769          gchar *tmp_name;
1770         
1771          gdk_font_unref (font);
1772          tmp_name = g_strconcat (fontname, ",*", NULL);
1773          font = gdk_fontset_load (tmp_name);
1774          g_free (tmp_name);
1775        }
1776      g_free (fontname);
1777     
1778      if (font)
1779        {
1780          fontsel->font = font;
1781          /* Make sure the message label is empty, but don't change it unless
1782             it's necessary as it results in a resize of the whole window! */
1783          gtk_label_get(GTK_LABEL(fontsel->message_label), &label_text);
1784          if (strcmp(label_text, ""))
1785            gtk_label_set_text(GTK_LABEL(fontsel->message_label), "");
1786          gtk_font_selection_update_preview (fontsel);
1787          return TRUE;
1788        }
1789      else
1790        {
1791          gtk_label_set_text(GTK_LABEL(fontsel->message_label),
1792                             _("The selected font is not available."));
1793        }
1794    }
1795  else
1796    {
1797      gtk_label_set_text(GTK_LABEL(fontsel->message_label),
1798                         _("The selected font is not a valid font."));
1799    }
1800 
1801  return FALSE;
1802}
1803
1804
1805/* This sets the font in the preview entry to the selected font, and tries to
1806   make sure that the preview entry is a reasonable size, i.e. so that the
1807   text can be seen with a bit of space to spare. But it tries to avoid
1808   resizing the entry every time the font changes.
1809   This also used to shrink the preview if the font size was decreased, but
1810   that made it awkward if the user wanted to resize the window themself. */
1811static void
1812gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1813{
1814  GtkWidget *preview_entry;
1815  GtkStyle *style;
1816  gint text_height, new_height;
1817  gchar *text;
1818  XFontStruct *xfs;
1819 
1820#ifdef FONTSEL_DEBUG
1821  g_message("In update_preview\n");
1822#endif
1823  style = gtk_style_new ();
1824  gdk_font_unref (style->font);
1825  style->font = fontsel->font;
1826  gdk_font_ref (style->font);
1827 
1828  preview_entry = fontsel->preview_entry;
1829  gtk_widget_set_style (preview_entry, style);
1830  gtk_style_unref(style);
1831 
1832  text_height = preview_entry->style->font->ascent
1833    + preview_entry->style->font->descent;
1834  /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1835  new_height = text_height + 20;
1836  if (new_height < INITIAL_PREVIEW_HEIGHT)
1837    new_height = INITIAL_PREVIEW_HEIGHT;
1838  if (new_height > MAX_PREVIEW_HEIGHT)
1839    new_height = MAX_PREVIEW_HEIGHT;
1840 
1841  if ((preview_entry->requisition.height < text_height + 10)
1842      || (preview_entry->requisition.height > text_height + 40))
1843    gtk_widget_set_usize(preview_entry, -1, new_height);
1844 
1845  /* This sets the preview text, if it hasn't been set already. */
1846  text = gtk_entry_get_text(GTK_ENTRY(fontsel->preview_entry));
1847  if (strlen(text) == 0)
1848    gtk_entry_set_text(GTK_ENTRY(fontsel->preview_entry), PREVIEW_TEXT);
1849  gtk_entry_set_position(GTK_ENTRY(fontsel->preview_entry), 0);
1850 
1851  /* If this is a 2-byte font display a message to say it may not be
1852     displayed properly. */
1853  xfs = GDK_FONT_XFONT(fontsel->font);
1854  if (xfs->min_byte1 != 0 || xfs->max_byte1 != 0)
1855    gtk_label_set_text(GTK_LABEL(fontsel->message_label),
1856                       _("This is a 2-byte font and may not be displayed correctly."));
1857}
1858
1859
1860static void
1861gtk_font_selection_switch_page (GtkWidget       *w,
1862                                GtkNotebookPage *page,
1863                                gint             page_num,
1864                                gpointer         data)
1865{
1866  GtkFontSelection *fontsel = GTK_FONT_SELECTION(data);
1867 
1868  /* This function strangely gets called when the window is destroyed,
1869     so we check here to see if the notebook is visible. */
1870  if (!GTK_WIDGET_VISIBLE(w))
1871    return;
1872 
1873  if (page_num == 0)
1874    gtk_font_selection_update_filter(fontsel);
1875  else if (page_num == 1)
1876    gtk_font_selection_show_font_info(fontsel);
1877}
1878
1879
1880static void
1881gtk_font_selection_show_font_info (GtkFontSelection *fontsel)
1882{
1883  Atom font_atom, atom;
1884  Bool status;
1885  char *name;
1886  gchar *fontname;
1887  gchar field_buffer[XLFD_MAX_FIELD_LEN];
1888  gchar *field;
1889  gint i;
1890  gboolean shown_actual_fields = FALSE;
1891 
1892  fontname = gtk_font_selection_get_font_name(fontsel);
1893  gtk_entry_set_text(GTK_ENTRY(fontsel->requested_font_name),
1894                     fontname ? fontname : "");
1895 
1896  gtk_clist_freeze (GTK_CLIST(fontsel->info_clist));
1897  for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1898    {
1899      if (fontname)
1900        field = gtk_font_selection_get_xlfd_field (fontname, i, field_buffer);
1901      else
1902        field = NULL;
1903      if (field)
1904        {
1905          if (i == XLFD_SLANT)
1906            field = gtk_font_selection_expand_slant_code(field);
1907          else if (i == XLFD_SPACING)
1908            field = gtk_font_selection_expand_spacing_code(field);
1909        }
1910      gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 1,
1911                         field ? field : "");
1912    }
1913 
1914  if (fontsel->font)
1915    {
1916      font_atom = gdk_atom_intern ("FONT", FALSE);
1917
1918      if (fontsel->font->type == GDK_FONT_FONTSET)
1919        {
1920          XFontStruct **font_structs;
1921          gint num_fonts;
1922          gchar **font_names;
1923         
1924          num_fonts = XFontsOfFontSet (GDK_FONT_XFONT(fontsel->font),
1925                                       &font_structs, &font_names);
1926          status = XGetFontProperty(font_structs[0], font_atom, &atom);
1927        }
1928      else
1929        {
1930          status = XGetFontProperty(GDK_FONT_XFONT(fontsel->font), font_atom,
1931                                    &atom);
1932        }
1933
1934      if (status == True)
1935        {
1936          name = gdk_atom_name (atom);
1937          gtk_entry_set_text(GTK_ENTRY(fontsel->actual_font_name), name);
1938         
1939          for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1940            {
1941              field = gtk_font_selection_get_xlfd_field (name, i,
1942                                                         field_buffer);
1943              if (i == XLFD_SLANT)
1944                field = gtk_font_selection_expand_slant_code(field);
1945              else if (i == XLFD_SPACING)
1946                field = gtk_font_selection_expand_spacing_code(field);
1947              gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 2,
1948                                 field ? field : "");
1949            }
1950          shown_actual_fields = TRUE;
1951          g_free (name);
1952        }
1953    }
1954  if (!shown_actual_fields)
1955    {
1956      gtk_entry_set_text(GTK_ENTRY(fontsel->actual_font_name), "");
1957      for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1958        {
1959          gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 2,
1960                             fontname ? _("(unknown)") : "");
1961        }
1962    }
1963  gtk_clist_thaw (GTK_CLIST(fontsel->info_clist));
1964  g_free(fontname);
1965}
1966
1967
1968static gchar*
1969gtk_font_selection_expand_slant_code(gchar *slant)
1970{
1971  if      (!g_strcasecmp(slant, "r"))   return(_("roman"));
1972  else if (!g_strcasecmp(slant, "i"))   return(_("italic"));
1973  else if (!g_strcasecmp(slant, "o"))   return(_("oblique"));
1974  else if (!g_strcasecmp(slant, "ri"))  return(_("reverse italic"));
1975  else if (!g_strcasecmp(slant, "ro"))  return(_("reverse oblique"));
1976  else if (!g_strcasecmp(slant, "ot"))  return(_("other"));
1977  return slant;
1978}
1979
1980static gchar*
1981gtk_font_selection_expand_spacing_code(gchar *spacing)
1982{
1983  if      (!g_strcasecmp(spacing, "p")) return(_("proportional"));
1984  else if (!g_strcasecmp(spacing, "m")) return(_("monospaced"));
1985  else if (!g_strcasecmp(spacing, "c")) return(_("char cell"));
1986  return spacing;
1987}
1988
1989
1990/*****************************************************************************
1991 * These functions all deal with the Filter page and filtering the fonts.
1992 *****************************************************************************/
1993
1994/* This is called when an item is selected in one of the filter clists.
1995   We make sure that the first row of the clist, i.e. the wildcard '*', is
1996   selected if and only if none of the other items are selected.
1997   Also doesn't allow selections of values filtered out by base filter.
1998   We may need to be careful about triggering other signals. */
1999static void
2000gtk_font_selection_select_filter             (GtkWidget      *w,
2001                                              gint            row,
2002                                              gint            column,
2003                                              GdkEventButton *bevent,
2004                                              GtkFontSelection *fontsel)
2005{
2006  gint i, prop, index;
2007 
2008  if (row == 0)
2009    {
2010      for (i = 1; i < GTK_CLIST(w)->rows; i++)
2011        gtk_clist_unselect_row(GTK_CLIST(w), i, 0);
2012    }
2013  else
2014    {
2015      /* Find out which property this is. */
2016      for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2017        if (fontsel->filter_clists[prop] == w)
2018          break;
2019      index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(w), row));
2020      if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_BASE,
2021                                           prop, index) == NOT_FILTERED)
2022        gtk_clist_unselect_row(GTK_CLIST(w), row, 0);
2023      else
2024        gtk_clist_unselect_row(GTK_CLIST(w), 0, 0);
2025    }
2026}
2027
2028
2029/* Here a filter item is being deselected. If there are now no items selected
2030   we select the first '*' item, unless that it is the item being deselected,
2031   in which case we select all of the other items. This makes it easy to
2032   select all items in the list except one or two. */
2033static void
2034gtk_font_selection_unselect_filter           (GtkWidget      *w,
2035                                              gint            row,
2036                                              gint            column,
2037                                              GdkEventButton *bevent,
2038                                              GtkFontSelection *fontsel)
2039{
2040  gint i, prop, index;
2041
2042  if (!GTK_CLIST(w)->selection)
2043    {
2044      if (row == 0)
2045        {
2046          /* Find out which property this is. */
2047          for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2048            if (fontsel->filter_clists[prop] == w)
2049              break;
2050
2051          for (i = 1; i < GTK_CLIST(w)->rows; i++)
2052            {
2053              index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(w),
2054                                                              i));
2055              if (gtk_font_selection_filter_state (fontsel,
2056                                                   GTK_FONT_FILTER_BASE,
2057                                                   prop, index)
2058                  != NOT_FILTERED)
2059                gtk_clist_select_row(GTK_CLIST(w), i, 0);
2060            }
2061        }
2062      else
2063        {
2064          gtk_clist_select_row(GTK_CLIST(w), 0, 0);
2065        }
2066    }
2067}
2068
2069
2070/* This is called when the main notebook page is selected. It checks if the
2071   filter has changed, an if so it creates the filter settings, and filters the
2072   fonts shown. If an empty filter (all '*'s) is applied, then filtering is
2073   turned off. */
2074static void
2075gtk_font_selection_update_filter     (GtkFontSelection *fontsel)
2076{
2077  GtkWidget *clist;
2078  GList *selection;
2079  gboolean default_filter = TRUE, filter_changed = FALSE;
2080  gint prop, nselected, i, row, index;
2081  GtkFontFilter *filter = &fontsel->filters[GTK_FONT_FILTER_USER];
2082  gint base_font_type, user_font_type, new_font_type;
2083 
2084#ifdef FONTSEL_DEBUG
2085  g_message("In update_filter\n");
2086#endif
2087 
2088  /* Check if the user filter has changed, and also if it is the default
2089     filter, i.e. bitmap & scalable fonts and all '*'s selected.
2090     We only look at the bits which are not already filtered out by the base
2091     filter, since that overrides the user filter. */
2092  base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
2093    & GTK_FONT_ALL;
2094  user_font_type = fontsel->filters[GTK_FONT_FILTER_USER].font_type
2095    & GTK_FONT_ALL;
2096  new_font_type = GTK_TOGGLE_BUTTON(fontsel->type_bitmaps_button)->active
2097    ? GTK_FONT_BITMAP : 0;
2098  new_font_type |= (GTK_TOGGLE_BUTTON(fontsel->type_scalable_button)->active
2099    ? GTK_FONT_SCALABLE : 0);
2100  new_font_type |= (GTK_TOGGLE_BUTTON(fontsel->type_scaled_bitmaps_button)->active ? GTK_FONT_SCALABLE_BITMAP : 0);
2101  new_font_type &= base_font_type;
2102  new_font_type |= (~base_font_type & user_font_type);
2103  if (new_font_type != (GTK_FONT_BITMAP | GTK_FONT_SCALABLE))
2104    default_filter = FALSE;
2105
2106  if (new_font_type != user_font_type)
2107    filter_changed = TRUE;
2108  fontsel->filters[GTK_FONT_FILTER_USER].font_type = new_font_type;
2109
2110  for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2111    {
2112      clist = fontsel->filter_clists[prop];
2113      selection = GTK_CLIST(clist)->selection;
2114      nselected = g_list_length(selection);
2115      if (nselected != 1 || GPOINTER_TO_INT (selection->data) != 0)
2116        {
2117          default_filter = FALSE;
2118         
2119          if (filter->property_nfilters[prop] != nselected)
2120            filter_changed = TRUE;
2121          else
2122            {
2123              for (i = 0; i < nselected; i++)
2124                {
2125                  row = GPOINTER_TO_INT (selection->data);
2126                  index = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (clist), row));
2127                  if (filter->property_filters[prop][i] != index)
2128                    filter_changed = TRUE;
2129                  selection = selection->next;
2130                }
2131            }
2132        }
2133      else
2134        {
2135          if (filter->property_nfilters[prop] != 0)
2136            filter_changed = TRUE;
2137        }
2138    }
2139 
2140  /* If the filter hasn't changed we just return. */
2141  if (!filter_changed)
2142    return;
2143 
2144#ifdef FONTSEL_DEBUG
2145  g_message("   update_fonts: filter has changed\n");
2146#endif
2147 
2148  /* Free the old filter data and create the new arrays. */
2149  for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2150    {
2151      g_free(filter->property_filters[prop]);
2152
2153      clist = fontsel->filter_clists[prop];
2154      selection = GTK_CLIST(clist)->selection;
2155      nselected = g_list_length(selection);
2156      if (nselected == 1 && GPOINTER_TO_INT (selection->data) == 0)
2157        {
2158          filter->property_filters[prop] = NULL;
2159          filter->property_nfilters[prop] = 0;
2160        }
2161      else
2162        {
2163          filter->property_filters[prop] = g_new(guint16, nselected);
2164          filter->property_nfilters[prop] = nselected;
2165          for (i = 0; i < nselected; i++)
2166            {
2167              row = GPOINTER_TO_INT (selection->data);
2168              index = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (clist), row));
2169              filter->property_filters[prop][i] = index;
2170              selection = selection->next;
2171            }
2172        }
2173    }
2174
2175  /* Set the 'Reset Filter' button sensitive if a filter is in effect, and
2176     also set the label above the font list to show this as well. */
2177  if (default_filter)
2178    {
2179      gtk_widget_set_sensitive(fontsel->filter_button, FALSE);
2180      gtk_label_set_text(GTK_LABEL(fontsel->font_label), _("Font:"));
2181    }
2182  else
2183    {
2184      gtk_widget_set_sensitive(fontsel->filter_button, TRUE);
2185      gtk_label_set_text(GTK_LABEL(fontsel->font_label), _("Font: (Filter Applied)"));
2186    }
2187  gtk_font_selection_show_available_fonts(fontsel);
2188
2189
2190
2191/* This shows all the available fonts in the font clist. */
2192static void
2193gtk_font_selection_show_available_fonts     (GtkFontSelection *fontsel)
2194{
2195  FontInfo *font_info, *font;
2196  GtkFontFilter *filter;
2197  gint nfonts, i, j, k, row, style, font_row = -1;
2198  gchar font_buffer[XLFD_MAX_FIELD_LEN * 2 + 4];
2199  gchar *font_item;
2200  gboolean matched, matched_style;
2201 
2202#ifdef FONTSEL_DEBUG
2203  g_message("In show_available_fonts\n");
2204#endif
2205  font_info = fontsel_info->font_info;
2206  nfonts = fontsel_info->nfonts;
2207 
2208  /* Filter the list of fonts. */
2209  gtk_clist_freeze (GTK_CLIST(fontsel->font_clist));
2210  gtk_clist_clear (GTK_CLIST(fontsel->font_clist));
2211  for (i = 0; i < nfonts; i++)
2212    {
2213      font = &font_info[i];
2214     
2215      /* Check if the foundry passes through all filters. */
2216      matched = TRUE;
2217      for (k = 0; k < GTK_NUM_FONT_FILTERS; k++)
2218        {
2219          filter = &fontsel->filters[k];
2220
2221          if (filter->property_nfilters[FOUNDRY] != 0)
2222            {
2223              matched = FALSE;
2224              for (j = 0; j < filter->property_nfilters[FOUNDRY]; j++)
2225                {
2226                  if (font->foundry == filter->property_filters[FOUNDRY][j])
2227                    {
2228                      matched = TRUE;
2229                      break;
2230                    }
2231                }
2232              if (!matched)
2233                break;
2234            }
2235        }
2236     
2237      if (!matched)
2238        continue;
2239
2240
2241      /* Now check if the other properties are matched in at least one style.*/
2242      matched_style = FALSE;
2243      for (style = 0; style < font->nstyles; style++)
2244        {
2245          if (gtk_font_selection_style_visible(fontsel, font, style))
2246            {
2247              matched_style = TRUE;
2248              break;
2249            }
2250        }
2251      if (!matched_style)
2252        continue;
2253     
2254      /* Insert the font in the clist. */
2255      if ((i > 0 && font->family == font_info[i-1].family)
2256          || (i < nfonts - 1 && font->family == font_info[i+1].family))
2257        {
2258          sprintf(font_buffer, "%s (%s)", font->family,
2259                  fontsel_info->properties[FOUNDRY][font->foundry]);
2260          font_item = font_buffer;
2261          row = gtk_clist_append(GTK_CLIST(fontsel->font_clist), &font_item);
2262        }
2263      else
2264        {
2265          row = gtk_clist_append(GTK_CLIST(fontsel->font_clist),
2266                                 &font->family);
2267        }
2268      gtk_clist_set_row_data(GTK_CLIST(fontsel->font_clist), row,
2269                             GINT_TO_POINTER (i));
2270      if (fontsel->font_index == i)
2271        font_row = row;
2272    }
2273  gtk_clist_thaw (GTK_CLIST(fontsel->font_clist));
2274 
2275  /* If the currently-selected font isn't in the new list, reset the
2276     selection. */
2277  if (font_row == -1)
2278    {
2279      fontsel->font_index = -1;
2280      if (fontsel->font)
2281        gdk_font_unref(fontsel->font);
2282      fontsel->font = NULL;
2283      gtk_entry_set_text(GTK_ENTRY(fontsel->font_entry), "");
2284      gtk_clist_clear (GTK_CLIST(fontsel->font_style_clist));
2285      gtk_entry_set_text(GTK_ENTRY(fontsel->font_style_entry), "");
2286      return;
2287    }
2288
2289  gtk_clist_select_row(GTK_CLIST(fontsel->font_clist), font_row, 0);
2290  if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_clist), font_row)
2291      != GTK_VISIBILITY_FULL)
2292    gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), font_row, -1, 0.5, 0);
2293
2294  gtk_font_selection_show_available_styles (fontsel);
2295  gtk_font_selection_select_best_style (fontsel, FALSE);
2296}
2297
2298
2299/* Returns TRUE if the style is not currently filtered out. */
2300static gboolean
2301gtk_font_selection_style_visible(GtkFontSelection *fontsel,
2302                                 FontInfo         *font,
2303                                 gint              style_index)
2304{
2305  FontStyle *styles, *style;
2306  GtkFontFilter *filter;
2307  guint16 value;
2308  gint prop, i, j;
2309  gboolean matched;
2310  gint type_filter;
2311
2312  styles = &fontsel_info->font_styles[font->style_index];
2313  style = &styles[style_index];
2314
2315  /* Check if font_type of style is filtered. */
2316  type_filter = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
2317    & fontsel->filters[GTK_FONT_FILTER_USER].font_type;
2318  if (!(style->flags & type_filter))
2319    return FALSE;
2320 
2321  for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2322    {
2323      value = style->properties[prop];
2324     
2325      /* Check each filter. */
2326      for (i = 0; i < GTK_NUM_FONT_FILTERS; i++)
2327        {
2328          filter = &fontsel->filters[i];
2329
2330          if (filter->property_nfilters[prop] != 0)
2331            {
2332              matched = FALSE;
2333              for (j = 0; j < filter->property_nfilters[prop]; j++)
2334                {
2335                  if (value == filter->property_filters[prop][j])
2336                    {
2337                      matched = TRUE;
2338                      break;
2339                    }
2340                }
2341              if (!matched)
2342                return FALSE;
2343            }
2344        }
2345    }
2346  return TRUE;
2347}
2348
2349
2350/* This resets the font type to bitmap or scalable, and sets all the filter
2351   clists to the wildcard '*' options. */
2352static void
2353gtk_font_selection_reset_filter      (GtkWidget      *w,
2354                                      GtkFontSelection *fontsel)
2355{
2356  gint prop, base_font_type;
2357 
2358  fontsel->filters[GTK_FONT_FILTER_USER].font_type = GTK_FONT_BITMAP
2359    | GTK_FONT_SCALABLE;
2360
2361  base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type;
2362  if (base_font_type & GTK_FONT_BITMAP)
2363    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), TRUE);
2364  if (base_font_type & GTK_FONT_SCALABLE)
2365    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), TRUE);
2366  if (base_font_type & GTK_FONT_SCALABLE_BITMAP)
2367    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), FALSE);
2368 
2369  for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2370    gtk_clist_select_row(GTK_CLIST(fontsel->filter_clists[prop]), 0, 0);
2371}
2372
2373
2374/* This clears the filter, showing all fonts and styles again. */
2375static void
2376gtk_font_selection_on_clear_filter     (GtkWidget      *w,
2377                                        GtkFontSelection *fontsel)
2378{
2379  gtk_font_selection_clear_filter(fontsel);
2380}
2381
2382
2383/* This resets the user filter, showing all fonts and styles which pass the
2384   base filter again. Note that the font type is set to bitmaps and scalable
2385   fonts - scaled bitmaps are not shown. */
2386static void
2387gtk_font_selection_clear_filter     (GtkFontSelection *fontsel)
2388{
2389  GtkFontFilter *filter;
2390  gint prop;
2391 
2392#ifdef FONTSEL_DEBUG
2393  g_message("In clear_filter\n");
2394#endif
2395  /* Clear the filter data. */
2396  filter = &fontsel->filters[GTK_FONT_FILTER_USER];
2397  filter->font_type = GTK_FONT_BITMAP | GTK_FONT_SCALABLE;
2398  for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2399    {
2400      g_free(filter->property_filters[prop]);
2401      filter->property_filters[prop] = NULL;
2402      filter->property_nfilters[prop] = 0;
2403    }
2404 
2405  /* Select all the '*'s on the filter page. */
2406  gtk_font_selection_reset_filter(NULL, fontsel);
2407 
2408  /* Update the main notebook page. */
2409  gtk_widget_set_sensitive(fontsel->filter_button, FALSE);
2410  gtk_label_set_text(GTK_LABEL(fontsel->font_label), _("Font:"));
2411 
2412  gtk_font_selection_show_available_fonts(fontsel);
2413}
2414 
2415 
2416void
2417gtk_font_selection_set_filter   (GtkFontSelection *fontsel,
2418                                 GtkFontFilterType filter_type,
2419                                 GtkFontType       font_type,
2420                                 gchar           **foundries,
2421                                 gchar           **weights,
2422                                 gchar           **slants,
2423                                 gchar           **setwidths,
2424                                 gchar           **spacings,
2425                                 gchar           **charsets)
2426{
2427  GtkFontFilter *filter;
2428  gchar **filter_strings [GTK_NUM_FONT_PROPERTIES];
2429  gchar *filter_string;
2430  gchar *property, *property_alt;
2431  gint prop, nfilters, i, j, num_found;
2432  gint base_font_type, user_font_type;
2433  gboolean filter_set;
2434
2435  /* Put them into an array so we can use a simple loop. */
2436  filter_strings[FOUNDRY]   = foundries;
2437  filter_strings[WEIGHT]    = weights;
2438  filter_strings[SLANT]     = slants;
2439  filter_strings[SET_WIDTH] = setwidths;
2440  filter_strings[SPACING]   = spacings;
2441  filter_strings[CHARSET]   = charsets;
2442
2443  filter = &fontsel->filters[filter_type];
2444  filter->font_type = font_type;
2445     
2446  /* Free the old filter data, and insert the new. */
2447  for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2448    {
2449      g_free(filter->property_filters[prop]);
2450      filter->property_filters[prop] = NULL;
2451      filter->property_nfilters[prop] = 0;
2452     
2453      if (filter_strings[prop])
2454        {
2455          /* Count how many items in the new array. */
2456          nfilters = 0;
2457          while (filter_strings[prop][nfilters])
2458            nfilters++;
2459
2460          filter->property_filters[prop] = g_new(guint16, nfilters);
2461          filter->property_nfilters[prop] = 0;
2462
2463          /* Now convert the strings to property indices. */
2464          num_found = 0;
2465          for (i = 0; i < nfilters; i++)
2466            {
2467              filter_string = filter_strings[prop][i];
2468              for (j = 0; j < fontsel_info->nproperties[prop]; j++)
2469                {
2470                  property = _(fontsel_info->properties[prop][j]);
2471                  property_alt = NULL;
2472                  if (prop == SLANT)
2473                    property_alt = gtk_font_selection_expand_slant_code(property);
2474                  else if (prop == SPACING)
2475                    property_alt = gtk_font_selection_expand_spacing_code(property);
2476                  if (!strcmp (filter_string, property)
2477                      || (property_alt && !strcmp (filter_string, property_alt)))
2478                    {
2479                      filter->property_filters[prop][num_found] = j;
2480                      num_found++;
2481                      break;
2482                    }
2483                }
2484            }
2485          filter->property_nfilters[prop] = num_found;
2486        }
2487    }
2488
2489  /* Now set the clists on the filter page according to the new filter. */
2490  gtk_font_selection_update_filter_lists (fontsel);
2491
2492  if (filter_type == GTK_FONT_FILTER_BASE)
2493    {
2494      user_font_type = fontsel->filters[GTK_FONT_FILTER_USER].font_type;
2495      if (font_type & GTK_FONT_BITMAP)
2496        {
2497          gtk_widget_set_sensitive (fontsel->type_bitmaps_button, TRUE);
2498          gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), user_font_type & GTK_FONT_BITMAP);
2499        }
2500      else
2501        {
2502          gtk_widget_set_sensitive (fontsel->type_bitmaps_button, FALSE);
2503          gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), FALSE);
2504        }
2505     
2506      if (font_type & GTK_FONT_SCALABLE)
2507        {
2508          gtk_widget_set_sensitive (fontsel->type_scalable_button, TRUE);
2509          gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), user_font_type & GTK_FONT_SCALABLE);
2510        }
2511      else
2512        {
2513          gtk_widget_set_sensitive (fontsel->type_scalable_button, FALSE);
2514          gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), FALSE);
2515        }
2516
2517      if (font_type & GTK_FONT_SCALABLE_BITMAP)
2518        {
2519          gtk_widget_set_sensitive (fontsel->type_scaled_bitmaps_button, TRUE);
2520          gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), user_font_type & GTK_FONT_SCALABLE_BITMAP);
2521        }
2522      else
2523        {
2524          gtk_widget_set_sensitive (fontsel->type_scaled_bitmaps_button, FALSE);
2525          gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), FALSE);
2526        }
2527    }
2528  else
2529    {
2530      base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type;
2531      if (base_font_type & GTK_FONT_BITMAP)
2532        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), font_type & GTK_FONT_BITMAP);
2533
2534      if (base_font_type & GTK_FONT_SCALABLE)
2535        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), font_type & GTK_FONT_SCALABLE);
2536
2537      if (base_font_type & GTK_FONT_SCALABLE_BITMAP)
2538        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), font_type & GTK_FONT_SCALABLE_BITMAP);
2539
2540      /* If the user filter is not the default, make the 'Reset Filter' button
2541         sensitive. */
2542      filter_set = FALSE;
2543      if (font_type != (GTK_FONT_BITMAP | GTK_FONT_SCALABLE))
2544        filter_set = TRUE;
2545      for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2546        {
2547          if (filter->property_nfilters[prop] != 0)
2548            filter_set = TRUE;
2549        }
2550      if (filter_set)
2551        gtk_widget_set_sensitive (fontsel->filter_button, TRUE);
2552    }
2553
2554  gtk_font_selection_show_available_fonts (fontsel);
2555}
2556
2557
2558/* This sets the colour of each property in the filter clists according to
2559   the base filter. i.e. Filtered properties are shown as insensitive. */
2560static void
2561gtk_font_selection_update_filter_lists (GtkFontSelection *fontsel)
2562{
2563  GtkWidget *clist;
2564  GdkColor *inactive_fg, *inactive_bg, *fg, *bg;
2565  gint prop, row, index;
2566
2567  /* We have to make sure the clist is realized to use the colours. */
2568  for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2569    {
2570      clist = fontsel->filter_clists[prop];
2571      gtk_widget_realize (clist);
2572      inactive_fg = &clist->style->fg[GTK_STATE_INSENSITIVE];
2573      inactive_bg = &clist->style->bg[GTK_STATE_INSENSITIVE];
2574      for (row = 1; row < GTK_CLIST(clist)->rows; row++)
2575        {
2576          index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(clist),
2577                                                           row));
2578          /* Set the colour according to the base filter. */
2579          if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_BASE,
2580                                               prop, index) == NOT_FILTERED)
2581            {
2582              fg = inactive_fg;
2583              bg = inactive_bg;
2584            }
2585          else
2586            {
2587              fg = NULL;
2588              bg = NULL;
2589            }
2590          gtk_clist_set_foreground(GTK_CLIST(clist), row, fg);
2591          gtk_clist_set_background(GTK_CLIST(clist), row, bg);
2592
2593          /* Set the selection state according to the user filter. */
2594          if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_USER,
2595                                               prop, index) == FILTERED
2596              && fg == NULL)
2597            gtk_clist_select_row (GTK_CLIST (clist), row, 0);
2598          else
2599            gtk_clist_unselect_row (GTK_CLIST (clist), row, 0);
2600        }
2601    }
2602}
2603
2604
2605/* Returns whether a property value is in the filter or not, or if the
2606   property has no filter set. */
2607static GtkFontPropertyFilterState
2608gtk_font_selection_filter_state (GtkFontSelection *fontsel,
2609                                 GtkFontFilterType filter_type,
2610                                 gint             property,
2611                                 gint             index)
2612{
2613  GtkFontFilter *filter;
2614  gint i;
2615
2616  filter = &fontsel->filters[filter_type];
2617  if (filter->property_nfilters[property] == 0)
2618    return NOT_SET;
2619
2620  for (i = 0; i < filter->property_nfilters[property]; i++)
2621    {
2622      if (filter->property_filters[property][i] == index)
2623        return FILTERED;
2624    }
2625  return NOT_FILTERED;
2626}
2627
2628
2629/*****************************************************************************
2630 * These functions all deal with creating the main class arrays containing
2631 * the data about all available fonts.
2632 *****************************************************************************/
2633static void
2634gtk_font_selection_get_fonts (void)
2635{
2636  gchar **xfontnames;
2637  GSList **fontnames;
2638  gchar *fontname;
2639  GSList * temp_list;
2640  gint num_fonts;
2641  gint i, prop, style, size;
2642  gint npixel_sizes = 0, npoint_sizes = 0;
2643  FontInfo *font;
2644  FontStyle *current_style, *prev_style, *tmp_style;
2645  gboolean matched_style, found_size;
2646  gint pixels, points, res_x, res_y;
2647  gchar field_buffer[XLFD_MAX_FIELD_LEN];
2648  gchar *field;
2649  guint8 flags;
2650  guint16 *pixel_sizes, *point_sizes, *tmp_sizes;
2651 
2652  fontsel_info = g_new (GtkFontSelInfo, 1);
2653 
2654  /* Get a maximum of MAX_FONTS fontnames from the X server.
2655     Use "-*" as the pattern rather than "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" since
2656     the latter may result in fonts being returned which don't actually exist.
2657     xlsfonts also uses "*" so I think it's OK. "-*" gets rid of aliases. */
2658  xfontnames = XListFonts (GDK_DISPLAY(), "-*", MAX_FONTS, &num_fonts);
2659  /* Output a warning if we actually get MAX_FONTS fonts. */
2660  if (num_fonts == MAX_FONTS)
2661    g_warning(_("MAX_FONTS exceeded. Some fonts may be missing."));
2662 
2663  /* The maximum size of all these tables is the number of font names
2664     returned. We realloc them later when we know exactly how many
2665     unique entries there are. */
2666  fontsel_info->font_info = g_new (FontInfo, num_fonts);
2667  fontsel_info->font_styles = g_new (FontStyle, num_fonts);
2668  fontsel_info->pixel_sizes = g_new (guint16, num_fonts);
2669  fontsel_info->point_sizes = g_new (guint16, num_fonts);
2670 
2671  fontnames = g_new (GSList*, num_fonts);
2672 
2673  /* Create the initial arrays for the property value strings, though they
2674     may be realloc'ed later. Put the wildcard '*' in the first elements. */
2675  for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2676    {
2677      fontsel_info->properties[prop] = g_new(gchar*, PROPERTY_ARRAY_INCREMENT);
2678      fontsel_info->space_allocated[prop] = PROPERTY_ARRAY_INCREMENT;
2679      fontsel_info->nproperties[prop] = 1;
2680      fontsel_info->properties[prop][0] = "*";
2681    }
2682 
2683 
2684  /* Insert the font families into the main table, sorted by family and
2685     foundry (fonts with different foundries are placed in seaparate FontInfos.
2686     All fontnames in each family + foundry are placed into the fontnames
2687     array of lists. */
2688  fontsel_info->nfonts = 0;
2689  for (i = 0; i < num_fonts; i++)
2690    {
2691#ifdef FONTSEL_DEBUG
2692      g_message("%s\n", xfontnames[i]);
2693#endif
2694      if (gtk_font_selection_is_xlfd_font_name (xfontnames[i]))
2695        gtk_font_selection_insert_font (fontnames, &fontsel_info->nfonts, xfontnames[i]);
2696      else
2697        {
2698#ifdef FONTSEL_DEBUG
2699          g_warning("Skipping invalid font: %s", xfontnames[i]);
2700#endif
2701        }
2702    }
2703 
2704 
2705  /* Since many font names will be in the same FontInfo not all of the
2706     allocated FontInfo table will be used, so we will now reallocate it
2707     with the real size. */
2708  fontsel_info->font_info = g_realloc(fontsel_info->font_info,
2709                                      sizeof(FontInfo) * fontsel_info->nfonts);
2710 
2711 
2712  /* Now we work out which choices of weight/slant etc. are valid for each
2713     font. */
2714  fontsel_info->nstyles = 0;
2715  current_style = fontsel_info->font_styles;
2716  for (i = 0; i < fontsel_info->nfonts; i++)
2717    {
2718      font = &fontsel_info->font_info[i];
2719     
2720      /* Use the next free position in the styles array. */
2721      font->style_index = fontsel_info->nstyles;
2722     
2723      /* Now step through each of the fontnames with this family, and create
2724         a style for each fontname. Each style contains the index into the
2725         weights/slants etc. arrays, and a number of pixel/point sizes. */
2726      style = 0;
2727      temp_list = fontnames[i];
2728      while (temp_list)
2729        {
2730          fontname = temp_list->data;
2731          temp_list = temp_list->next;
2732         
2733          for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2734            {
2735              current_style->properties[prop]
2736                = gtk_font_selection_insert_field (fontname, prop);
2737            }
2738          current_style->pixel_sizes_index = npixel_sizes;
2739          current_style->npixel_sizes = 0;
2740          current_style->point_sizes_index = npoint_sizes;
2741          current_style->npoint_sizes = 0;
2742          current_style->flags = 0;
2743         
2744         
2745          field = gtk_font_selection_get_xlfd_field (fontname, XLFD_PIXELS,
2746                                                     field_buffer);
2747          pixels = atoi(field);
2748         
2749          field = gtk_font_selection_get_xlfd_field (fontname, XLFD_POINTS,
2750                                                     field_buffer);
2751          points = atoi(field);
2752         
2753          field = gtk_font_selection_get_xlfd_field (fontname,
2754                                                     XLFD_RESOLUTION_X,
2755                                                     field_buffer);
2756          res_x = atoi(field);
2757         
2758          field = gtk_font_selection_get_xlfd_field (fontname,
2759                                                     XLFD_RESOLUTION_Y,
2760                                                     field_buffer);
2761          res_y = atoi(field);
2762         
2763          if (pixels == 0 && points == 0)
2764            {
2765              if (res_x == 0 && res_y == 0)
2766                flags = GTK_FONT_SCALABLE;
2767              else
2768                flags = GTK_FONT_SCALABLE_BITMAP;
2769            }
2770          else
2771            flags = GTK_FONT_BITMAP;
2772         
2773          /* Now we check to make sure that the style is unique. If it isn't
2774             we forget it. */
2775          prev_style = fontsel_info->font_styles + font->style_index;
2776          matched_style = FALSE;
2777          while (prev_style < current_style)
2778            {
2779              matched_style = TRUE;
2780              for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2781                {
2782                  if (prev_style->properties[prop]
2783                      != current_style->properties[prop])
2784                    {
2785                      matched_style = FALSE;
2786                      break;
2787                    }
2788                }
2789              if (matched_style)
2790                break;
2791              prev_style++;
2792            }
2793         
2794          /* If we matched an existing style, we need to add the pixels &
2795             point sizes to the style. If not, we insert the pixel & point
2796             sizes into our new style. Note that we don't add sizes for
2797             scalable fonts. */
2798          if (matched_style)
2799            {
2800              prev_style->flags |= flags;
2801              if (flags == GTK_FONT_BITMAP)
2802                {
2803                  pixel_sizes = fontsel_info->pixel_sizes
2804                    + prev_style->pixel_sizes_index;
2805                  found_size = FALSE;
2806                  for (size = 0; size < prev_style->npixel_sizes; size++)
2807                    {
2808                      if (pixels == *pixel_sizes)
2809                        {
2810                          found_size = TRUE;
2811                          break;
2812                        }
2813                      else if (pixels < *pixel_sizes)
2814                        break;
2815                      pixel_sizes++;
2816                    }
2817                  /* We need to move all the following pixel sizes up, and also
2818                     update the indexes of any following styles. */
2819                  if (!found_size)
2820                    {
2821                      for (tmp_sizes = fontsel_info->pixel_sizes + npixel_sizes;
2822                           tmp_sizes > pixel_sizes; tmp_sizes--)
2823                        *tmp_sizes = *(tmp_sizes - 1);
2824                     
2825                      *pixel_sizes = pixels;
2826                      npixel_sizes++;
2827                      prev_style->npixel_sizes++;
2828                     
2829                      tmp_style = prev_style + 1;
2830                      while (tmp_style < current_style)
2831                        {
2832                          tmp_style->pixel_sizes_index++;
2833                          tmp_style++;
2834                        }
2835                    }
2836                 
2837                  point_sizes = fontsel_info->point_sizes
2838                    + prev_style->point_sizes_index;
2839                  found_size = FALSE;
2840                  for (size = 0; size < prev_style->npoint_sizes; size++)
2841                    {
2842                      if (points == *point_sizes)
2843                        {
2844                          found_size = TRUE;
2845                          break;
2846                        }
2847                      else if (points < *point_sizes)
2848                        break;
2849                      point_sizes++;
2850                    }
2851                  /* We need to move all the following point sizes up, and also
2852                     update the indexes of any following styles. */
2853                  if (!found_size)
2854                    {
2855                      for (tmp_sizes = fontsel_info->point_sizes + npoint_sizes;
2856                           tmp_sizes > point_sizes; tmp_sizes--)
2857                        *tmp_sizes = *(tmp_sizes - 1);
2858                     
2859                      *point_sizes = points;
2860                      npoint_sizes++;
2861                      prev_style->npoint_sizes++;
2862                     
2863                      tmp_style = prev_style + 1;
2864                      while (tmp_style < current_style)
2865                        {
2866                          tmp_style->point_sizes_index++;
2867                          tmp_style++;
2868                        }
2869                    }
2870                }
2871            }
2872          else
2873            {
2874              current_style->flags = flags;
2875              if (flags == GTK_FONT_BITMAP)
2876                {
2877                  fontsel_info->pixel_sizes[npixel_sizes++] = pixels;
2878                  current_style->npixel_sizes = 1;
2879                  fontsel_info->point_sizes[npoint_sizes++] = points;
2880                  current_style->npoint_sizes = 1;
2881                }
2882              style++;
2883              fontsel_info->nstyles++;
2884              current_style++;
2885            }
2886        }
2887      g_slist_free(fontnames[i]);
2888     
2889      /* Set nstyles to the real value, minus duplicated fontnames.
2890         Note that we aren't using all the allocated memory if fontnames are
2891         duplicated. */
2892      font->nstyles = style;
2893    }
2894 
2895  /* Since some repeated styles may be skipped we won't have used all the
2896     allocated space, so we will now reallocate it with the real size. */
2897  fontsel_info->font_styles = g_realloc(fontsel_info->font_styles,
2898                                        sizeof(FontStyle) * fontsel_info->nstyles);
2899  fontsel_info->pixel_sizes = g_realloc(fontsel_info->pixel_sizes,
2900                                        sizeof(guint16) * npixel_sizes);
2901  fontsel_info->point_sizes = g_realloc(fontsel_info->point_sizes,
2902                                        sizeof(guint16) * npoint_sizes);
2903  g_free(fontnames);
2904  XFreeFontNames (xfontnames);
2905 
2906 
2907  /* Debugging Output */
2908  /* This outputs all FontInfos. */
2909#ifdef FONTSEL_DEBUG
2910  g_message("\n\n Font Family           Weight    Slant     Set Width Spacing   Charset\n\n");
2911  for (i = 0; i < fontsel_info->nfonts; i++)
2912    {
2913      FontInfo *font = &fontsel_info->font_info[i];
2914      FontStyle *styles = fontsel_info->font_styles + font->style_index;
2915      for (style = 0; style < font->nstyles; style++)
2916        {
2917          g_message("%5i %-16.16s ", i, font->family);
2918          for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2919            g_message("%-9.9s ",
2920                      fontsel_info->properties[prop][styles->properties[prop]]);
2921          g_message("\n      ");
2922         
2923          if (styles->flags & GTK_FONT_BITMAP)
2924            g_message("Bitmapped font  ");
2925          if (styles->flags & GTK_FONT_SCALABLE)
2926            g_message("Scalable font  ");
2927          if (styles->flags & GTK_FONT_SCALABLE_BITMAP)
2928            g_message("Scalable-Bitmapped font  ");
2929          g_message("\n");
2930         
2931          if (styles->npixel_sizes)
2932            {
2933              g_message("      Pixel sizes: ");
2934              tmp_sizes = fontsel_info->pixel_sizes + styles->pixel_sizes_index;
2935              for (size = 0; size < styles->npixel_sizes; size++)
2936                g_message("%i ", *tmp_sizes++);
2937              g_message("\n");
2938            }
2939         
2940          if (styles->npoint_sizes)
2941            {
2942              g_message("      Point sizes: ");
2943              tmp_sizes = fontsel_info->point_sizes + styles->point_sizes_index;
2944              for (size = 0; size < styles->npoint_sizes; size++)
2945                g_message("%i ", *tmp_sizes++);
2946              g_message("\n");
2947            }
2948         
2949          g_message("\n");
2950          styles++;
2951        }
2952    }
2953  /* This outputs all available properties. */
2954  for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2955    {
2956      g_message("Property: %s\n", xlfd_field_names[xlfd_index[prop]]);
2957      for (i = 0; i < fontsel_info->nproperties[prop]; i++)
2958        g_message("  %s\n", fontsel_info->properties[prop][i]);
2959    }
2960#endif
2961}
2962
2963/* This inserts the given fontname into the FontInfo table.
2964   If a FontInfo already exists with the same family and foundry, then the
2965   fontname is added to the FontInfos list of fontnames, else a new FontInfo
2966   is created and inserted in alphabetical order in the table. */
2967static void
2968gtk_font_selection_insert_font (GSList                *fontnames[],
2969                                gint                  *ntable,
2970                                gchar                 *fontname)
2971{
2972  FontInfo *table;
2973  FontInfo temp_info;
2974  GSList *temp_fontname;
2975  gchar *family;
2976  gboolean family_exists = FALSE;
2977  gint foundry;
2978  gint lower, upper;
2979  gint middle, cmp;
2980  gchar family_buffer[XLFD_MAX_FIELD_LEN];
2981 
2982  table = fontsel_info->font_info;
2983 
2984  /* insert a fontname into a table */
2985  family = gtk_font_selection_get_xlfd_field (fontname, XLFD_FAMILY,
2986                                              family_buffer);
2987  if (!family)
2988    return;
2989 
2990  foundry = gtk_font_selection_insert_field (fontname, FOUNDRY);
2991 
2992  lower = 0;
2993  if (*ntable > 0)
2994    {
2995      /* Do a binary search to determine if we have already encountered
2996       *  a font with this family & foundry. */
2997      upper = *ntable;
2998      while (lower < upper)
2999        {
3000          middle = (lower + upper) >> 1;
3001         
3002          cmp = strcmp (family, table[middle].family);
3003          /* If the family matches we sort by the foundry. */
3004          if (cmp == 0)
3005            {
3006              family_exists = TRUE;
3007              family = table[middle].family;
3008              cmp = strcmp(fontsel_info->properties[FOUNDRY][foundry],
3009                           fontsel_info->properties[FOUNDRY][table[middle].foundry]);
3010            }
3011         
3012          if (cmp == 0)
3013            {
3014              fontnames[middle] = g_slist_prepend (fontnames[middle],
3015                                                   fontname);
3016              return;
3017            }
3018          else if (cmp < 0)
3019            upper = middle;
3020          else
3021            lower = middle+1;
3022        }
3023    }
3024 
3025  /* Add another entry to the table for this new font family */
3026  temp_info.family = family_exists ? family : g_strdup(family);
3027  temp_info.foundry = foundry;
3028  temp_fontname = g_slist_prepend (NULL, fontname);
3029 
3030  (*ntable)++;
3031 
3032  /* Quickly insert the entry into the table in sorted order
3033   *  using a modification of insertion sort and the knowledge
3034   *  that the entries proper position in the table was determined
3035   *  above in the binary search and is contained in the "lower"
3036   *  variable. */
3037  if (*ntable > 1)
3038    {
3039      upper = *ntable - 1;
3040      while (lower != upper)
3041        {
3042          table[upper] = table[upper-1];
3043          fontnames[upper] = fontnames[upper-1];
3044          upper--;
3045        }
3046    }
3047  table[lower] = temp_info;
3048  fontnames[lower] = temp_fontname;
3049}
3050
3051
3052/* This checks that the specified field of the given fontname is in the
3053   appropriate properties array. If not it is added. Thus eventually we get
3054   arrays of all possible weights/slants etc. It returns the array index. */
3055static gint
3056gtk_font_selection_insert_field (gchar                 *fontname,
3057                                 gint                   prop)
3058{
3059  gchar field_buffer[XLFD_MAX_FIELD_LEN];
3060  gchar *field;
3061  guint16 index;
3062 
3063  field = gtk_font_selection_get_xlfd_field (fontname, xlfd_index[prop],
3064                                             field_buffer);
3065  if (!field)
3066    return 0;
3067 
3068  /* If the field is already in the array just return its index. */
3069  for (index = 0; index < fontsel_info->nproperties[prop]; index++)
3070    if (!strcmp(field, fontsel_info->properties[prop][index]))
3071      return index;
3072 
3073  /* Make sure we have enough space to add the field. */
3074  if (fontsel_info->nproperties[prop] == fontsel_info->space_allocated[prop])
3075    {
3076      fontsel_info->space_allocated[prop] += PROPERTY_ARRAY_INCREMENT;
3077      fontsel_info->properties[prop] = g_realloc(fontsel_info->properties[prop],
3078                                                 sizeof(gchar*)
3079                                                 * fontsel_info->space_allocated[prop]);
3080    }
3081 
3082  /* Add the new field. */
3083  index = fontsel_info->nproperties[prop];
3084  fontsel_info->properties[prop][index] = g_strdup(field);
3085  fontsel_info->nproperties[prop]++;
3086  return index;
3087}
3088
3089
3090/*****************************************************************************
3091 * These functions are the main public interface for getting/setting the font.
3092 *****************************************************************************/
3093
3094GdkFont*
3095gtk_font_selection_get_font (GtkFontSelection *fontsel)
3096{
3097  g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
3098
3099  gtk_font_selection_update_size (fontsel);
3100 
3101  return fontsel->font;
3102}
3103
3104
3105gchar *
3106gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
3107{
3108  FontInfo *font;
3109  gchar *family_str, *foundry_str;
3110  gchar *property_str[GTK_NUM_STYLE_PROPERTIES];
3111  gint prop;
3112 
3113  g_return_val_if_fail (fontsel != NULL, NULL);
3114  g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
3115 
3116  gtk_font_selection_update_size (fontsel);
3117 
3118  /* If no family has been selected return NULL. */
3119  if (fontsel->font_index == -1)
3120    return NULL;
3121 
3122  font = &fontsel_info->font_info[fontsel->font_index];
3123  family_str = font->family;
3124  foundry_str = fontsel_info->properties[FOUNDRY][font->foundry];
3125  /* some fonts have a (nil) foundry */
3126  if (strcmp (foundry_str, "(nil)") == 0)
3127    foundry_str = "";
3128   
3129  for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
3130    {
3131      property_str[prop] = fontsel_info->properties[prop][fontsel->property_values[prop]];
3132      if (strcmp (property_str[prop], "(nil)") == 0)
3133        property_str[prop] = "";
3134    }
3135 
3136  return gtk_font_selection_create_xlfd (fontsel->size,
3137                                         fontsel->metric,
3138                                         foundry_str,
3139                                         family_str,
3140                                         property_str[WEIGHT],
3141                                         property_str[SLANT],
3142                                         property_str[SET_WIDTH],
3143                                         property_str[SPACING],
3144                                         property_str[CHARSET]);
3145}
3146
3147
3148/* This sets the current font, selecting the appropriate clist rows.
3149   First we check the fontname is valid and try to find the font family
3150   - i.e. the name in the main list. If we can't find that, then just return.
3151   Next we try to set each of the properties according to the fontname.
3152   Finally we select the font family & style in the clists. */
3153gboolean
3154gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
3155                                  const gchar      *fontname)
3156{
3157  gchar *family, *field;
3158  gint index, prop, size, row;
3159  guint16 foundry, value;
3160  gchar family_buffer[XLFD_MAX_FIELD_LEN];
3161  gchar field_buffer[XLFD_MAX_FIELD_LEN];
3162  gchar buffer[16];
3163 
3164  g_return_val_if_fail (fontsel != NULL, FALSE);
3165  g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
3166  g_return_val_if_fail (fontname != NULL, FALSE);
3167 
3168  /* Check it is a valid fontname. */
3169  if (!gtk_font_selection_is_xlfd_font_name(fontname))
3170    return FALSE;
3171 
3172  family = gtk_font_selection_get_xlfd_field (fontname, XLFD_FAMILY,
3173                                              family_buffer);
3174  if (!family)
3175    return FALSE;
3176 
3177  field = gtk_font_selection_get_xlfd_field (fontname, XLFD_FOUNDRY,
3178                                             field_buffer);
3179  foundry = gtk_font_selection_field_to_index (fontsel_info->properties[FOUNDRY],
3180                                               fontsel_info->nproperties[FOUNDRY],
3181                                               field);
3182 
3183  index = gtk_font_selection_find_font(fontsel, family, foundry);
3184  if (index == -1)
3185    return FALSE;
3186 
3187  /* Convert the property fields into indices and set them. */
3188  for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
3189    {
3190      field = gtk_font_selection_get_xlfd_field (fontname, xlfd_index[prop],
3191                                                 field_buffer);
3192      value = gtk_font_selection_field_to_index (fontsel_info->properties[prop],
3193                                                 fontsel_info->nproperties[prop],
3194                                                 field);
3195      fontsel->property_values[prop] = value;
3196    }
3197 
3198  field = gtk_font_selection_get_xlfd_field (fontname, XLFD_POINTS,
3199                                             field_buffer);
3200  size = atoi(field);
3201  if (size > 0)
3202    {
3203      if (size < 20)
3204        size = 20;
3205      fontsel->size = fontsel->selected_size = size;
3206      fontsel->metric = GTK_FONT_METRIC_POINTS;
3207      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fontsel->points_button),
3208                                  TRUE);
3209      if (size % 10 == 0)
3210        sprintf (buffer, "%i", size / 10);
3211      else
3212        sprintf (buffer, "%i.%i", size / 10, size % 10);
3213    }
3214  else
3215    {
3216      field = gtk_font_selection_get_xlfd_field (fontname, XLFD_PIXELS,
3217                                                 field_buffer);
3218      size = atoi(field);
3219      if (size < 2)
3220        size = 2;
3221      fontsel->size = fontsel->selected_size = size;
3222      fontsel->metric = GTK_FONT_METRIC_PIXELS;
3223      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fontsel->pixels_button),
3224                                  TRUE);
3225      sprintf (buffer, "%i", size);
3226    }
3227  gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
3228 
3229  /* Clear any current filter. */
3230  gtk_font_selection_clear_filter(fontsel);
3231 
3232  /* Now find the best style match. */
3233  fontsel->font_index = index;
3234  row = gtk_clist_find_row_from_data (GTK_CLIST (fontsel->font_clist),
3235                                      GINT_TO_POINTER (index));
3236  if (row != -1)
3237    {
3238      gtk_clist_select_row (GTK_CLIST (fontsel->font_clist), row, 0);
3239      if (GTK_WIDGET_MAPPED (fontsel->font_clist))
3240        gtk_clist_moveto (GTK_CLIST (fontsel->font_clist), row, -1, 0.5, 0);
3241    }
3242 
3243  gtk_font_selection_show_available_styles (fontsel);
3244  /* This will load the font. */
3245  gtk_font_selection_select_best_style (fontsel, FALSE);
3246 
3247  return TRUE;
3248}
3249
3250
3251/* Returns the index of the given family, or -1 if not found */
3252static gint
3253gtk_font_selection_find_font (GtkFontSelection *fontsel,
3254                              gchar            *family,
3255                              guint16           foundry)
3256{
3257  FontInfo *font_info;
3258  gint lower, upper, middle = -1, cmp, nfonts;
3259  gint found_family = -1;
3260 
3261  font_info = fontsel_info->font_info;
3262  nfonts = fontsel_info->nfonts;
3263  if (nfonts == 0)
3264    return -1;
3265 
3266  /* Do a binary search to find the font family. */
3267  lower = 0;
3268  upper = nfonts;
3269  while (lower < upper)
3270    {
3271      middle = (lower + upper) >> 1;
3272     
3273      cmp = strcmp (family, font_info[middle].family);
3274      if (cmp == 0)
3275        {
3276          found_family = middle;
3277          cmp = strcmp(fontsel_info->properties[FOUNDRY][foundry],
3278                       fontsel_info->properties[FOUNDRY][font_info[middle].foundry]);
3279        }
3280
3281      if (cmp == 0)
3282        return middle;
3283      else if (cmp < 0)
3284        upper = middle;
3285      else if (cmp > 0)
3286        lower = middle+1;
3287    }
3288 
3289  /* We couldn't find the family and foundry, but we may have just found the
3290     family, so we return that. */
3291  return found_family;
3292}
3293
3294
3295/* This returns the text in the preview entry. You should copy the returned
3296   text if you need it. */
3297gchar*
3298gtk_font_selection_get_preview_text  (GtkFontSelection *fontsel)
3299{
3300  return gtk_entry_get_text(GTK_ENTRY(fontsel->preview_entry));
3301}
3302
3303
3304/* This sets the text in the preview entry. */
3305void
3306gtk_font_selection_set_preview_text  (GtkFontSelection *fontsel,
3307                                      const gchar         *text)
3308{
3309  gtk_entry_set_text(GTK_ENTRY(fontsel->preview_entry), text);
3310}
3311
3312
3313/*****************************************************************************
3314 * These functions all deal with X Logical Font Description (XLFD) fontnames.
3315 * See the freely available documentation about this.
3316 *****************************************************************************/
3317
3318/*
3319 * Returns TRUE if the fontname is a valid XLFD.
3320 * (It just checks if the number of dashes is 14, and that each
3321 * field < XLFD_MAX_FIELD_LEN  characters long - that's not in the XLFD but it
3322 * makes it easier for me).
3323 */
3324static gboolean
3325gtk_font_selection_is_xlfd_font_name (const gchar *fontname)
3326{
3327  gint i = 0;
3328  gint field_len = 0;
3329 
3330  while (*fontname)
3331    {
3332      if (*fontname++ == '-')
3333        {
3334          if (field_len > XLFD_MAX_FIELD_LEN) return FALSE;
3335          field_len = 0;
3336          i++;
3337        }
3338      else
3339        field_len++;
3340    }
3341 
3342  return (i == 14) ? TRUE : FALSE;
3343}
3344
3345/*
3346 * This fills the buffer with the specified field from the X Logical Font
3347 * Description name, and returns it. If fontname is NULL or the field is
3348 * longer than XFLD_MAX_FIELD_LEN it returns NULL.
3349 * Note: For the charset field, we also return the encoding, e.g. 'iso8859-1'.
3350 */
3351static gchar*
3352gtk_font_selection_get_xlfd_field (const gchar *fontname,
3353                                   FontField    field_num,
3354                                   gchar       *buffer)
3355{
3356  const gchar *t1, *t2;
3357  gint countdown, len, num_dashes;
3358 
3359  if (!fontname)
3360    return NULL;
3361 
3362  /* we assume this is a valid fontname...that is, it has 14 fields */
3363 
3364  countdown = field_num;
3365  t1 = fontname;
3366  while (*t1 && (countdown >= 0))
3367    if (*t1++ == '-')
3368      countdown--;
3369 
3370  num_dashes = (field_num == XLFD_CHARSET) ? 2 : 1;
3371  for (t2 = t1; *t2; t2++)
3372    {
3373      if (*t2 == '-' && --num_dashes == 0)
3374        break;
3375    }
3376 
3377  if (t1 != t2)
3378    {
3379      /* Check we don't overflow the buffer */
3380      len = (long) t2 - (long) t1;
3381      if (len > XLFD_MAX_FIELD_LEN - 1)
3382        return NULL;
3383      strncpy (buffer, t1, len);
3384      buffer[len] = 0;
3385
3386      /* Convert to lower case. */
3387      g_strdown (buffer);
3388    }
3389  else
3390    strcpy(buffer, "(nil)");
3391 
3392  return buffer;
3393}
3394
3395/*
3396 * This returns a X Logical Font Description font name, given all the pieces.
3397 * Note: this retval must be freed by the caller.
3398 */
3399static gchar *
3400gtk_font_selection_create_xlfd (gint              size,
3401                                GtkFontMetricType metric,
3402                                gchar             *foundry,
3403                                gchar             *family,
3404                                gchar             *weight,
3405                                gchar             *slant,
3406                                gchar             *set_width,
3407                                gchar             *spacing,
3408                                gchar             *charset)
3409{
3410  gchar buffer[16];
3411  gchar *pixel_size = "*", *point_size = "*", *fontname;
3412 
3413  if (size <= 0)
3414    return NULL;
3415 
3416  sprintf (buffer, "%d", (int) size);
3417  if (metric == GTK_FONT_METRIC_PIXELS)
3418    pixel_size = buffer;
3419  else
3420    point_size = buffer;
3421 
3422  fontname = g_strdup_printf("-%s-%s-%s-%s-%s-*-%s-%s-*-*-%s-*-%s",
3423                             foundry, family, weight, slant, set_width,
3424                             pixel_size, point_size, spacing, charset);
3425  return fontname;
3426}
3427
3428
3429
3430/*****************************************************************************
3431 * GtkFontSelectionDialog
3432 *****************************************************************************/
3433
3434guint
3435gtk_font_selection_dialog_get_type (void)
3436{
3437  static guint font_selection_dialog_type = 0;
3438 
3439  if (!font_selection_dialog_type)
3440    {
3441      GtkTypeInfo fontsel_diag_info =
3442      {
3443        "GtkFontSelectionDialog",
3444        sizeof (GtkFontSelectionDialog),
3445        sizeof (GtkFontSelectionDialogClass),
3446        (GtkClassInitFunc) gtk_font_selection_dialog_class_init,
3447        (GtkObjectInitFunc) gtk_font_selection_dialog_init,
3448        /* reserved_1 */ NULL,
3449        /* reserved_2 */ NULL,
3450        (GtkClassInitFunc) NULL,
3451      };
3452     
3453      font_selection_dialog_type = gtk_type_unique (GTK_TYPE_WINDOW, &fontsel_diag_info);
3454    }
3455 
3456  return font_selection_dialog_type;
3457}
3458
3459static void
3460gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
3461{
3462  GtkObjectClass *object_class;
3463 
3464  object_class = (GtkObjectClass*) klass;
3465 
3466  font_selection_dialog_parent_class = gtk_type_class (GTK_TYPE_WINDOW);
3467}
3468
3469static void
3470gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
3471{
3472  fontseldiag->dialog_width = -1;
3473  fontseldiag->auto_resize = TRUE;
3474 
3475  gtk_widget_set_events(GTK_WIDGET(fontseldiag), GDK_STRUCTURE_MASK);
3476  gtk_signal_connect (GTK_OBJECT (fontseldiag), "configure_event",
3477                      (GtkSignalFunc) gtk_font_selection_dialog_on_configure,
3478                      fontseldiag);
3479 
3480  gtk_container_set_border_width (GTK_CONTAINER (fontseldiag), 4);
3481  gtk_window_set_policy(GTK_WINDOW(fontseldiag), FALSE, TRUE, TRUE);
3482 
3483  fontseldiag->main_vbox = gtk_vbox_new (FALSE, 4);
3484  gtk_widget_show (fontseldiag->main_vbox);
3485  gtk_container_add (GTK_CONTAINER (fontseldiag), fontseldiag->main_vbox);
3486 
3487  fontseldiag->fontsel = gtk_font_selection_new();
3488  gtk_widget_show (fontseldiag->fontsel);
3489  gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
3490                      fontseldiag->fontsel, TRUE, TRUE, 0);
3491 
3492  /* Create the action area */
3493  fontseldiag->action_area = gtk_hbutton_box_new ();
3494  gtk_button_box_set_layout(GTK_BUTTON_BOX(fontseldiag->action_area),
3495                            GTK_BUTTONBOX_END);
3496  gtk_button_box_set_spacing(GTK_BUTTON_BOX(fontseldiag->action_area), 5);
3497  gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
3498                      fontseldiag->action_area, FALSE, FALSE, 0);
3499  gtk_widget_show (fontseldiag->action_area);
3500 
3501  fontseldiag->ok_button = gtk_button_new_with_label(_("OK"));
3502  GTK_WIDGET_SET_FLAGS (fontseldiag->ok_button, GTK_CAN_DEFAULT);
3503  gtk_widget_show(fontseldiag->ok_button);
3504  gtk_box_pack_start (GTK_BOX (fontseldiag->action_area),
3505                      fontseldiag->ok_button, TRUE, TRUE, 0);
3506  gtk_widget_grab_default (fontseldiag->ok_button);
3507 
3508  fontseldiag->apply_button = gtk_button_new_with_label(_("Apply"));
3509  GTK_WIDGET_SET_FLAGS (fontseldiag->apply_button, GTK_CAN_DEFAULT);
3510  /*gtk_widget_show(fontseldiag->apply_button);*/
3511  gtk_box_pack_start (GTK_BOX(fontseldiag->action_area),
3512                      fontseldiag->apply_button, TRUE, TRUE, 0);
3513 
3514  fontseldiag->cancel_button = gtk_button_new_with_label(_("Cancel"));
3515  GTK_WIDGET_SET_FLAGS (fontseldiag->cancel_button, GTK_CAN_DEFAULT);
3516  gtk_widget_show(fontseldiag->cancel_button);
3517  gtk_box_pack_start (GTK_BOX(fontseldiag->action_area),
3518                      fontseldiag->cancel_button, TRUE, TRUE, 0);
3519 
3520 
3521}
3522
3523GtkWidget*
3524gtk_font_selection_dialog_new   (const gchar      *title)
3525{
3526  GtkFontSelectionDialog *fontseldiag;
3527 
3528  fontseldiag = gtk_type_new (GTK_TYPE_FONT_SELECTION_DIALOG);
3529  gtk_window_set_title (GTK_WINDOW (fontseldiag),
3530                        title ? title : _("Font Selection"));
3531 
3532  return GTK_WIDGET (fontseldiag);
3533}
3534
3535gchar*
3536gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
3537{
3538  return gtk_font_selection_get_font_name(GTK_FONT_SELECTION(fsd->fontsel));
3539}
3540
3541GdkFont*
3542gtk_font_selection_dialog_get_font      (GtkFontSelectionDialog *fsd)
3543{
3544  return gtk_font_selection_get_font(GTK_FONT_SELECTION(fsd->fontsel));
3545}
3546
3547gboolean
3548gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
3549                                         const gchar      *fontname)
3550{
3551  return gtk_font_selection_set_font_name(GTK_FONT_SELECTION(fsd->fontsel),
3552                                          fontname);
3553}
3554
3555void
3556gtk_font_selection_dialog_set_filter    (GtkFontSelectionDialog *fsd,
3557                                         GtkFontFilterType filter_type,
3558                                         GtkFontType       font_type,
3559                                         gchar           **foundries,
3560                                         gchar           **weights,
3561                                         gchar           **slants,
3562                                         gchar           **setwidths,
3563                                         gchar           **spacings,
3564                                         gchar           **charsets)
3565{
3566  gtk_font_selection_set_filter (GTK_FONT_SELECTION (fsd->fontsel),
3567                                 filter_type, font_type,
3568                                 foundries, weights, slants, setwidths,
3569                                 spacings, charsets);
3570}
3571
3572gchar*
3573gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
3574{
3575  return gtk_font_selection_get_preview_text(GTK_FONT_SELECTION(fsd->fontsel));
3576}
3577
3578void
3579gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
3580                                            const gchar   *text)
3581{
3582  gtk_font_selection_set_preview_text(GTK_FONT_SELECTION(fsd->fontsel), text);
3583}
3584
3585
3586/* This turns auto-shrink off if the user resizes the width of the dialog.
3587   It also turns it back on again if the user resizes it back to its normal
3588   width. */
3589static gint
3590gtk_font_selection_dialog_on_configure (GtkWidget         *widget,
3591                                        GdkEventConfigure *event,
3592                                        GtkFontSelectionDialog *fsd)
3593{
3594  /* This sets the initial width. */
3595  if (fsd->dialog_width == -1)
3596    fsd->dialog_width = event->width;
3597  else if (fsd->auto_resize && fsd->dialog_width != event->width)
3598    {
3599      fsd->auto_resize = FALSE;
3600      gtk_window_set_policy(GTK_WINDOW(fsd), FALSE, TRUE, FALSE);
3601    }
3602  else if (!fsd->auto_resize && fsd->dialog_width == event->width)
3603    {
3604      fsd->auto_resize = TRUE;
3605      gtk_window_set_policy(GTK_WINDOW(fsd), FALSE, TRUE, TRUE);
3606    }
3607 
3608  return FALSE;
3609}
Note: See TracBrowser for help on using the repository browser.