gtkfontsel.c 112 KB
Newer Older
Owen Taylor's avatar
Owen Taylor committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
/* GTK - The GIMP Toolkit
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * GtkFontSelection widget for Gtk+, by Damon Chaplin, May 1998.
 * Based on the GnomeFontSelector widget, by Elliot Lee, but major changes.
 * The GnomeFontSelector was derived from app/text_tool.c in the GIMP.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
 * Limits:
 *
 *  Fontnames	 - A maximum of MAX_FONTS (32767) fontnames will be retrieved
 *		   from X Windows with XListFonts(). Any more are ignored.
 *		   I think this limit may have been set because of a limit in
 *		   GtkList. It could possibly be increased since we are using
 *		   GtkClists now, but I'd be surprised if it was reached.
 *  Field length - XLFD_MAX_FIELD_LEN is the maximum length that any field of a
 *		   fontname can be for it to be considered valid. Others are
 *		   ignored.
 *  Properties   - Maximum of 65535 choices for each font property - guint16's
 *		   are used as indices, e.g. in the FontInfo struct.
 *  Combinations - Maximum of 65535 combinations of properties for each font
 *		   family - a guint16 is used in the FontInfo struct.
 *  Font size    - Minimum font size of 2 pixels/points, since trying to load
 *		   some fonts with a size of 1 can cause X to hang.
 *		   (e.g. the Misc Fixed fonts).
 */

/*
 * Possible Improvements:
 *
 *  Font Styles  - could sort the styles into a reasonable order - regular
48
 *		   first, then bold, bold italic etc.
Owen Taylor's avatar
Owen Taylor committed
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
 *
 *  I18N	 - the default preview text is not useful for international
 *		   fonts. Maybe the first few characters of the font could be
 *		   displayed instead.
 *		 - fontsets? should these be handled by the font dialog?
 */

/*
 * Debugging: compile with -DFONTSEL_DEBUG for lots of debugging output.
 */


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <X11/Xlib.h>

#include "gdk/gdkx.h"
#include "gdk/gdkkeysyms.h"

#include "gtkbutton.h"
71
#include "gtkcheckbutton.h"
Owen Taylor's avatar
Owen Taylor committed
72 73 74 75 76 77 78 79 80 81 82 83
#include "gtkclist.h"
#include "gtkentry.h"
#include "gtkfontsel.h"
#include "gtkframe.h"
#include "gtkhbbox.h"
#include "gtkhbox.h"
#include "gtklabel.h"
#include "gtknotebook.h"
#include "gtkradiobutton.h"
#include "gtksignal.h"
#include "gtktable.h"
#include "gtkvbox.h"
84
#include "gtkscrolledwindow.h"
Owen Taylor's avatar
Owen Taylor committed
85 86 87 88 89 90 91 92 93 94 95

/* The maximum number of fontnames requested with XListFonts(). */
#define MAX_FONTS 32767

/* This is the largest field length we will accept. If a fontname has a field
   larger than this we will skip it. */
#define XLFD_MAX_FIELD_LEN 64

/* These are what we use as the standard font sizes, for the size clist.
   Note that when using points we still show these integer point values but
   we work internally in decipoints (and decipoint values can be typed in). */
96
static const guint16 font_sizes[] = {
Owen Taylor's avatar
Owen Taylor committed
97 98 99 100 101 102
  8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28,
  32, 36, 40, 48, 56, 64, 72
};

/* Initial font metric & size (Remember point sizes are in decipoints).
   The font size should match one of those in the font_sizes array. */
103
#define INITIAL_METRIC		  GTK_FONT_METRIC_POINTS
Owen Taylor's avatar
Owen Taylor committed
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
#define INITIAL_FONT_SIZE	  140

/* This is the default text shown in the preview entry, though the user
   can set it. Remember that some fonts only have capital letters. */
#define PREVIEW_TEXT "abcdefghijk ABCDEFGHIJK"

/* This is the initial and maximum height of the preview entry (it expands
   when large font sizes are selected). Initial height is also the minimum. */
#define INITIAL_PREVIEW_HEIGHT 44
#define MAX_PREVIEW_HEIGHT 300

/* These are the sizes of the font, style & size clists. */
#define FONT_LIST_HEIGHT	136
#define FONT_LIST_WIDTH		180
#define FONT_STYLE_LIST_WIDTH	160
#define FONT_SIZE_LIST_WIDTH	60

/* This is the number of fields in an X Logical Font Description font name.
   Note that we count the registry & encoding as 1. */
#define GTK_XLFD_NUM_FIELDS 13

125 126 127 128 129 130 131 132 133 134 135 136 137 138
typedef struct _GtkFontSelInfo GtkFontSelInfo;
typedef struct _FontInfo FontInfo;
typedef struct _FontStyle FontStyle;

/* This struct represents one family of fonts (with one foundry), e.g. adobe
   courier or sony fixed. It stores the family name, the index of the foundry
   name, and the index of and number of available styles. */
struct _FontInfo
{
  gchar   *family;
  guint16  foundry;
  gint	   style_index;
  guint16  nstyles;
};
139

140 141
/* This represents one style, as displayed in the Font Style clist. It can
   have a number of available pixel sizes and point sizes. The indexes point
142 143 144 145 146
   into the two big fontsel_info->pixel_sizes & fontsel_info->point_sizes
   arrays. The displayed flag is used when displaying styles to remember which
   styles have already been displayed. Note that it is combined with the
   GtkFontType in the flags field. */
#define  GTK_FONT_DISPLAYED	(1 << 7)
147 148 149 150 151 152 153 154 155 156 157
struct _FontStyle
{
  guint16  properties[GTK_NUM_STYLE_PROPERTIES];
  gint	   pixel_sizes_index;
  guint16  npixel_sizes;
  gint	   point_sizes_index;
  guint16  npoint_sizes;
  guint8   flags;
};

struct _GtkFontSelInfo {
158
  
159 160 161
  /* This is a table with each FontInfo representing one font family+foundry */
  FontInfo *font_info;
  gint nfonts;
162
  
163 164 165 166
  /* This stores all the valid combinations of properties for every family.
     Each FontInfo holds an index into its own space in this one big array. */
  FontStyle *font_styles;
  gint nstyles;
167
  
168 169 170 171
  /* This stores all the font sizes available for every style.
     Each style holds an index into these arrays. */
  guint16 *pixel_sizes;
  guint16 *point_sizes;
172
  
173 174 175
  /* These are the arrays of strings of all possible weights, slants, 
     set widths, spacings, charsets & foundries, and the amount of space
     allocated for each array. */
176 177 178 179 180
  gchar **properties[GTK_NUM_FONT_PROPERTIES];
  guint16 nproperties[GTK_NUM_FONT_PROPERTIES];
  guint16 space_allocated[GTK_NUM_FONT_PROPERTIES];
};

Owen Taylor's avatar
Owen Taylor committed
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
/* These are the field numbers in the X Logical Font Description fontnames,
   e.g. -adobe-courier-bold-o-normal--25-180-100-100-m-150-iso8859-1 */
typedef enum
{
  XLFD_FOUNDRY		= 0,
  XLFD_FAMILY		= 1,
  XLFD_WEIGHT		= 2,
  XLFD_SLANT		= 3,
  XLFD_SET_WIDTH	= 4,
  XLFD_ADD_STYLE	= 5,
  XLFD_PIXELS		= 6,
  XLFD_POINTS		= 7,
  XLFD_RESOLUTION_X	= 8,
  XLFD_RESOLUTION_Y	= 9,
  XLFD_SPACING		= 10,
  XLFD_AVERAGE_WIDTH	= 11,
  XLFD_CHARSET		= 12
} FontField;

/* These are the names of the fields, used on the info & filter page. */
201
static const gchar* xlfd_field_names[GTK_XLFD_NUM_FIELDS] = {
Owen Taylor's avatar
Owen Taylor committed
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
  "Foundry:",
  "Family:",
  "Weight:",
  "Slant:",
  "Set Width:",
  "Add Style:",
  "Pixel Size:",
  "Point Size:",
  "Resolution X:",
  "Resolution Y:",
  "Spacing:",
  "Average Width:",
  "Charset:",
};

/* These are the array indices of the font properties used in several arrays,
   and should match the xlfd_index array below. */
typedef enum
{
  WEIGHT	= 0,
  SLANT		= 1,
  SET_WIDTH	= 2,
  SPACING	= 3,
  CHARSET	= 4,
  FOUNDRY	= 5
} PropertyIndexType;

/* This is used to look up a field in a fontname given one of the above
   property indices. */
231
static const FontField xlfd_index[GTK_NUM_FONT_PROPERTIES] = {
Owen Taylor's avatar
Owen Taylor committed
232 233 234 235 236 237 238 239 240
  XLFD_WEIGHT,
  XLFD_SLANT,
  XLFD_SET_WIDTH,
  XLFD_SPACING,
  XLFD_CHARSET,
  XLFD_FOUNDRY
};

/* These are the positions of the properties in the filter table - x, y. */
241
static const gint filter_positions[GTK_NUM_FONT_PROPERTIES][2] = {
Owen Taylor's avatar
Owen Taylor committed
242 243
  { 1, 0 }, { 0, 2 }, { 1, 2 }, { 2, 2 }, { 2, 0 }, { 0, 0 }
};
244
static const gint filter_heights[GTK_NUM_FONT_PROPERTIES] = {
245
  100, 70, 70, 40, 100, 100
Owen Taylor's avatar
Owen Taylor committed
246 247
};

248 249 250 251 252 253 254 255 256 257 258
/* This is returned by gtk_font_selection_filter_state to describe if a
   property value is filtered. e.g. if 'bold' has been selected on the filter
   page, then that will return 'FILTERED' and 'black' will be 'NOT_FILTERED'.
   If none of the weight values are selected, they all return 'NOT_SET'. */
typedef enum
{
  FILTERED,
  NOT_FILTERED,
  NOT_SET
} GtkFontPropertyFilterState;

259 260
static GtkFontSelInfo *fontsel_info = NULL;

Owen Taylor's avatar
Owen Taylor committed
261 262 263 264 265 266 267 268
/* The initial size and increment of each of the arrays of property values. */
#define PROPERTY_ARRAY_INCREMENT	16

static void    gtk_font_selection_class_init	     (GtkFontSelectionClass *klass);
static void    gtk_font_selection_init		     (GtkFontSelection *fontsel);
static void    gtk_font_selection_destroy	     (GtkObject      *object);

/* These are all used for class initialization - loading in the fonts etc. */
269 270
static void    gtk_font_selection_get_fonts          (void);
static void    gtk_font_selection_insert_font        (GSList         *fontnames[],
Owen Taylor's avatar
Owen Taylor committed
271 272
						      gint           *ntable,
						      gchar          *fontname);
273
static gint    gtk_font_selection_insert_field       (gchar          *fontname,
Owen Taylor's avatar
Owen Taylor committed
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
						      gint            prop);

/* These are the callbacks & related functions. */
static void    gtk_font_selection_select_font	     (GtkWidget      *w,
						      gint	      row,
						      gint	      column,
						      GdkEventButton *bevent,
						      gpointer        data);
static gint    gtk_font_selection_on_clist_key_press (GtkWidget      *clist,
						      GdkEventKey    *event,
						      GtkFontSelection *fs);
static gboolean gtk_font_selection_select_next	     (GtkFontSelection *fs,
						      GtkWidget        *clist,
						      gint		step);
static void    gtk_font_selection_show_available_styles
289
(GtkFontSelection *fs);
290 291 292
static void    gtk_font_selection_select_best_style  (GtkFontSelection *fs,
						      gboolean	       use_first);
static gint    gtk_font_selection_get_best_match     (GtkFontSelection *fs);
Owen Taylor's avatar
Owen Taylor committed
293 294 295 296 297 298 299

static void    gtk_font_selection_select_style	     (GtkWidget      *w,
						      gint	      row,
						      gint	      column,
						      GdkEventButton *bevent,
						      gpointer        data);
static void    gtk_font_selection_show_available_sizes
300
(GtkFontSelection *fs);
Owen Taylor's avatar
Owen Taylor committed
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
static gint    gtk_font_selection_size_key_press     (GtkWidget      *w,
						      GdkEventKey    *event,
						      gpointer        data);
static void    gtk_font_selection_select_best_size   (GtkFontSelection *fs);
static void    gtk_font_selection_select_size	     (GtkWidget      *w,
						      gint	      row,
						      gint	      column,
						      GdkEventButton *bevent,
						      gpointer        data);

static void    gtk_font_selection_metric_callback    (GtkWidget      *w,
						      gpointer        data);
static void    gtk_font_selection_expose_list	     (GtkWidget	     *w,
						      GdkEventExpose *event,
						      gpointer        data);

static void    gtk_font_selection_switch_page	     (GtkWidget      *w,
						      GtkNotebookPage *page,
						      gint             page_num,
						      gpointer         data);
static void    gtk_font_selection_show_font_info     (GtkFontSelection *fs);

static void    gtk_font_selection_select_filter	     (GtkWidget      *w,
						      gint	      row,
						      gint	      column,
						      GdkEventButton *bevent,
327
						      GtkFontSelection *fs);
Owen Taylor's avatar
Owen Taylor committed
328 329 330 331
static void    gtk_font_selection_unselect_filter    (GtkWidget      *w,
						      gint	      row,
						      gint	      column,
						      GdkEventButton *bevent,
332 333
						      GtkFontSelection *fs);
static void    gtk_font_selection_update_filter	     (GtkFontSelection *fs);
Owen Taylor's avatar
Owen Taylor committed
334 335 336 337
static gboolean gtk_font_selection_style_visible     (GtkFontSelection *fs,
						      FontInfo       *font,
						      gint	      style);
static void    gtk_font_selection_reset_filter	     (GtkWidget      *w,
338
						      GtkFontSelection *fs);
339
static void    gtk_font_selection_on_clear_filter    (GtkWidget      *w,
340 341 342
						      GtkFontSelection *fs);
static void    gtk_font_selection_show_available_fonts
						     (GtkFontSelection *fs);
Owen Taylor's avatar
Owen Taylor committed
343
static void    gtk_font_selection_clear_filter       (GtkFontSelection *fs);
344 345 346 347 348 349
static void    gtk_font_selection_update_filter_lists(GtkFontSelection *fs);
static GtkFontPropertyFilterState gtk_font_selection_filter_state
						     (GtkFontSelection *fs,
						      GtkFontFilterType filter_type,
						      gint		property,
						      gint		index);
Owen Taylor's avatar
Owen Taylor committed
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391

/* Misc. utility functions. */
static gboolean gtk_font_selection_load_font         (GtkFontSelection *fs);
static void    gtk_font_selection_update_preview     (GtkFontSelection *fs);

static gint    gtk_font_selection_find_font	     (GtkFontSelection *fs,
						      gchar          *family,
						      guint16	      foundry);
static guint16 gtk_font_selection_field_to_index     (gchar         **table,
						      gint            ntable,
						      gchar          *field);

static gchar*  gtk_font_selection_expand_slant_code  (gchar          *slant);
static gchar*  gtk_font_selection_expand_spacing_code(gchar          *spacing);

/* Functions for handling X Logical Font Description fontnames. */
static gboolean gtk_font_selection_is_xlfd_font_name (const gchar    *fontname);
static char*   gtk_font_selection_get_xlfd_field     (const gchar    *fontname,
						      FontField       field_num,
						      gchar          *buffer);
static gchar * gtk_font_selection_create_xlfd        (gint            size,
						      GtkFontMetricType metric,
						      gchar          *foundry,
						      gchar          *family,
						      gchar          *weight,
						      gchar          *slant,
						      gchar          *set_width,
						      gchar          *spacing,
						      gchar	     *charset);


/* FontSelectionDialog */
static void    gtk_font_selection_dialog_class_init  (GtkFontSelectionDialogClass *klass);
static void    gtk_font_selection_dialog_init	     (GtkFontSelectionDialog *fontseldiag);

static gint    gtk_font_selection_dialog_on_configure(GtkWidget      *widget,
						      GdkEventConfigure *event,
						      GtkFontSelectionDialog *fsd);

static GtkWindowClass *font_selection_parent_class = NULL;
static GtkNotebookClass *font_selection_dialog_parent_class = NULL;

Tim Janik's avatar
Tim Janik committed
392
GtkType
Owen Taylor's avatar
Owen Taylor committed
393 394
gtk_font_selection_get_type()
{
Tim Janik's avatar
Tim Janik committed
395
  static GtkType font_selection_type = 0;
396
  
Owen Taylor's avatar
Owen Taylor committed
397 398
  if(!font_selection_type)
    {
399
      static const GtkTypeInfo fontsel_type_info =
Owen Taylor's avatar
Owen Taylor committed
400 401
      {
	"GtkFontSelection",
Tim Janik's avatar
Tim Janik committed
402 403
	sizeof (GtkFontSelection),
	sizeof (GtkFontSelectionClass),
Owen Taylor's avatar
Owen Taylor committed
404 405
	(GtkClassInitFunc) gtk_font_selection_class_init,
	(GtkObjectInitFunc) gtk_font_selection_init,
406 407
	/* reserved_1 */ NULL,
	/* reserved_2 */ NULL,
408
        (GtkClassInitFunc) NULL,
Owen Taylor's avatar
Owen Taylor committed
409
      };
410
      
Tim Janik's avatar
Tim Janik committed
411 412
      font_selection_type = gtk_type_unique (GTK_TYPE_NOTEBOOK,
					     &fontsel_type_info);
Owen Taylor's avatar
Owen Taylor committed
413
    }
414
  
Owen Taylor's avatar
Owen Taylor committed
415 416 417 418 419 420 421
  return font_selection_type;
}

static void
gtk_font_selection_class_init(GtkFontSelectionClass *klass)
{
  GtkObjectClass *object_class;
422
  
Owen Taylor's avatar
Owen Taylor committed
423
  object_class = (GtkObjectClass *) klass;
424
  
Tim Janik's avatar
Tim Janik committed
425
  font_selection_parent_class = gtk_type_class (GTK_TYPE_NOTEBOOK);
426
  
Owen Taylor's avatar
Owen Taylor committed
427
  object_class->destroy = gtk_font_selection_destroy;
428
  
429
  gtk_font_selection_get_fonts ();
Owen Taylor's avatar
Owen Taylor committed
430 431 432 433 434
}

static void
gtk_font_selection_init(GtkFontSelection *fontsel)
{
435
  GtkWidget *scrolled_win;
Owen Taylor's avatar
Owen Taylor committed
436
  GtkWidget *text_frame;
437
  GtkWidget *text_box, *frame;
Owen Taylor's avatar
Owen Taylor committed
438 439 440 441 442 443 444 445 446
  GtkWidget *table, *label, *hbox, *hbox2, *clist, *button, *vbox, *alignment;
  gint i, prop, row;
  gchar *titles[] = { "Font Property", "Requested Value", "Actual Value" };
  gchar buffer[128];
  gchar *size;
  gint size_to_match;
  gchar *row_text[3];
  gchar *property, *text;
  gboolean inserted;
447
  
Owen Taylor's avatar
Owen Taylor committed
448 449 450 451 452 453 454 455
  /* Initialize the GtkFontSelection struct. We do this here in case any
     callbacks are triggered while creating the interface. */
  fontsel->font = NULL;
  fontsel->font_index = -1;
  fontsel->style = -1;
  fontsel->metric = INITIAL_METRIC;
  fontsel->size = INITIAL_FONT_SIZE;
  fontsel->selected_size = INITIAL_FONT_SIZE;
456 457 458 459 460

  fontsel->filters[GTK_FONT_FILTER_BASE].font_type = GTK_FONT_ALL;
  fontsel->filters[GTK_FONT_FILTER_USER].font_type = GTK_FONT_BITMAP
    | GTK_FONT_SCALABLE;

461
  
Owen Taylor's avatar
Owen Taylor committed
462 463
  for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
    {
464 465 466 467
      fontsel->filters[GTK_FONT_FILTER_BASE].property_filters[prop] = NULL;
      fontsel->filters[GTK_FONT_FILTER_BASE].property_nfilters[prop] = 0;
      fontsel->filters[GTK_FONT_FILTER_USER].property_filters[prop] = NULL;
      fontsel->filters[GTK_FONT_FILTER_USER].property_nfilters[prop] = 0;
Owen Taylor's avatar
Owen Taylor committed
468
    }
469
  
Owen Taylor's avatar
Owen Taylor committed
470
  for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
471 472
    fontsel->property_values[prop] = 0;
  
473
  /* Create the main notebook page. */
Owen Taylor's avatar
Owen Taylor committed
474 475
  fontsel->main_vbox = gtk_vbox_new (FALSE, 4);
  gtk_widget_show (fontsel->main_vbox);
476
  gtk_container_set_border_width (GTK_CONTAINER (fontsel->main_vbox), 6);
Owen Taylor's avatar
Owen Taylor committed
477 478 479 480
  label = gtk_label_new("Font");
  gtk_widget_set_usize (label, 120, -1);
  gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
			    fontsel->main_vbox, label);
481
  
Owen Taylor's avatar
Owen Taylor committed
482 483 484 485 486
  /* Create the table of font, style & size. */
  table = gtk_table_new (3, 3, FALSE);
  gtk_widget_show (table);
  gtk_table_set_col_spacings(GTK_TABLE(table), 8);
  gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), table, TRUE, TRUE, 0);
487
  
Owen Taylor's avatar
Owen Taylor committed
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
  fontsel->font_label = gtk_label_new("Font:");
  gtk_misc_set_alignment (GTK_MISC (fontsel->font_label), 0.0, 0.5);
  gtk_widget_show (fontsel->font_label);
  gtk_table_attach (GTK_TABLE (table), fontsel->font_label, 0, 1, 0, 1,
		    GTK_FILL, 0, 0, 0);
  label = gtk_label_new("Font Style:");
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  gtk_widget_show (label);
  gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1,
		    GTK_FILL, 0, 0, 0);
  label = gtk_label_new("Size:");
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  gtk_widget_show (label);
  gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
		    GTK_FILL, 0, 0, 0);
  
  fontsel->font_entry = gtk_entry_new();
  gtk_entry_set_editable(GTK_ENTRY(fontsel->font_entry), FALSE);
  gtk_widget_set_usize (fontsel->font_entry, 20, -1);
  gtk_widget_show (fontsel->font_entry);
  gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
		    GTK_FILL, 0, 0, 0);
  fontsel->font_style_entry = gtk_entry_new();
  gtk_entry_set_editable(GTK_ENTRY(fontsel->font_style_entry), FALSE);
  gtk_widget_set_usize (fontsel->font_style_entry, 20, -1);
  gtk_widget_show (fontsel->font_style_entry);
  gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
		    GTK_FILL, 0, 0, 0);
  fontsel->size_entry = gtk_entry_new();
  gtk_widget_set_usize (fontsel->size_entry, 20, -1);
  gtk_widget_show (fontsel->size_entry);
  gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
		    GTK_FILL, 0, 0, 0);
  gtk_signal_connect (GTK_OBJECT (fontsel->size_entry), "key_press_event",
		      (GtkSignalFunc) gtk_font_selection_size_key_press,
		      fontsel);
524
  
Owen Taylor's avatar
Owen Taylor committed
525 526 527 528 529 530
  /* Create the clists  */
  fontsel->font_clist = gtk_clist_new(1);
  gtk_clist_column_titles_hide (GTK_CLIST(fontsel->font_clist));
  gtk_clist_set_column_width (GTK_CLIST(fontsel->font_clist), 0, 300);
  gtk_widget_set_usize (fontsel->font_clist, FONT_LIST_WIDTH,
			FONT_LIST_HEIGHT);
531 532 533 534
  scrolled_win = gtk_scrolled_window_new (NULL, NULL);
  gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->font_clist);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
				  GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
Owen Taylor's avatar
Owen Taylor committed
535
  gtk_widget_show(fontsel->font_clist);
536 537 538
  gtk_widget_show(scrolled_win);

  gtk_table_attach (GTK_TABLE (table), scrolled_win, 0, 1, 2, 3,
Owen Taylor's avatar
Owen Taylor committed
539 540
		    GTK_EXPAND | GTK_FILL,
		    GTK_EXPAND | GTK_FILL, 0, 0);
541
  
Owen Taylor's avatar
Owen Taylor committed
542 543 544 545
  fontsel->font_style_clist = gtk_clist_new(1);
  gtk_clist_column_titles_hide (GTK_CLIST(fontsel->font_style_clist));
  gtk_clist_set_column_width (GTK_CLIST(fontsel->font_style_clist), 0, 300);
  gtk_widget_set_usize (fontsel->font_style_clist, FONT_STYLE_LIST_WIDTH, -1);
546 547 548 549
  scrolled_win = gtk_scrolled_window_new (NULL, NULL);
  gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->font_style_clist);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
				  GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
Owen Taylor's avatar
Owen Taylor committed
550
  gtk_widget_show(fontsel->font_style_clist);
551 552
  gtk_widget_show(scrolled_win);
  gtk_table_attach (GTK_TABLE (table), scrolled_win, 1, 2, 2, 3,
Owen Taylor's avatar
Owen Taylor committed
553 554
		    GTK_EXPAND | GTK_FILL,
		    GTK_EXPAND | GTK_FILL, 0, 0);
555
  
Owen Taylor's avatar
Owen Taylor committed
556 557 558
  fontsel->size_clist = gtk_clist_new(1);
  gtk_clist_column_titles_hide (GTK_CLIST(fontsel->size_clist));
  gtk_widget_set_usize (fontsel->size_clist, FONT_SIZE_LIST_WIDTH, -1);
559 560 561 562
  scrolled_win = gtk_scrolled_window_new (NULL, NULL);
  gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->size_clist);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
				  GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
Owen Taylor's avatar
Owen Taylor committed
563
  gtk_widget_show(fontsel->size_clist);
564 565
  gtk_widget_show(scrolled_win);
  gtk_table_attach (GTK_TABLE (table), scrolled_win, 2, 3, 2, 3,
Owen Taylor's avatar
Owen Taylor committed
566
		    GTK_FILL, GTK_FILL, 0, 0);
567 568
  
  
Owen Taylor's avatar
Owen Taylor committed
569 570
  /* Insert the fonts. If there exist fonts with the same family but
     different foundries, then the foundry name is appended in brackets. */
571
  gtk_font_selection_show_available_fonts(fontsel);
572
  
Owen Taylor's avatar
Owen Taylor committed
573 574 575 576 577 578 579 580 581 582
  gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "select_row",
		      GTK_SIGNAL_FUNC(gtk_font_selection_select_font),
		      fontsel);
  GTK_WIDGET_SET_FLAGS (fontsel->font_clist, GTK_CAN_FOCUS);
  gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "key_press_event",
		      GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
		      fontsel);
  gtk_signal_connect_after (GTK_OBJECT (fontsel->font_clist), "expose_event",
			    GTK_SIGNAL_FUNC(gtk_font_selection_expose_list),
			    fontsel);
583
  
Owen Taylor's avatar
Owen Taylor committed
584 585 586 587 588 589 590 591
  gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist), "select_row",
		      GTK_SIGNAL_FUNC(gtk_font_selection_select_style),
		      fontsel);
  GTK_WIDGET_SET_FLAGS (fontsel->font_style_clist, GTK_CAN_FOCUS);
  gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist),
		      "key_press_event",
		      GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
		      fontsel);
592
  
Owen Taylor's avatar
Owen Taylor committed
593 594 595
  /* Insert the standard font sizes */
  gtk_clist_freeze (GTK_CLIST(fontsel->size_clist));
  size_to_match = INITIAL_FONT_SIZE;
596
  if (INITIAL_METRIC == GTK_FONT_METRIC_POINTS)
Owen Taylor's avatar
Owen Taylor committed
597 598 599 600 601 602 603 604 605 606 607 608 609
    size_to_match = size_to_match / 10;
  for (i = 0; i < sizeof(font_sizes) / sizeof(font_sizes[0]); i++)
    {
      sprintf(buffer, "%i", font_sizes[i]);
      size = buffer;
      gtk_clist_append(GTK_CLIST(fontsel->size_clist), &size);
      if (font_sizes[i] == size_to_match)
	{
	  gtk_clist_select_row(GTK_CLIST(fontsel->size_clist), i, 0);
	  gtk_entry_set_text(GTK_ENTRY(fontsel->size_entry), buffer);
	}
    }
  gtk_clist_thaw (GTK_CLIST(fontsel->size_clist));
610
  
Owen Taylor's avatar
Owen Taylor committed
611 612 613 614 615 616 617
  gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "select_row",
		      GTK_SIGNAL_FUNC(gtk_font_selection_select_size),
		      fontsel);
  GTK_WIDGET_SET_FLAGS (fontsel->size_clist, GTK_CAN_FOCUS);
  gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "key_press_event",
		      GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
		      fontsel);
618 619
  
  
620
  /* create the Reset Filter & Metric buttons */
Owen Taylor's avatar
Owen Taylor committed
621 622 623
  hbox = gtk_hbox_new(FALSE, 8);
  gtk_widget_show (hbox);
  gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), hbox, FALSE, TRUE, 0);
624
  
625
  fontsel->filter_button = gtk_button_new_with_label("  Reset Filter  ");
Owen Taylor's avatar
Owen Taylor committed
626 627 628 629
  gtk_widget_show(fontsel->filter_button);
  gtk_box_pack_start (GTK_BOX (hbox), fontsel->filter_button, FALSE, FALSE, 0);
  gtk_widget_set_sensitive (fontsel->filter_button, FALSE);
  gtk_signal_connect (GTK_OBJECT (fontsel->filter_button), "clicked",
630
		      GTK_SIGNAL_FUNC(gtk_font_selection_on_clear_filter),
Owen Taylor's avatar
Owen Taylor committed
631
		      fontsel);
632
  
Owen Taylor's avatar
Owen Taylor committed
633 634 635 636 637 638 639
  hbox2 = gtk_hbox_new(FALSE, 0);
  gtk_widget_show (hbox2);
  gtk_box_pack_end (GTK_BOX (hbox), hbox2, FALSE, FALSE, 0);
  
  label = gtk_label_new("Metric:");
  gtk_widget_show (label);
  gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 8);
640
  
Owen Taylor's avatar
Owen Taylor committed
641 642 643
  fontsel->points_button = gtk_radio_button_new_with_label(NULL, "Points");
  gtk_widget_show (fontsel->points_button);
  gtk_box_pack_start (GTK_BOX (hbox2), fontsel->points_button, FALSE, TRUE, 0);
644
  if (INITIAL_METRIC == GTK_FONT_METRIC_POINTS)
Owen Taylor's avatar
Owen Taylor committed
645 646
    gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->points_button),
				TRUE);
647
  
Owen Taylor's avatar
Owen Taylor committed
648 649 650
  fontsel->pixels_button = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(fontsel->points_button), "Pixels");
  gtk_widget_show (fontsel->pixels_button);
  gtk_box_pack_start (GTK_BOX (hbox2), fontsel->pixels_button, FALSE, TRUE, 0);
651
  if (INITIAL_METRIC == GTK_FONT_METRIC_PIXELS)
Owen Taylor's avatar
Owen Taylor committed
652 653
    gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->pixels_button),
				TRUE);
654
  
Owen Taylor's avatar
Owen Taylor committed
655 656 657 658 659 660
  gtk_signal_connect(GTK_OBJECT(fontsel->points_button), "toggled",
		     (GtkSignalFunc) gtk_font_selection_metric_callback,
		     fontsel);
  gtk_signal_connect(GTK_OBJECT(fontsel->pixels_button), "toggled",
		     (GtkSignalFunc) gtk_font_selection_metric_callback,
		     fontsel);
661 662
  
  
Owen Taylor's avatar
Owen Taylor committed
663 664 665 666 667 668
  /* create the text entry widget */
  text_frame = gtk_frame_new ("Preview:");
  gtk_widget_show (text_frame);
  gtk_frame_set_shadow_type(GTK_FRAME(text_frame), GTK_SHADOW_ETCHED_IN);
  gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), text_frame,
		      FALSE, TRUE, 0);
669
  
Owen Taylor's avatar
Owen Taylor committed
670 671 672 673
  /* This is just used to get a 4-pixel space around the preview entry. */
  text_box = gtk_hbox_new (FALSE, 0);
  gtk_widget_show (text_box);
  gtk_container_add (GTK_CONTAINER (text_frame), text_box);
674
  gtk_container_set_border_width (GTK_CONTAINER (text_box), 4);
675
  
Owen Taylor's avatar
Owen Taylor committed
676 677 678 679 680
  fontsel->preview_entry = gtk_entry_new ();
  gtk_widget_show (fontsel->preview_entry);
  gtk_widget_set_usize (fontsel->preview_entry, -1, INITIAL_PREVIEW_HEIGHT);
  gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
		      TRUE, TRUE, 0);
681
  
Owen Taylor's avatar
Owen Taylor committed
682 683 684 685 686
  /* Create the message area */
  fontsel->message_label = gtk_label_new("");
  gtk_widget_show (fontsel->message_label);
  gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), fontsel->message_label, 
		      FALSE, FALSE, 0);
687 688
  
  
Owen Taylor's avatar
Owen Taylor committed
689 690 691
  /* Create the font info page */
  fontsel->info_vbox = gtk_vbox_new (FALSE, 4);
  gtk_widget_show (fontsel->info_vbox);
692
  gtk_container_set_border_width (GTK_CONTAINER (fontsel->info_vbox), 2);
Owen Taylor's avatar
Owen Taylor committed
693 694 695 696
  label = gtk_label_new("Font Information");
  gtk_widget_set_usize (label, 120, -1);
  gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
			    fontsel->info_vbox, label);
697
  
698
  fontsel->info_clist = gtk_clist_new_with_titles (3, titles);
Owen Taylor's avatar
Owen Taylor committed
699 700 701 702 703
  gtk_widget_set_usize (fontsel->info_clist, 390, 150);
  gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 0, 130);
  gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 1, 130);
  gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 2, 130);
  gtk_clist_column_titles_passive(GTK_CLIST(fontsel->info_clist));
704 705 706 707
  scrolled_win = gtk_scrolled_window_new (NULL, NULL);
  gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->info_clist);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
				  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
Owen Taylor's avatar
Owen Taylor committed
708
  gtk_widget_show(fontsel->info_clist);
709 710
  gtk_widget_show(scrolled_win);
  gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), scrolled_win,
Owen Taylor's avatar
Owen Taylor committed
711
		      TRUE, TRUE, 0);
712
  
Owen Taylor's avatar
Owen Taylor committed
713 714 715 716 717 718 719 720 721 722 723 724 725
  /* Insert the property names */
  gtk_clist_freeze (GTK_CLIST(fontsel->info_clist));
  row_text[1] = "";
  row_text[2] = "";
  for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
    {
      row_text[0] = xlfd_field_names[i];
      gtk_clist_append(GTK_CLIST(fontsel->info_clist), row_text);
      gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 0, 0, 4);
      gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 1, 0, 4);
      gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 2, 0, 4);
    }
  gtk_clist_thaw (GTK_CLIST(fontsel->info_clist));
726
  
Owen Taylor's avatar
Owen Taylor committed
727 728 729 730
  label = gtk_label_new("Requested Font Name:");
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  gtk_widget_show (label);
  gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, TRUE, 0);
731
  
Owen Taylor's avatar
Owen Taylor committed
732 733 734 735 736
  fontsel->requested_font_name = gtk_entry_new();
  gtk_entry_set_editable(GTK_ENTRY(fontsel->requested_font_name), FALSE);
  gtk_widget_show (fontsel->requested_font_name);
  gtk_box_pack_start (GTK_BOX (fontsel->info_vbox),
		      fontsel->requested_font_name, FALSE, TRUE, 0);
737
  
Owen Taylor's avatar
Owen Taylor committed
738 739 740 741 742 743 744 745 746 747
  label = gtk_label_new("Actual Font Name:");
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  gtk_widget_show (label);
  gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, TRUE, 0);
  
  fontsel->actual_font_name = gtk_entry_new();
  gtk_entry_set_editable(GTK_ENTRY(fontsel->actual_font_name), FALSE);
  gtk_widget_show (fontsel->actual_font_name);
  gtk_box_pack_start (GTK_BOX (fontsel->info_vbox),
		      fontsel->actual_font_name, FALSE, TRUE, 0);
748
  
Owen Taylor's avatar
Owen Taylor committed
749
  sprintf(buffer, "%i fonts available with a total of %i styles.",
750
	  fontsel_info->nfonts, fontsel_info->nstyles);
Owen Taylor's avatar
Owen Taylor committed
751 752 753
  label = gtk_label_new(buffer);
  gtk_widget_show (label);
  gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, FALSE, 0);
754
  
Owen Taylor's avatar
Owen Taylor committed
755 756 757
  gtk_signal_connect (GTK_OBJECT (fontsel), "switch_page",
		      GTK_SIGNAL_FUNC(gtk_font_selection_switch_page),
		      fontsel);
758 759
  
  
Owen Taylor's avatar
Owen Taylor committed
760 761 762
  /* Create the Filter page. */
  fontsel->filter_vbox = gtk_vbox_new (FALSE, 4);
  gtk_widget_show (fontsel->filter_vbox);
763
  gtk_container_set_border_width (GTK_CONTAINER (fontsel->filter_vbox), 2);
Owen Taylor's avatar
Owen Taylor committed
764 765 766 767
  label = gtk_label_new("Filter");
  gtk_widget_set_usize (label, 120, -1);
  gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
			    fontsel->filter_vbox, label);
768
  
769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
  /* Create the font type checkbuttons. */
  frame = gtk_frame_new (NULL);
  gtk_widget_show (frame);
  gtk_box_pack_start (GTK_BOX (fontsel->filter_vbox), frame, FALSE, TRUE, 0);

  hbox = gtk_hbox_new (FALSE, 20);
  gtk_widget_show (hbox);
  gtk_container_add (GTK_CONTAINER (frame), hbox);

  label = gtk_label_new("Font Types:");
  gtk_widget_show (label);
  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 10);

  hbox2 = gtk_hbox_new (TRUE, 0);
  gtk_widget_show (hbox2);
  gtk_box_pack_start (GTK_BOX (hbox), hbox2, FALSE, TRUE, 0);

  fontsel->type_bitmaps_button = gtk_check_button_new_with_label ("Bitmap");
  gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), TRUE);
  gtk_widget_show (fontsel->type_bitmaps_button);
  gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_bitmaps_button,
		      FALSE, TRUE, 0);

  fontsel->type_scalable_button = gtk_check_button_new_with_label ("Scalable");
  gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), TRUE);
  gtk_widget_show (fontsel->type_scalable_button);
  gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_scalable_button,
		      FALSE, TRUE, 0);

  fontsel->type_scaled_bitmaps_button = gtk_check_button_new_with_label ("Scaled Bitmap");
  gtk_widget_show (fontsel->type_scaled_bitmaps_button);
  gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_scaled_bitmaps_button,
		      FALSE, TRUE, 0);

Owen Taylor's avatar
Owen Taylor committed
803 804 805 806
  table = gtk_table_new (4, 3, FALSE);
  gtk_table_set_col_spacings(GTK_TABLE(table), 2);
  gtk_widget_show (table);
  gtk_box_pack_start (GTK_BOX (fontsel->filter_vbox), table, TRUE, TRUE, 0);
807
  
Owen Taylor's avatar
Owen Taylor committed
808 809 810 811
  for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
    {
      gint left = filter_positions[prop][0];
      gint top = filter_positions[prop][1];
812
      
Owen Taylor's avatar
Owen Taylor committed
813 814 815 816 817 818
      label = gtk_label_new(xlfd_field_names[xlfd_index[prop]]);
      gtk_misc_set_alignment (GTK_MISC (label), 0.0, 1.0);
      gtk_misc_set_padding (GTK_MISC (label), 0, 2);
      gtk_widget_show(label);
      gtk_table_attach (GTK_TABLE (table), label, left, left + 1,
			top, top + 1, GTK_FILL, GTK_FILL, 0, 0);
819
      
Owen Taylor's avatar
Owen Taylor committed
820 821 822 823
      clist = gtk_clist_new(1);
      gtk_widget_set_usize (clist, 100, filter_heights[prop]);
      gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_MULTIPLE);
      gtk_clist_column_titles_hide(GTK_CLIST(clist));
824 825 826 827 828
      scrolled_win = gtk_scrolled_window_new (NULL, NULL);
      gtk_container_add (GTK_CONTAINER (scrolled_win), clist);
      gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
				      GTK_POLICY_AUTOMATIC,
				      GTK_POLICY_AUTOMATIC);
Owen Taylor's avatar
Owen Taylor committed
829
      gtk_widget_show(clist);
830
      gtk_widget_show(scrolled_win);
831
      
832
      /* For the bottom-right cell we add the 'Reset Filter' button. */
Owen Taylor's avatar
Owen Taylor committed
833 834 835 836 837 838
      if (top == 2 && left == 2)
	{
	  vbox = gtk_vbox_new(FALSE, 0);
	  gtk_widget_show(vbox);
	  gtk_table_attach (GTK_TABLE (table), vbox, left, left + 1,
			    top + 1, top + 2, GTK_FILL, GTK_FILL, 0, 0);
839
	  
840
	  gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0);
841
	  
Owen Taylor's avatar
Owen Taylor committed
842 843 844
	  alignment = gtk_alignment_new(0.5, 0.0, 0.8, 0.0);
	  gtk_widget_show(alignment);
	  gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, TRUE, 4);
845
	  
846
	  button = gtk_button_new_with_label("Reset Filter");
Owen Taylor's avatar
Owen Taylor committed
847 848 849 850 851 852 853
	  gtk_widget_show(button);
	  gtk_container_add(GTK_CONTAINER(alignment), button);
	  gtk_signal_connect (GTK_OBJECT (button), "clicked",
			      GTK_SIGNAL_FUNC(gtk_font_selection_reset_filter),
			      fontsel);
	}
      else
854
	gtk_table_attach (GTK_TABLE (table), scrolled_win,
Owen Taylor's avatar
Owen Taylor committed
855 856
			  left, left + 1, top + 1, top + 2,
			  GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
857
      
Owen Taylor's avatar
Owen Taylor committed
858 859 860 861 862 863
      gtk_signal_connect (GTK_OBJECT (clist), "select_row",
			  GTK_SIGNAL_FUNC(gtk_font_selection_select_filter),
			  fontsel);
      gtk_signal_connect (GTK_OBJECT (clist), "unselect_row",
			  GTK_SIGNAL_FUNC(gtk_font_selection_unselect_filter),
			  fontsel);
864
      
Owen Taylor's avatar
Owen Taylor committed
865 866 867 868 869
      /* Insert the property names, expanded, and in sorted order.
	 But we make sure that the wildcard '*' is first. */
      gtk_clist_freeze (GTK_CLIST(clist));
      property = "*";
      gtk_clist_append(GTK_CLIST(clist), &property);
870
      
871 872
      for (i = 1; i < fontsel_info->nproperties[prop]; i++) {
	property = fontsel_info->properties[prop][i];
Owen Taylor's avatar
Owen Taylor committed
873 874 875 876
	if (prop == SLANT)
	  property = gtk_font_selection_expand_slant_code(property);
	else if (prop == SPACING)
	  property = gtk_font_selection_expand_spacing_code(property);
877
	
Owen Taylor's avatar
Owen Taylor committed
878 879 880 881 882 883 884 885 886 887 888 889 890
	inserted = FALSE;
	for (row = 1; row < GTK_CLIST(clist)->rows; row++)
	  {
	    gtk_clist_get_text(GTK_CLIST(clist), row, 0, &text);
	    if (strcmp(property, text) < 0)
	      {
		inserted = TRUE;
		gtk_clist_insert(GTK_CLIST(clist), row, &property);
		break;
	      }
	  }
	if (!inserted)
	  row = gtk_clist_append(GTK_CLIST(clist), &property);
891
	gtk_clist_set_row_data(GTK_CLIST(clist), row, GINT_TO_POINTER (i));
Owen Taylor's avatar
Owen Taylor committed
892 893 894 895 896 897 898 899 900 901 902
      }
      gtk_clist_select_row(GTK_CLIST(clist), 0, 0);
      gtk_clist_thaw (GTK_CLIST(clist));
      fontsel->filter_clists[prop] = clist;
    }
}

GtkWidget *
gtk_font_selection_new()
{
  GtkFontSelection *fontsel;
903
  
Tim Janik's avatar
Tim Janik committed
904
  fontsel = gtk_type_new (GTK_TYPE_FONT_SELECTION);
905
  
Owen Taylor's avatar
Owen Taylor committed
906 907 908 909 910 911 912
  return GTK_WIDGET (fontsel);
}

static void
gtk_font_selection_destroy (GtkObject *object)
{
  GtkFontSelection *fontsel;
913
  
Owen Taylor's avatar
Owen Taylor committed
914 915
  g_return_if_fail (object != NULL);
  g_return_if_fail (GTK_IS_FONT_SELECTION (object));
916
  
Owen Taylor's avatar
Owen Taylor committed
917
  fontsel = GTK_FONT_SELECTION (object);
918
  
Owen Taylor's avatar
Owen Taylor committed
919 920 921
  /* All we have to do is unref the font, if we have one. */
  if (fontsel->font)
    gdk_font_unref (fontsel->font);
922
  
Owen Taylor's avatar
Owen Taylor committed
923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938
  if (GTK_OBJECT_CLASS (font_selection_parent_class)->destroy)
    (* GTK_OBJECT_CLASS (font_selection_parent_class)->destroy) (object);
}


/* This is called when the clist is exposed. Here we scroll to the current
   font if necessary. */
static void
gtk_font_selection_expose_list (GtkWidget		*widget,
				GdkEventExpose		*event,
				gpointer		 data)
{
  GtkFontSelection *fontsel;
  FontInfo *font_info;
  GList *selection;
  gint index;
939
  
Owen Taylor's avatar
Owen Taylor committed
940
#ifdef FONTSEL_DEBUG
941
  g_message("In expose_list\n");
Owen Taylor's avatar
Owen Taylor committed
942 943
#endif
  fontsel = GTK_FONT_SELECTION(data);
944
  
945
  font_info = fontsel_info->font_info;
946
      
947 948 949 950 951 952 953 954 955
  /* Try to scroll the font family clist to the selected item */
  selection = GTK_CLIST(fontsel->font_clist)->selection;
  if (selection)
    {
      index = GPOINTER_TO_INT (selection->data);
      if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_clist), index)
	  != GTK_VISIBILITY_FULL)
	gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), index, -1, 0.5, 0);
    }
956
      
957 958 959 960 961 962 963 964 965 966
  /* Try to scroll the font style clist to the selected item */
  selection = GTK_CLIST(fontsel->font_style_clist)->selection;
  if (selection)
    {
      index = GPOINTER_TO_INT (selection->data);
      if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_style_clist), index)
	  != GTK_VISIBILITY_FULL)
	gtk_clist_moveto(GTK_CLIST(fontsel->font_style_clist), index, -1,
			 0.5, 0);
    }
967
      
968 969 970 971 972 973 974 975
  /* Try to scroll the font size clist to the selected item */
  selection = GTK_CLIST(fontsel->size_clist)->selection;
  if (selection)
    {
      index = GPOINTER_TO_INT (selection->data);
      if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->size_clist), index)
	  != GTK_VISIBILITY_FULL)
      gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), index, -1, 0.5, 0);
Owen Taylor's avatar
Owen Taylor committed
976 977 978 979 980 981 982 983 984 985 986 987 988 989 990
    }
}


/* This is called when a family is selected in the list. */
static void
gtk_font_selection_select_font (GtkWidget      *w,
				gint	        row,
				gint	        column,
				GdkEventButton *bevent,
				gpointer        data)
{
  GtkFontSelection *fontsel;
  FontInfo *font_info;
  FontInfo *font;
991
  
Owen Taylor's avatar
Owen Taylor committed
992
#ifdef FONTSEL_DEBUG
993
  g_message("In select_font\n");
Owen Taylor's avatar
Owen Taylor committed
994 995
#endif
  fontsel = GTK_FONT_SELECTION(data);
996
  font_info = fontsel_info->font_info;
997
  
Owen Taylor's avatar
Owen Taylor committed
998 999
  if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
    gtk_widget_grab_focus (w);
1000
  
1001
  row = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_clist), row));
Owen Taylor's avatar
Owen Taylor committed
1002 1003
  font = &font_info[row];
  gtk_entry_set_text(GTK_ENTRY(fontsel->font_entry), font->family);
1004
  
Owen Taylor's avatar
Owen Taylor committed
1005 1006 1007
  /* If it is already the current font, just return. */
  if (fontsel->font_index == row)
    return;
1008
  
Owen Taylor's avatar
Owen Taylor committed
1009 1010
  fontsel->font_index = row;
  gtk_font_selection_show_available_styles (fontsel);
1011
  gtk_font_selection_select_best_style (fontsel, TRUE);
Owen Taylor's avatar
Owen Taylor committed
1012 1013 1014 1015 1016 1017 1018 1019 1020
}


static gint
gtk_font_selection_on_clist_key_press (GtkWidget        *clist,
				       GdkEventKey      *event,
				       GtkFontSelection *fontsel)
{
#ifdef FONTSEL_DEBUG
1021
  g_message("In on_clist_key_press\n");
Owen Taylor's avatar
Owen Taylor committed
1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038
#endif
  if (event->keyval == GDK_Up)
    return gtk_font_selection_select_next (fontsel, clist, -1);
  else if (event->keyval == GDK_Down)
    return gtk_font_selection_select_next (fontsel, clist, 1);
  else
    return FALSE;
}


static gboolean
gtk_font_selection_select_next (GtkFontSelection *fontsel,
				GtkWidget        *clist,
				gint		  step)
{
  GList *selection;
  gint current_row, row;
1039
  
Owen Taylor's avatar
Owen Taylor committed
1040 1041 1042
  selection = GTK_CLIST(clist)->selection;
  if (!selection)
    return FALSE;
1043
  current_row = GPOINTER_TO_INT (selection->data);
1044
  
1045 1046 1047
  /* Stop the normal clist key handler from being run. */
  gtk_signal_emit_stop_by_name (GTK_OBJECT (clist), "key_press_event");

Owen Taylor's avatar
Owen Taylor committed
1048 1049 1050 1051 1052 1053 1054
  for (row = current_row + step;
       row >= 0 && row < GTK_CLIST(clist)->rows;
       row += step)
    {
      /* If this is the style clist, make sure that the item is not a charset
	 entry. */
      if (clist == fontsel->font_style_clist)
1055
	if (GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(clist), row)) == -1)
Owen Taylor's avatar
Owen Taylor committed
1056
	  continue;
1057
      
Owen Taylor's avatar
Owen Taylor committed
1058 1059 1060 1061 1062
      /* Now we've found the row to select. */
      if (gtk_clist_row_is_visible(GTK_CLIST(clist), row)
	  != GTK_VISIBILITY_FULL)
	gtk_clist_moveto(GTK_CLIST(clist), row, -1, (step < 0) ? 0 : 1, 0);
      gtk_clist_select_row(GTK_CLIST(clist), row, 0);
1063
      break;
Owen Taylor's avatar
Owen Taylor committed
1064
    }
1065
  return TRUE;
Owen Taylor's avatar
Owen Taylor committed
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084
}


/* This fills the font style clist with all the possible style combinations
   for the current font family. */
static void
gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
{
  FontInfo *font;
  FontStyle *styles;
  gint style, tmpstyle, row;
  gint weight_index, slant_index, set_width_index, spacing_index;
  gint charset_index;
  gchar *weight, *slant, *set_width, *spacing;
  gchar *charset = NULL;
  gchar *new_item;
  gchar buffer[XLFD_MAX_FIELD_LEN * 6 + 2];
  GdkColor *inactive_fg, *inactive_bg;
  gboolean show_charset;
1085
  
Owen Taylor's avatar
Owen Taylor committed
1086
#ifdef FONTSEL_DEBUG
1087
  g_message("In show_available_styles\n");
Owen Taylor's avatar
Owen Taylor committed
1088
#endif
1089 1090
  font = &fontsel_info->font_info[fontsel->font_index];
  styles = &fontsel_info->font_styles[font->style_index];
1091
  
Owen Taylor's avatar
Owen Taylor committed
1092 1093
  gtk_clist_freeze (GTK_CLIST(fontsel->font_style_clist));
  gtk_clist_clear (GTK_CLIST(fontsel->font_style_clist));
1094
  
Owen Taylor's avatar
Owen Taylor committed
1095 1096 1097 1098 1099 1100 1101 1102 1103
  /* First we mark all visible styles as not having been displayed yet,
     and check if every style has the same charset. If not then we will
     display the charset in the list before the styles. */
  show_charset = FALSE;
  charset_index = -1;
  for (style = 0; style < font->nstyles; style++)
    {
      if (gtk_font_selection_style_visible(fontsel, font, style))
	{
1104
	  styles[style].flags &= ~GTK_FONT_DISPLAYED;
1105
	  
Owen Taylor's avatar
Owen Taylor committed
1106 1107 1108 1109 1110 1111
	  if (charset_index == -1)
	    charset_index  = styles[style].properties[CHARSET];
	  else if (charset_index != styles[style].properties[CHARSET])
	    show_charset = TRUE;
	}
      else
1112
	styles[style].flags |= GTK_FONT_DISPLAYED;
Owen Taylor's avatar
Owen Taylor committed
1113
    }
1114
  
Owen Taylor's avatar
Owen Taylor committed
1115 1116 1117 1118 1119
  /* Step through the undisplayed styles, finding the next charset which
     hasn't been displayed yet. Then display the charset on one line, if
     necessary, and the visible styles indented beneath it. */
  inactive_fg = &fontsel->font_style_clist->style->fg[GTK_STATE_INSENSITIVE];
  inactive_bg = &fontsel->font_style_clist->style->bg[GTK_STATE_INSENSITIVE];
1120
  
Owen Taylor's avatar
Owen Taylor committed
1121 1122
  for (style = 0; style < font->nstyles; style++)
    {
1123 1124
      if (styles[style].flags & GTK_FONT_DISPLAYED)
	continue;
1125
      
Owen Taylor's avatar
Owen Taylor committed
1126 1127 1128
      if (show_charset)
	{
	  charset_index  = styles[style].properties[CHARSET];
1129
	  charset  = fontsel_info->properties[CHARSET] [charset_index];
Owen Taylor's avatar
Owen Taylor committed
1130 1131 1132 1133 1134 1135 1136 1137 1138
	  row = gtk_clist_append(GTK_CLIST(fontsel->font_style_clist),
				 &charset);
	  gtk_clist_set_row_data(GTK_CLIST(fontsel->font_style_clist), row,
				 (gpointer) -1);
	  gtk_clist_set_foreground(GTK_CLIST(fontsel->font_style_clist),
				   row, inactive_fg);
	  gtk_clist_set_background(GTK_CLIST(fontsel->font_style_clist),
				   row, inactive_bg);
	}
1139
      
Owen Taylor's avatar
Owen Taylor committed
1140 1141
      for (tmpstyle = style; tmpstyle < font->nstyles; tmpstyle++)
	{
1142
	  if (styles[tmpstyle].flags & GTK_FONT_DISPLAYED
Owen Taylor's avatar
Owen Taylor committed
1143 1144
	      || charset_index != styles[tmpstyle].properties[CHARSET])
	    continue;
1145
	  
1146
	  styles[tmpstyle].flags |= GTK_FONT_DISPLAYED;
1147
	  
Owen Taylor's avatar
Owen Taylor committed
1148 1149 1150 1151
	  weight_index    = styles[tmpstyle].properties[WEIGHT];
	  slant_index     = styles[tmpstyle].properties[SLANT];
	  set_width_index = styles[tmpstyle].properties[SET_WIDTH];
	  spacing_index   = styles[tmpstyle].properties[SPACING];
1152 1153 1154 1155
	  weight    = fontsel_info->properties[WEIGHT]   [weight_index];
	  slant     = fontsel_info->properties[SLANT]    [slant_index];
	  set_width = fontsel_info->properties[SET_WIDTH][set_width_index];
	  spacing   = fontsel_info->properties[SPACING]  [spacing_index];
1156
	  
Owen Taylor's avatar
Owen Taylor committed
1157 1158
	  /* Convert '(nil)' weights to 'regular', since it looks nicer. */
	  if      (!g_strcasecmp(weight, "(nil)"))	weight = "regular";
1159
	  
Owen Taylor's avatar
Owen Taylor committed
1160 1161 1162 1163 1164 1165 1166 1167
	  /* We don't show default values or (nil) in the other properties. */
	  if      (!g_strcasecmp(slant, "r"))        slant = NULL;
	  else if (!g_strcasecmp(slant, "(nil)"))</