1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
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.
27 * Fontnames - A maximum of MAX_FONTS (32767) fontnames will be retrieved
28 * from X Windows with XListFonts(). Any more are ignored.
29 * I think this limit may have been set because of a limit in
30 * GtkList. It could possibly be increased since we are using
31 * GtkClists now, but I'd be surprised if it was reached.
32 * Field length - XLFD_MAX_FIELD_LEN is the maximum length that any field of a
33 * fontname can be for it to be considered valid. Others are
35 * Properties - Maximum of 65535 choices for each font property - guint16's
36 * are used as indices, e.g. in the FontInfo struct.
37 * Combinations - Maximum of 65535 combinations of properties for each font
38 * family - a guint16 is used in the FontInfo struct.
39 * Font size - Minimum font size of 2 pixels/points, since trying to load
40 * some fonts with a size of 1 can cause X to hang.
41 * (e.g. the Misc Fixed fonts).
45 * Possible Improvements:
47 * Font Styles - could sort the styles into a reasonable order - regular
48 * first, then bold, bold italic etc.
50 * I18N - the default preview text is not useful for international
51 * fonts. Maybe the first few characters of the font could be
53 * - fontsets? should these be handled by the font dialog?
57 * Debugging: compile with -DFONTSEL_DEBUG for lots of debugging output.
68 #include "gdk/gdkkeysyms.h"
70 #include "gtkbutton.h"
71 #include "gtkcheckbutton.h"
74 #include "gtkfontsel.h"
79 #include "gtknotebook.h"
80 #include "gtkradiobutton.h"
81 #include "gtksignal.h"
85 /* The maximum number of fontnames requested with XListFonts(). */
86 #define MAX_FONTS 32767
88 /* This is the largest field length we will accept. If a fontname has a field
89 larger than this we will skip it. */
90 #define XLFD_MAX_FIELD_LEN 64
92 /* These are what we use as the standard font sizes, for the size clist.
93 Note that when using points we still show these integer point values but
94 we work internally in decipoints (and decipoint values can be typed in). */
95 static guint16 font_sizes[] = {
96 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28,
97 32, 36, 40, 48, 56, 64, 72
100 /* Initial font metric & size (Remember point sizes are in decipoints).
101 The font size should match one of those in the font_sizes array. */
102 #define INITIAL_METRIC GTK_FONT_METRIC_POINTS
103 #define INITIAL_FONT_SIZE 140
105 /* This is the default text shown in the preview entry, though the user
106 can set it. Remember that some fonts only have capital letters. */
107 #define PREVIEW_TEXT "abcdefghijk ABCDEFGHIJK"
109 /* This is the initial and maximum height of the preview entry (it expands
110 when large font sizes are selected). Initial height is also the minimum. */
111 #define INITIAL_PREVIEW_HEIGHT 44
112 #define MAX_PREVIEW_HEIGHT 300
114 /* These are the sizes of the font, style & size clists. */
115 #define FONT_LIST_HEIGHT 136
116 #define FONT_LIST_WIDTH 180
117 #define FONT_STYLE_LIST_WIDTH 160
118 #define FONT_SIZE_LIST_WIDTH 60
120 /* This is the number of fields in an X Logical Font Description font name.
121 Note that we count the registry & encoding as 1. */
122 #define GTK_XLFD_NUM_FIELDS 13
124 typedef struct _GtkFontSelInfo GtkFontSelInfo;
125 typedef struct _FontInfo FontInfo;
126 typedef struct _FontStyle FontStyle;
128 /* This struct represents one family of fonts (with one foundry), e.g. adobe
129 courier or sony fixed. It stores the family name, the index of the foundry
130 name, and the index of and number of available styles. */
139 /* This represents one style, as displayed in the Font Style clist. It can
140 have a number of available pixel sizes and point sizes. The indexes point
141 into the two big fontsel_info->pixel_sizes & fontsel_info->point_sizes
142 arrays. The displayed flag is used when displaying styles to remember which
143 styles have already been displayed. Note that it is combined with the
144 GtkFontType in the flags field. */
145 #define GTK_FONT_DISPLAYED (1 << 7)
148 guint16 properties[GTK_NUM_STYLE_PROPERTIES];
149 gint pixel_sizes_index;
150 guint16 npixel_sizes;
151 gint point_sizes_index;
152 guint16 npoint_sizes;
156 struct _GtkFontSelInfo {
158 /* This is a table with each FontInfo representing one font family+foundry */
162 /* This stores all the valid combinations of properties for every family.
163 Each FontInfo holds an index into its own space in this one big array. */
164 FontStyle *font_styles;
167 /* This stores all the font sizes available for every style.
168 Each style holds an index into these arrays. */
169 guint16 *pixel_sizes;
170 guint16 *point_sizes;
172 /* These are the arrays of strings of all possible weights, slants,
173 set widths, spacings, charsets & foundries, and the amount of space
174 allocated for each array. */
175 gchar **properties[GTK_NUM_FONT_PROPERTIES];
176 guint16 nproperties[GTK_NUM_FONT_PROPERTIES];
177 guint16 space_allocated[GTK_NUM_FONT_PROPERTIES];
180 /* These are the field numbers in the X Logical Font Description fontnames,
181 e.g. -adobe-courier-bold-o-normal--25-180-100-100-m-150-iso8859-1 */
192 XLFD_RESOLUTION_X = 8,
193 XLFD_RESOLUTION_Y = 9,
195 XLFD_AVERAGE_WIDTH = 11,
199 /* These are the names of the fields, used on the info & filter page. */
200 static gchar* xlfd_field_names[GTK_XLFD_NUM_FIELDS] = {
216 /* These are the array indices of the font properties used in several arrays,
217 and should match the xlfd_index array below. */
228 /* This is used to look up a field in a fontname given one of the above
230 static FontField xlfd_index[GTK_NUM_FONT_PROPERTIES] = {
239 /* These are the positions of the properties in the filter table - x, y. */
240 static gint filter_positions[GTK_NUM_FONT_PROPERTIES][2] = {
241 { 1, 0 }, { 0, 2 }, { 1, 2 }, { 2, 2 }, { 2, 0 }, { 0, 0 }
243 static gint filter_heights[GTK_NUM_FONT_PROPERTIES] = {
244 100, 70, 70, 40, 100, 100
247 /* This is returned by gtk_font_selection_filter_state to describe if a
248 property value is filtered. e.g. if 'bold' has been selected on the filter
249 page, then that will return 'FILTERED' and 'black' will be 'NOT_FILTERED'.
250 If none of the weight values are selected, they all return 'NOT_SET'. */
256 } GtkFontPropertyFilterState;
258 static GtkFontSelInfo *fontsel_info = NULL;
260 /* The initial size and increment of each of the arrays of property values. */
261 #define PROPERTY_ARRAY_INCREMENT 16
263 static void gtk_font_selection_class_init (GtkFontSelectionClass *klass);
264 static void gtk_font_selection_init (GtkFontSelection *fontsel);
265 static void gtk_font_selection_destroy (GtkObject *object);
267 /* These are all used for class initialization - loading in the fonts etc. */
268 static void gtk_font_selection_get_fonts (void);
269 static void gtk_font_selection_insert_font (GSList *fontnames[],
272 static gint gtk_font_selection_insert_field (gchar *fontname,
275 /* These are the callbacks & related functions. */
276 static void gtk_font_selection_select_font (GtkWidget *w,
279 GdkEventButton *bevent,
281 static gint gtk_font_selection_on_clist_key_press (GtkWidget *clist,
283 GtkFontSelection *fs);
284 static gboolean gtk_font_selection_select_next (GtkFontSelection *fs,
287 static void gtk_font_selection_show_available_styles
288 (GtkFontSelection *fs);
289 static void gtk_font_selection_select_best_style (GtkFontSelection *fs,
291 static gint gtk_font_selection_get_best_match (GtkFontSelection *fs);
293 static void gtk_font_selection_select_style (GtkWidget *w,
296 GdkEventButton *bevent,
298 static void gtk_font_selection_show_available_sizes
299 (GtkFontSelection *fs);
300 static gint gtk_font_selection_size_key_press (GtkWidget *w,
303 static void gtk_font_selection_select_best_size (GtkFontSelection *fs);
304 static void gtk_font_selection_select_size (GtkWidget *w,
307 GdkEventButton *bevent,
310 static void gtk_font_selection_metric_callback (GtkWidget *w,
312 static void gtk_font_selection_expose_list (GtkWidget *w,
313 GdkEventExpose *event,
316 static void gtk_font_selection_switch_page (GtkWidget *w,
317 GtkNotebookPage *page,
320 static void gtk_font_selection_show_font_info (GtkFontSelection *fs);
322 static void gtk_font_selection_select_filter (GtkWidget *w,
325 GdkEventButton *bevent,
326 GtkFontSelection *fs);
327 static void gtk_font_selection_unselect_filter (GtkWidget *w,
330 GdkEventButton *bevent,
331 GtkFontSelection *fs);
332 static void gtk_font_selection_update_filter (GtkFontSelection *fs);
333 static gboolean gtk_font_selection_style_visible (GtkFontSelection *fs,
336 static void gtk_font_selection_reset_filter (GtkWidget *w,
337 GtkFontSelection *fs);
338 static void gtk_font_selection_on_clear_filter (GtkWidget *w,
339 GtkFontSelection *fs);
340 static void gtk_font_selection_show_available_fonts
341 (GtkFontSelection *fs);
342 static void gtk_font_selection_clear_filter (GtkFontSelection *fs);
343 static void gtk_font_selection_update_filter_lists(GtkFontSelection *fs);
344 static GtkFontPropertyFilterState gtk_font_selection_filter_state
345 (GtkFontSelection *fs,
346 GtkFontFilterType filter_type,
350 /* Misc. utility functions. */
351 static gboolean gtk_font_selection_load_font (GtkFontSelection *fs);
352 static void gtk_font_selection_update_preview (GtkFontSelection *fs);
354 static gint gtk_font_selection_find_font (GtkFontSelection *fs,
357 static guint16 gtk_font_selection_field_to_index (gchar **table,
361 static gchar* gtk_font_selection_expand_slant_code (gchar *slant);
362 static gchar* gtk_font_selection_expand_spacing_code(gchar *spacing);
364 /* Functions for handling X Logical Font Description fontnames. */
365 static gboolean gtk_font_selection_is_xlfd_font_name (const gchar *fontname);
366 static char* gtk_font_selection_get_xlfd_field (const gchar *fontname,
369 static gchar * gtk_font_selection_create_xlfd (gint size,
370 GtkFontMetricType metric,
380 /* FontSelectionDialog */
381 static void gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass);
382 static void gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag);
384 static gint gtk_font_selection_dialog_on_configure(GtkWidget *widget,
385 GdkEventConfigure *event,
386 GtkFontSelectionDialog *fsd);
388 static GtkWindowClass *font_selection_parent_class = NULL;
389 static GtkNotebookClass *font_selection_dialog_parent_class = NULL;
392 gtk_font_selection_get_type()
394 static GtkType font_selection_type = 0;
396 if(!font_selection_type)
398 GtkTypeInfo fontsel_type_info =
401 sizeof (GtkFontSelection),
402 sizeof (GtkFontSelectionClass),
403 (GtkClassInitFunc) gtk_font_selection_class_init,
404 (GtkObjectInitFunc) gtk_font_selection_init,
405 /* reserved_1 */ NULL,
406 /* reserved_2 */ NULL,
407 (GtkClassInitFunc) NULL,
410 font_selection_type = gtk_type_unique (GTK_TYPE_NOTEBOOK,
414 return font_selection_type;
418 gtk_font_selection_class_init(GtkFontSelectionClass *klass)
420 GtkObjectClass *object_class;
422 object_class = (GtkObjectClass *) klass;
424 font_selection_parent_class = gtk_type_class (GTK_TYPE_NOTEBOOK);
426 object_class->destroy = gtk_font_selection_destroy;
428 gtk_font_selection_get_fonts ();
432 gtk_font_selection_init(GtkFontSelection *fontsel)
434 GtkWidget *text_frame;
435 GtkWidget *text_box, *frame;
436 GtkWidget *table, *label, *hbox, *hbox2, *clist, *button, *vbox, *alignment;
438 gchar *titles[] = { "Font Property", "Requested Value", "Actual Value" };
443 gchar *property, *text;
446 /* Initialize the GtkFontSelection struct. We do this here in case any
447 callbacks are triggered while creating the interface. */
448 fontsel->font = NULL;
449 fontsel->font_index = -1;
451 fontsel->metric = INITIAL_METRIC;
452 fontsel->size = INITIAL_FONT_SIZE;
453 fontsel->selected_size = INITIAL_FONT_SIZE;
455 fontsel->filters[GTK_FONT_FILTER_BASE].font_type = GTK_FONT_ALL;
456 fontsel->filters[GTK_FONT_FILTER_USER].font_type = GTK_FONT_BITMAP
460 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
462 fontsel->filters[GTK_FONT_FILTER_BASE].property_filters[prop] = NULL;
463 fontsel->filters[GTK_FONT_FILTER_BASE].property_nfilters[prop] = 0;
464 fontsel->filters[GTK_FONT_FILTER_USER].property_filters[prop] = NULL;
465 fontsel->filters[GTK_FONT_FILTER_USER].property_nfilters[prop] = 0;
468 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
469 fontsel->property_values[prop] = 0;
471 /* Create the main notebook page. */
472 fontsel->main_vbox = gtk_vbox_new (FALSE, 4);
473 gtk_widget_show (fontsel->main_vbox);
474 gtk_container_border_width (GTK_CONTAINER (fontsel->main_vbox), 6);
475 label = gtk_label_new("Font");
476 gtk_widget_set_usize (label, 120, -1);
477 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
478 fontsel->main_vbox, label);
480 /* Create the table of font, style & size. */
481 table = gtk_table_new (3, 3, FALSE);
482 gtk_widget_show (table);
483 gtk_table_set_col_spacings(GTK_TABLE(table), 8);
484 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), table, TRUE, TRUE, 0);
486 fontsel->font_label = gtk_label_new("Font:");
487 gtk_misc_set_alignment (GTK_MISC (fontsel->font_label), 0.0, 0.5);
488 gtk_widget_show (fontsel->font_label);
489 gtk_table_attach (GTK_TABLE (table), fontsel->font_label, 0, 1, 0, 1,
491 label = gtk_label_new("Font Style:");
492 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
493 gtk_widget_show (label);
494 gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1,
496 label = gtk_label_new("Size:");
497 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
498 gtk_widget_show (label);
499 gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
502 fontsel->font_entry = gtk_entry_new();
503 gtk_entry_set_editable(GTK_ENTRY(fontsel->font_entry), FALSE);
504 gtk_widget_set_usize (fontsel->font_entry, 20, -1);
505 gtk_widget_show (fontsel->font_entry);
506 gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
508 fontsel->font_style_entry = gtk_entry_new();
509 gtk_entry_set_editable(GTK_ENTRY(fontsel->font_style_entry), FALSE);
510 gtk_widget_set_usize (fontsel->font_style_entry, 20, -1);
511 gtk_widget_show (fontsel->font_style_entry);
512 gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
514 fontsel->size_entry = gtk_entry_new();
515 gtk_widget_set_usize (fontsel->size_entry, 20, -1);
516 gtk_widget_show (fontsel->size_entry);
517 gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
519 gtk_signal_connect (GTK_OBJECT (fontsel->size_entry), "key_press_event",
520 (GtkSignalFunc) gtk_font_selection_size_key_press,
523 /* Create the clists */
524 fontsel->font_clist = gtk_clist_new(1);
525 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->font_clist));
526 gtk_clist_set_column_width (GTK_CLIST(fontsel->font_clist), 0, 300);
527 gtk_clist_set_policy(GTK_CLIST(fontsel->font_clist), GTK_POLICY_ALWAYS,
528 GTK_POLICY_AUTOMATIC);
529 gtk_widget_set_usize (fontsel->font_clist, FONT_LIST_WIDTH,
531 gtk_widget_show(fontsel->font_clist);
532 gtk_table_attach (GTK_TABLE (table), fontsel->font_clist, 0, 1, 2, 3,
533 GTK_EXPAND | GTK_FILL,
534 GTK_EXPAND | GTK_FILL, 0, 0);
536 fontsel->font_style_clist = gtk_clist_new(1);
537 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->font_style_clist));
538 gtk_clist_set_column_width (GTK_CLIST(fontsel->font_style_clist), 0, 300);
539 gtk_clist_set_policy(GTK_CLIST(fontsel->font_style_clist), GTK_POLICY_ALWAYS,
540 GTK_POLICY_AUTOMATIC);
541 gtk_widget_set_usize (fontsel->font_style_clist, FONT_STYLE_LIST_WIDTH, -1);
542 gtk_widget_show(fontsel->font_style_clist);
543 gtk_table_attach (GTK_TABLE (table), fontsel->font_style_clist, 1, 2, 2, 3,
544 GTK_EXPAND | GTK_FILL,
545 GTK_EXPAND | GTK_FILL, 0, 0);
547 fontsel->size_clist = gtk_clist_new(1);
548 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->size_clist));
549 gtk_clist_set_policy(GTK_CLIST(fontsel->size_clist), GTK_POLICY_ALWAYS,
550 GTK_POLICY_AUTOMATIC);
551 gtk_widget_set_usize (fontsel->size_clist, FONT_SIZE_LIST_WIDTH, -1);
552 gtk_widget_show(fontsel->size_clist);
553 gtk_table_attach (GTK_TABLE (table), fontsel->size_clist, 2, 3, 2, 3,
554 GTK_FILL, GTK_FILL, 0, 0);
557 /* Insert the fonts. If there exist fonts with the same family but
558 different foundries, then the foundry name is appended in brackets. */
559 gtk_font_selection_show_available_fonts(fontsel);
561 gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "select_row",
562 GTK_SIGNAL_FUNC(gtk_font_selection_select_font),
564 GTK_WIDGET_SET_FLAGS (fontsel->font_clist, GTK_CAN_FOCUS);
565 gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "key_press_event",
566 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
568 gtk_signal_connect_after (GTK_OBJECT (fontsel->font_clist), "expose_event",
569 GTK_SIGNAL_FUNC(gtk_font_selection_expose_list),
572 gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist), "select_row",
573 GTK_SIGNAL_FUNC(gtk_font_selection_select_style),
575 GTK_WIDGET_SET_FLAGS (fontsel->font_style_clist, GTK_CAN_FOCUS);
576 gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist),
578 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
581 /* Insert the standard font sizes */
582 gtk_clist_freeze (GTK_CLIST(fontsel->size_clist));
583 size_to_match = INITIAL_FONT_SIZE;
584 if (INITIAL_METRIC == GTK_FONT_METRIC_POINTS)
585 size_to_match = size_to_match / 10;
586 for (i = 0; i < sizeof(font_sizes) / sizeof(font_sizes[0]); i++)
588 sprintf(buffer, "%i", font_sizes[i]);
590 gtk_clist_append(GTK_CLIST(fontsel->size_clist), &size);
591 if (font_sizes[i] == size_to_match)
593 gtk_clist_select_row(GTK_CLIST(fontsel->size_clist), i, 0);
594 gtk_entry_set_text(GTK_ENTRY(fontsel->size_entry), buffer);
597 gtk_clist_thaw (GTK_CLIST(fontsel->size_clist));
599 gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "select_row",
600 GTK_SIGNAL_FUNC(gtk_font_selection_select_size),
602 GTK_WIDGET_SET_FLAGS (fontsel->size_clist, GTK_CAN_FOCUS);
603 gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "key_press_event",
604 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
608 /* create the Reset Filter & Metric buttons */
609 hbox = gtk_hbox_new(FALSE, 8);
610 gtk_widget_show (hbox);
611 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), hbox, FALSE, TRUE, 0);
613 fontsel->filter_button = gtk_button_new_with_label(" Reset Filter ");
614 gtk_widget_show(fontsel->filter_button);
615 gtk_box_pack_start (GTK_BOX (hbox), fontsel->filter_button, FALSE, FALSE, 0);
616 gtk_widget_set_sensitive (fontsel->filter_button, FALSE);
617 gtk_signal_connect (GTK_OBJECT (fontsel->filter_button), "clicked",
618 GTK_SIGNAL_FUNC(gtk_font_selection_on_clear_filter),
621 hbox2 = gtk_hbox_new(FALSE, 0);
622 gtk_widget_show (hbox2);
623 gtk_box_pack_end (GTK_BOX (hbox), hbox2, FALSE, FALSE, 0);
625 label = gtk_label_new("Metric:");
626 gtk_widget_show (label);
627 gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 8);
629 fontsel->points_button = gtk_radio_button_new_with_label(NULL, "Points");
630 gtk_widget_show (fontsel->points_button);
631 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->points_button, FALSE, TRUE, 0);
632 if (INITIAL_METRIC == GTK_FONT_METRIC_POINTS)
633 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->points_button),
636 fontsel->pixels_button = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(fontsel->points_button), "Pixels");
637 gtk_widget_show (fontsel->pixels_button);
638 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->pixels_button, FALSE, TRUE, 0);
639 if (INITIAL_METRIC == GTK_FONT_METRIC_PIXELS)
640 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->pixels_button),
643 gtk_signal_connect(GTK_OBJECT(fontsel->points_button), "toggled",
644 (GtkSignalFunc) gtk_font_selection_metric_callback,
646 gtk_signal_connect(GTK_OBJECT(fontsel->pixels_button), "toggled",
647 (GtkSignalFunc) gtk_font_selection_metric_callback,
651 /* create the text entry widget */
652 text_frame = gtk_frame_new ("Preview:");
653 gtk_widget_show (text_frame);
654 gtk_frame_set_shadow_type(GTK_FRAME(text_frame), GTK_SHADOW_ETCHED_IN);
655 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), text_frame,
658 /* This is just used to get a 4-pixel space around the preview entry. */
659 text_box = gtk_hbox_new (FALSE, 0);
660 gtk_widget_show (text_box);
661 gtk_container_add (GTK_CONTAINER (text_frame), text_box);
662 gtk_container_border_width (GTK_CONTAINER (text_box), 4);
664 fontsel->preview_entry = gtk_entry_new ();
665 gtk_widget_show (fontsel->preview_entry);
666 gtk_widget_set_usize (fontsel->preview_entry, -1, INITIAL_PREVIEW_HEIGHT);
667 gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
670 /* Create the message area */
671 fontsel->message_label = gtk_label_new("");
672 gtk_widget_show (fontsel->message_label);
673 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), fontsel->message_label,
677 /* Create the font info page */
678 fontsel->info_vbox = gtk_vbox_new (FALSE, 4);
679 gtk_widget_show (fontsel->info_vbox);
680 gtk_container_border_width (GTK_CONTAINER (fontsel->info_vbox), 2);
681 label = gtk_label_new("Font Information");
682 gtk_widget_set_usize (label, 120, -1);
683 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
684 fontsel->info_vbox, label);
686 fontsel->info_clist = gtk_clist_new_with_titles(3, titles);
687 gtk_widget_set_usize (fontsel->info_clist, 390, 150);
688 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 0, 130);
689 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 1, 130);
690 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 2, 130);
691 gtk_clist_column_titles_passive(GTK_CLIST(fontsel->info_clist));
692 gtk_clist_set_policy(GTK_CLIST(fontsel->info_clist), GTK_POLICY_AUTOMATIC,
693 GTK_POLICY_AUTOMATIC);
694 gtk_widget_show(fontsel->info_clist);
695 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), fontsel->info_clist,
698 /* Insert the property names */
699 gtk_clist_freeze (GTK_CLIST(fontsel->info_clist));
702 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
704 row_text[0] = xlfd_field_names[i];
705 gtk_clist_append(GTK_CLIST(fontsel->info_clist), row_text);
706 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 0, 0, 4);
707 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 1, 0, 4);
708 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 2, 0, 4);
710 gtk_clist_thaw (GTK_CLIST(fontsel->info_clist));
712 label = gtk_label_new("Requested Font Name:");
713 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
714 gtk_widget_show (label);
715 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, TRUE, 0);
717 fontsel->requested_font_name = gtk_entry_new();
718 gtk_entry_set_editable(GTK_ENTRY(fontsel->requested_font_name), FALSE);
719 gtk_widget_show (fontsel->requested_font_name);
720 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox),
721 fontsel->requested_font_name, FALSE, TRUE, 0);
723 label = gtk_label_new("Actual Font Name:");
724 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
725 gtk_widget_show (label);
726 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, TRUE, 0);
728 fontsel->actual_font_name = gtk_entry_new();
729 gtk_entry_set_editable(GTK_ENTRY(fontsel->actual_font_name), FALSE);
730 gtk_widget_show (fontsel->actual_font_name);
731 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox),
732 fontsel->actual_font_name, FALSE, TRUE, 0);
734 sprintf(buffer, "%i fonts available with a total of %i styles.",
735 fontsel_info->nfonts, fontsel_info->nstyles);
736 label = gtk_label_new(buffer);
737 gtk_widget_show (label);
738 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, FALSE, 0);
740 gtk_signal_connect (GTK_OBJECT (fontsel), "switch_page",
741 GTK_SIGNAL_FUNC(gtk_font_selection_switch_page),
745 /* Create the Filter page. */
746 fontsel->filter_vbox = gtk_vbox_new (FALSE, 4);
747 gtk_widget_show (fontsel->filter_vbox);
748 gtk_container_border_width (GTK_CONTAINER (fontsel->filter_vbox), 2);
749 label = gtk_label_new("Filter");
750 gtk_widget_set_usize (label, 120, -1);
751 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
752 fontsel->filter_vbox, label);
754 /* Create the font type checkbuttons. */
755 frame = gtk_frame_new (NULL);
756 gtk_widget_show (frame);
757 gtk_box_pack_start (GTK_BOX (fontsel->filter_vbox), frame, FALSE, TRUE, 0);
759 hbox = gtk_hbox_new (FALSE, 20);
760 gtk_widget_show (hbox);
761 gtk_container_add (GTK_CONTAINER (frame), hbox);
763 label = gtk_label_new("Font Types:");
764 gtk_widget_show (label);
765 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 10);
767 hbox2 = gtk_hbox_new (TRUE, 0);
768 gtk_widget_show (hbox2);
769 gtk_box_pack_start (GTK_BOX (hbox), hbox2, FALSE, TRUE, 0);
771 fontsel->type_bitmaps_button = gtk_check_button_new_with_label ("Bitmap");
772 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), TRUE);
773 gtk_widget_show (fontsel->type_bitmaps_button);
774 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_bitmaps_button,
777 fontsel->type_scalable_button = gtk_check_button_new_with_label ("Scalable");
778 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), TRUE);
779 gtk_widget_show (fontsel->type_scalable_button);
780 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_scalable_button,
783 fontsel->type_scaled_bitmaps_button = gtk_check_button_new_with_label ("Scaled Bitmap");
784 gtk_widget_show (fontsel->type_scaled_bitmaps_button);
785 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_scaled_bitmaps_button,
788 table = gtk_table_new (4, 3, FALSE);
789 gtk_table_set_col_spacings(GTK_TABLE(table), 2);
790 gtk_widget_show (table);
791 gtk_box_pack_start (GTK_BOX (fontsel->filter_vbox), table, TRUE, TRUE, 0);
793 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
795 gint left = filter_positions[prop][0];
796 gint top = filter_positions[prop][1];
798 label = gtk_label_new(xlfd_field_names[xlfd_index[prop]]);
799 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 1.0);
800 gtk_misc_set_padding (GTK_MISC (label), 0, 2);
801 gtk_widget_show(label);
802 gtk_table_attach (GTK_TABLE (table), label, left, left + 1,
803 top, top + 1, GTK_FILL, GTK_FILL, 0, 0);
805 clist = gtk_clist_new(1);
806 gtk_widget_set_usize (clist, 100, filter_heights[prop]);
807 gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_MULTIPLE);
808 gtk_clist_column_titles_hide(GTK_CLIST(clist));
809 gtk_clist_set_policy(GTK_CLIST(clist), GTK_POLICY_AUTOMATIC,
810 GTK_POLICY_AUTOMATIC);
811 gtk_widget_show(clist);
813 /* For the bottom-right cell we add the 'Reset Filter' button. */
814 if (top == 2 && left == 2)
816 vbox = gtk_vbox_new(FALSE, 0);
817 gtk_widget_show(vbox);
818 gtk_table_attach (GTK_TABLE (table), vbox, left, left + 1,
819 top + 1, top + 2, GTK_FILL, GTK_FILL, 0, 0);
821 gtk_box_pack_start (GTK_BOX (vbox), clist, TRUE, TRUE, 0);
823 alignment = gtk_alignment_new(0.5, 0.0, 0.8, 0.0);
824 gtk_widget_show(alignment);
825 gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, TRUE, 4);
827 button = gtk_button_new_with_label("Reset Filter");
828 gtk_widget_show(button);
829 gtk_container_add(GTK_CONTAINER(alignment), button);
830 gtk_signal_connect (GTK_OBJECT (button), "clicked",
831 GTK_SIGNAL_FUNC(gtk_font_selection_reset_filter),
835 gtk_table_attach (GTK_TABLE (table), clist,
836 left, left + 1, top + 1, top + 2,
837 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
839 gtk_signal_connect (GTK_OBJECT (clist), "select_row",
840 GTK_SIGNAL_FUNC(gtk_font_selection_select_filter),
842 gtk_signal_connect (GTK_OBJECT (clist), "unselect_row",
843 GTK_SIGNAL_FUNC(gtk_font_selection_unselect_filter),
846 /* Insert the property names, expanded, and in sorted order.
847 But we make sure that the wildcard '*' is first. */
848 gtk_clist_freeze (GTK_CLIST(clist));
850 gtk_clist_append(GTK_CLIST(clist), &property);
852 for (i = 1; i < fontsel_info->nproperties[prop]; i++) {
853 property = fontsel_info->properties[prop][i];
855 property = gtk_font_selection_expand_slant_code(property);
856 else if (prop == SPACING)
857 property = gtk_font_selection_expand_spacing_code(property);
860 for (row = 1; row < GTK_CLIST(clist)->rows; row++)
862 gtk_clist_get_text(GTK_CLIST(clist), row, 0, &text);
863 if (strcmp(property, text) < 0)
866 gtk_clist_insert(GTK_CLIST(clist), row, &property);
871 row = gtk_clist_append(GTK_CLIST(clist), &property);
872 gtk_clist_set_row_data(GTK_CLIST(clist), row, GINT_TO_POINTER (i));
874 gtk_clist_select_row(GTK_CLIST(clist), 0, 0);
875 gtk_clist_thaw (GTK_CLIST(clist));
876 fontsel->filter_clists[prop] = clist;
881 gtk_font_selection_new()
883 GtkFontSelection *fontsel;
885 fontsel = gtk_type_new (GTK_TYPE_FONT_SELECTION);
887 return GTK_WIDGET (fontsel);
891 gtk_font_selection_destroy (GtkObject *object)
893 GtkFontSelection *fontsel;
895 g_return_if_fail (object != NULL);
896 g_return_if_fail (GTK_IS_FONT_SELECTION (object));
898 fontsel = GTK_FONT_SELECTION (object);
900 /* All we have to do is unref the font, if we have one. */
902 gdk_font_unref (fontsel->font);
904 if (GTK_OBJECT_CLASS (font_selection_parent_class)->destroy)
905 (* GTK_OBJECT_CLASS (font_selection_parent_class)->destroy) (object);
909 /* This is called when the clist is exposed. Here we scroll to the current
910 font if necessary. */
912 gtk_font_selection_expose_list (GtkWidget *widget,
913 GdkEventExpose *event,
916 GtkFontSelection *fontsel;
922 g_message("In expose_list\n");
924 fontsel = GTK_FONT_SELECTION(data);
926 font_info = fontsel_info->font_info;
928 /* Try to scroll the font family clist to the selected item */
929 selection = GTK_CLIST(fontsel->font_clist)->selection;
932 index = GPOINTER_TO_INT (selection->data);
933 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_clist), index)
934 != GTK_VISIBILITY_FULL)
935 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), index, -1, 0.5, 0);
938 /* Try to scroll the font style clist to the selected item */
939 selection = GTK_CLIST(fontsel->font_style_clist)->selection;
942 index = GPOINTER_TO_INT (selection->data);
943 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_style_clist), index)
944 != GTK_VISIBILITY_FULL)
945 gtk_clist_moveto(GTK_CLIST(fontsel->font_style_clist), index, -1,
949 /* Try to scroll the font size clist to the selected item */
950 selection = GTK_CLIST(fontsel->size_clist)->selection;
953 index = GPOINTER_TO_INT (selection->data);
954 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->size_clist), index)
955 != GTK_VISIBILITY_FULL)
956 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), index, -1, 0.5, 0);
961 /* This is called when a family is selected in the list. */
963 gtk_font_selection_select_font (GtkWidget *w,
966 GdkEventButton *bevent,
969 GtkFontSelection *fontsel;
974 g_message("In select_font\n");
976 fontsel = GTK_FONT_SELECTION(data);
977 font_info = fontsel_info->font_info;
979 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
980 gtk_widget_grab_focus (w);
982 row = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_clist), row));
983 font = &font_info[row];
984 gtk_entry_set_text(GTK_ENTRY(fontsel->font_entry), font->family);
986 /* If it is already the current font, just return. */
987 if (fontsel->font_index == row)
990 fontsel->font_index = row;
991 gtk_font_selection_show_available_styles (fontsel);
992 gtk_font_selection_select_best_style (fontsel, TRUE);
997 gtk_font_selection_on_clist_key_press (GtkWidget *clist,
999 GtkFontSelection *fontsel)
1001 #ifdef FONTSEL_DEBUG
1002 g_message("In on_clist_key_press\n");
1004 if (event->keyval == GDK_Up)
1005 return gtk_font_selection_select_next (fontsel, clist, -1);
1006 else if (event->keyval == GDK_Down)
1007 return gtk_font_selection_select_next (fontsel, clist, 1);
1014 gtk_font_selection_select_next (GtkFontSelection *fontsel,
1019 gint current_row, row;
1021 selection = GTK_CLIST(clist)->selection;
1024 current_row = GPOINTER_TO_INT (selection->data);
1026 /* Stop the normal clist key handler from being run. */
1027 gtk_signal_emit_stop_by_name (GTK_OBJECT (clist), "key_press_event");
1029 for (row = current_row + step;
1030 row >= 0 && row < GTK_CLIST(clist)->rows;
1033 /* If this is the style clist, make sure that the item is not a charset
1035 if (clist == fontsel->font_style_clist)
1036 if (GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(clist), row)) == -1)
1039 /* Now we've found the row to select. */
1040 if (gtk_clist_row_is_visible(GTK_CLIST(clist), row)
1041 != GTK_VISIBILITY_FULL)
1042 gtk_clist_moveto(GTK_CLIST(clist), row, -1, (step < 0) ? 0 : 1, 0);
1043 gtk_clist_select_row(GTK_CLIST(clist), row, 0);
1050 /* This fills the font style clist with all the possible style combinations
1051 for the current font family. */
1053 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
1057 gint style, tmpstyle, row;
1058 gint weight_index, slant_index, set_width_index, spacing_index;
1060 gchar *weight, *slant, *set_width, *spacing;
1061 gchar *charset = NULL;
1063 gchar buffer[XLFD_MAX_FIELD_LEN * 6 + 2];
1064 GdkColor *inactive_fg, *inactive_bg;
1065 gboolean show_charset;
1067 #ifdef FONTSEL_DEBUG
1068 g_message("In show_available_styles\n");
1070 font = &fontsel_info->font_info[fontsel->font_index];
1071 styles = &fontsel_info->font_styles[font->style_index];
1073 gtk_clist_freeze (GTK_CLIST(fontsel->font_style_clist));
1074 gtk_clist_clear (GTK_CLIST(fontsel->font_style_clist));
1076 /* First we mark all visible styles as not having been displayed yet,
1077 and check if every style has the same charset. If not then we will
1078 display the charset in the list before the styles. */
1079 show_charset = FALSE;
1081 for (style = 0; style < font->nstyles; style++)
1083 if (gtk_font_selection_style_visible(fontsel, font, style))
1085 styles[style].flags &= ~GTK_FONT_DISPLAYED;
1087 if (charset_index == -1)
1088 charset_index = styles[style].properties[CHARSET];
1089 else if (charset_index != styles[style].properties[CHARSET])
1090 show_charset = TRUE;
1093 styles[style].flags |= GTK_FONT_DISPLAYED;
1096 /* Step through the undisplayed styles, finding the next charset which
1097 hasn't been displayed yet. Then display the charset on one line, if
1098 necessary, and the visible styles indented beneath it. */
1099 inactive_fg = &fontsel->font_style_clist->style->fg[GTK_STATE_INSENSITIVE];
1100 inactive_bg = &fontsel->font_style_clist->style->bg[GTK_STATE_INSENSITIVE];
1102 for (style = 0; style < font->nstyles; style++)
1104 if (styles[style].flags & GTK_FONT_DISPLAYED)
1109 charset_index = styles[style].properties[CHARSET];
1110 charset = fontsel_info->properties[CHARSET] [charset_index];
1111 row = gtk_clist_append(GTK_CLIST(fontsel->font_style_clist),
1113 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_style_clist), row,
1115 gtk_clist_set_foreground(GTK_CLIST(fontsel->font_style_clist),
1117 gtk_clist_set_background(GTK_CLIST(fontsel->font_style_clist),
1121 for (tmpstyle = style; tmpstyle < font->nstyles; tmpstyle++)
1123 if (styles[tmpstyle].flags & GTK_FONT_DISPLAYED
1124 || charset_index != styles[tmpstyle].properties[CHARSET])
1127 styles[tmpstyle].flags |= GTK_FONT_DISPLAYED;
1129 weight_index = styles[tmpstyle].properties[WEIGHT];
1130 slant_index = styles[tmpstyle].properties[SLANT];
1131 set_width_index = styles[tmpstyle].properties[SET_WIDTH];
1132 spacing_index = styles[tmpstyle].properties[SPACING];
1133 weight = fontsel_info->properties[WEIGHT] [weight_index];
1134 slant = fontsel_info->properties[SLANT] [slant_index];
1135 set_width = fontsel_info->properties[SET_WIDTH][set_width_index];
1136 spacing = fontsel_info->properties[SPACING] [spacing_index];
1138 /* Convert '(nil)' weights to 'regular', since it looks nicer. */
1139 if (!g_strcasecmp(weight, "(nil)")) weight = "regular";
1141 /* We don't show default values or (nil) in the other properties. */
1142 if (!g_strcasecmp(slant, "r")) slant = NULL;
1143 else if (!g_strcasecmp(slant, "(nil)")) slant = NULL;
1144 else if (!g_strcasecmp(slant, "i")) slant = "italic";
1145 else if (!g_strcasecmp(slant, "o")) slant = "oblique";
1146 else if (!g_strcasecmp(slant, "ri")) slant = "reverse italic";
1147 else if (!g_strcasecmp(slant, "ro")) slant = "reverse oblique";
1148 else if (!g_strcasecmp(slant, "ot")) slant = "other";
1150 if (!g_strcasecmp(set_width, "normal")) set_width = NULL;
1151 else if (!g_strcasecmp(set_width, "(nil)")) set_width = NULL;
1153 if (!g_strcasecmp(spacing, "p")) spacing = NULL;
1154 else if (!g_strcasecmp(spacing, "(nil)")) spacing = NULL;
1155 else if (!g_strcasecmp(spacing, "m")) spacing = "[M]";
1156 else if (!g_strcasecmp(spacing, "c")) spacing = "[C]";
1158 /* Add the strings together, making sure there is 1 space between
1160 strcpy(buffer, weight);
1163 strcat(buffer, " ");
1164 strcat(buffer, slant);
1168 strcat(buffer, " ");
1169 strcat(buffer, set_width);
1173 strcat(buffer, " ");
1174 strcat(buffer, spacing);
1178 row = gtk_clist_append(GTK_CLIST(fontsel->font_style_clist),
1181 gtk_clist_set_shift(GTK_CLIST(fontsel->font_style_clist), row, 0,
1183 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_style_clist), row,
1184 GINT_TO_POINTER (tmpstyle));
1188 gtk_clist_thaw (GTK_CLIST(fontsel->font_style_clist));
1192 /* This selects a style when the user selects a font. It just uses the first
1193 available style at present. I was thinking of trying to maintain the
1194 selected style, e.g. bold italic, when the user selects different fonts.
1195 However, the interface is so easy to use now I'm not sure it's worth it.
1196 Note: This will load a font. */
1198 gtk_font_selection_select_best_style(GtkFontSelection *fontsel,
1203 gint row, prop, style = -1, style_to_find;
1204 gboolean found = FALSE;
1206 #ifdef FONTSEL_DEBUG
1207 g_message("In select_best_style\n");
1209 font = &fontsel_info->font_info[fontsel->font_index];
1210 styles = &fontsel_info->font_styles[font->style_index];
1212 /* If use_first is set, we just find the first style in the list, not
1213 including charset items. */
1214 style_to_find = use_first ? -1 : gtk_font_selection_get_best_match (fontsel);
1216 for (row = 0; row < GTK_CLIST(fontsel->font_style_clist)->rows; row++)
1218 style = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_style_clist), row));
1219 if (style != -1 && (style_to_find == -1 || style_to_find == style))
1225 g_return_if_fail (found);
1227 fontsel->style = style;
1229 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1230 fontsel->property_values[prop] = styles[fontsel->style].properties[prop];
1232 gtk_clist_select_row(GTK_CLIST(fontsel->font_style_clist), row, 0);
1233 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_style_clist), row)
1234 != GTK_VISIBILITY_FULL)
1235 gtk_clist_moveto(GTK_CLIST(fontsel->font_style_clist), row, -1, 0.5, 0);
1236 gtk_font_selection_show_available_sizes (fontsel);
1237 gtk_font_selection_select_best_size (fontsel);
1241 /* This is called when a style is selected in the list. */
1243 gtk_font_selection_select_style (GtkWidget *w,
1246 GdkEventButton *bevent,
1249 GtkFontSelection *fontsel;
1250 FontInfo *font_info;
1256 #ifdef FONTSEL_DEBUG
1257 g_message("In select_style\n");
1259 fontsel = GTK_FONT_SELECTION(data);
1260 font_info = fontsel_info->font_info;
1261 font = &font_info[fontsel->font_index];
1262 styles = &fontsel_info->font_styles[font->style_index];
1264 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1265 gtk_widget_grab_focus (w);
1267 /* The style index is stored in the row data, so we just need to copy
1268 the style values into the fontsel and reload the font. */
1269 style = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(fontsel->font_style_clist), row));
1271 /* Don't allow selection of charset rows. */
1274 gtk_clist_unselect_row(GTK_CLIST(fontsel->font_style_clist), row, 0);
1278 gtk_clist_get_text(GTK_CLIST(fontsel->font_style_clist), row, 0, &text);
1279 gtk_entry_set_text(GTK_ENTRY(fontsel->font_style_entry), text);
1281 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1282 fontsel->property_values[prop] = styles[style].properties[prop];
1284 if (fontsel->style == style)
1287 fontsel->style = style;
1288 gtk_font_selection_show_available_sizes (fontsel);
1289 gtk_font_selection_select_best_size (fontsel);
1293 /* This shows all the available sizes in the size clist, according to the
1294 current metric and the current font & style. */
1296 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel)
1299 FontStyle *styles, *style;
1300 guint16 *standard_sizes, *bitmapped_sizes, bitmap_size;
1301 gint nstandard_sizes, nbitmapped_sizes;
1302 gchar buffer[16], *size;
1303 gfloat bitmap_size_float;
1307 #ifdef FONTSEL_DEBUG
1308 g_message("In show_available_sizes\n");
1310 font = &fontsel_info->font_info[fontsel->font_index];
1311 styles = &fontsel_info->font_styles[font->style_index];
1312 style = &styles[fontsel->style];
1314 standard_sizes = font_sizes;
1315 nstandard_sizes = sizeof(font_sizes) / sizeof(font_sizes[0]);
1316 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1318 bitmapped_sizes = &fontsel_info->point_sizes[style->point_sizes_index];
1319 nbitmapped_sizes = style->npoint_sizes;
1323 bitmapped_sizes = &fontsel_info->pixel_sizes[style->pixel_sizes_index];
1324 nbitmapped_sizes = style->npixel_sizes;
1327 /* Only show the standard sizes if a scalable font is available. */
1328 type_filter = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
1329 & fontsel->filters[GTK_FONT_FILTER_USER].font_type;
1331 if (!((style->flags & GTK_FONT_SCALABLE_BITMAP
1332 && type_filter & GTK_FONT_SCALABLE_BITMAP)
1333 || (style->flags & GTK_FONT_SCALABLE
1334 && type_filter & GTK_FONT_SCALABLE)))
1335 nstandard_sizes = 0;
1337 gtk_clist_freeze (GTK_CLIST(fontsel->size_clist));
1338 gtk_clist_clear (GTK_CLIST(fontsel->size_clist));
1340 /* Interleave the standard sizes with the bitmapped sizes so we get a list
1341 of ascending sizes. If the metric is points, we have to convert the
1342 decipoints to points. */
1343 while (nstandard_sizes || nbitmapped_sizes)
1346 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1348 if (*bitmapped_sizes % 10 != 0)
1350 bitmap_size = *bitmapped_sizes / 10;
1351 bitmap_size_float = *bitmapped_sizes / 10;
1355 bitmap_size = *bitmapped_sizes;
1356 bitmap_size_float = *bitmapped_sizes;
1359 if (can_match && nstandard_sizes && nbitmapped_sizes
1360 && *standard_sizes == bitmap_size)
1362 sprintf(buffer, "%i *", *standard_sizes);
1368 else if (nstandard_sizes
1369 && (!nbitmapped_sizes
1370 || (gfloat)*standard_sizes < bitmap_size_float))
1372 sprintf(buffer, "%i", *standard_sizes);
1378 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1380 if (*bitmapped_sizes % 10 == 0)
1381 sprintf(buffer, "%i *", *bitmapped_sizes / 10);
1383 sprintf(buffer, "%i.%i *", *bitmapped_sizes / 10,
1384 *bitmapped_sizes % 10);
1388 sprintf(buffer, "%i *", *bitmapped_sizes);
1394 gtk_clist_append(GTK_CLIST(fontsel->size_clist), &size);
1396 gtk_clist_thaw (GTK_CLIST(fontsel->size_clist));
1400 /* If the user hits return in the font size entry, we change to the new font
1403 gtk_font_selection_size_key_press (GtkWidget *w,
1407 GtkFontSelection *fontsel;
1409 gfloat new_size_float;
1412 #ifdef FONTSEL_DEBUG
1413 g_message("In size_key_press\n");
1415 fontsel = GTK_FONT_SELECTION(data);
1417 if (event->keyval == GDK_Return)
1419 text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1420 if (fontsel->metric == GTK_FONT_METRIC_PIXELS)
1422 new_size = atoi (text);
1428 new_size_float = atof (text) * 10;
1429 new_size = (gint) new_size_float;
1434 /* Remember that this size was set explicitly. */
1435 fontsel->selected_size = new_size;
1437 /* Check if the font size has changed, and return if it hasn't. */
1438 if (fontsel->size == new_size)
1441 fontsel->size = new_size;
1442 gtk_font_selection_select_best_size (fontsel);
1450 /* This tries to select the closest size to the current size, though it
1451 may have to change the size if only unscaled bitmaps are available.
1452 Note: this will load a font. */
1454 gtk_font_selection_select_best_size(GtkFontSelection *fontsel)
1457 FontStyle *styles, *style;
1459 gint row, best_row = 0, size, size_fraction, best_size = 0, nmatched;
1460 gboolean found = FALSE;
1465 #ifdef FONTSEL_DEBUG
1466 g_message("In select_best_size\n");
1468 font = &fontsel_info->font_info[fontsel->font_index];
1469 styles = &fontsel_info->font_styles[font->style_index];
1470 style = &styles[fontsel->style];
1472 /* Find the closest size available in the size clist. If the exact size is
1473 in the list set found to TRUE. */
1474 for (row = 0; row < GTK_CLIST(fontsel->size_clist)->rows; row++)
1476 gtk_clist_get_text(GTK_CLIST(fontsel->size_clist), row, 0, &text);
1477 nmatched = sscanf(text, "%i.%i", &size, &size_fraction);
1478 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1482 size += size_fraction;
1485 if (size == fontsel->selected_size)
1492 else if (best_size == 0
1493 || abs(size - fontsel->selected_size)
1494 < (abs(best_size - fontsel->selected_size)))
1501 /* If we aren't scaling bitmapped fonts and this is a bitmapped font, we
1502 need to use the closest size found. */
1503 type_filter = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
1504 & fontsel->filters[GTK_FONT_FILTER_USER].font_type;
1506 if (!((style->flags & GTK_FONT_SCALABLE_BITMAP
1507 && type_filter & GTK_FONT_SCALABLE_BITMAP)
1508 || (style->flags & GTK_FONT_SCALABLE
1509 && type_filter & GTK_FONT_SCALABLE)))
1514 fontsel->size = best_size;
1515 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), best_row, -1, 0.5, 0);
1516 gtk_clist_select_row(GTK_CLIST(fontsel->size_clist), best_row, 0);
1520 fontsel->size = fontsel->selected_size;
1521 selection = GTK_CLIST(fontsel->size_clist)->selection;
1523 gtk_clist_unselect_row(GTK_CLIST(fontsel->size_clist),
1524 GPOINTER_TO_INT (selection->data), 0);
1525 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), best_row, -1, 0.5, 0);
1527 /* Show the size in the size entry. */
1528 if (fontsel->metric == GTK_FONT_METRIC_PIXELS)
1529 sprintf(buffer, "%i", fontsel->size);
1532 if (fontsel->size % 10 == 0)
1533 sprintf(buffer, "%i", fontsel->size / 10);
1535 sprintf(buffer, "%i.%i", fontsel->size / 10, fontsel->size % 10);
1537 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
1539 gtk_font_selection_load_font (fontsel);
1543 /* This is called when a size is selected in the list. */
1545 gtk_font_selection_select_size (GtkWidget *w,
1548 GdkEventButton *bevent,
1551 GtkFontSelection *fontsel;
1557 #ifdef FONTSEL_DEBUG
1558 g_message("In select_size\n");
1560 fontsel = GTK_FONT_SELECTION(data);
1562 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1563 gtk_widget_grab_focus (w);
1565 /* Copy the size from the clist to the size entry, but without the bitmapped
1567 gtk_clist_get_text(GTK_CLIST(fontsel->size_clist), row, 0, &text);
1569 while (i < 15 && (text[i] == '.' || (text[i] >= '0' && text[i] <= '9')))
1571 buffer[i] = text[i];
1575 gtk_entry_set_text(GTK_ENTRY(fontsel->size_entry), buffer);
1577 /* Check if the font size has changed, and return if it hasn't. */
1578 new_size = atoi(text);
1579 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1582 if (fontsel->size == new_size)
1585 /* If the size was selected by the user we set the selected_size. */
1586 fontsel->selected_size = new_size;
1588 fontsel->size = new_size;
1589 gtk_font_selection_load_font (fontsel);
1593 /* This is called when the pixels or points radio buttons are pressed. */
1595 gtk_font_selection_metric_callback (GtkWidget *w,
1598 GtkFontSelection *fontsel = GTK_FONT_SELECTION(data);
1600 #ifdef FONTSEL_DEBUG
1601 g_message("In metric_callback\n");
1603 if (GTK_TOGGLE_BUTTON(fontsel->pixels_button)->active)
1605 if (fontsel->metric == GTK_FONT_METRIC_PIXELS)
1607 fontsel->metric = GTK_FONT_METRIC_PIXELS;
1608 fontsel->size = (fontsel->size + 5) / 10;
1609 fontsel->selected_size = (fontsel->selected_size + 5) / 10;
1613 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1615 fontsel->metric = GTK_FONT_METRIC_POINTS;
1616 fontsel->size *= 10;
1617 fontsel->selected_size *= 10;
1619 if (fontsel->font_index != -1)
1621 gtk_font_selection_show_available_sizes (fontsel);
1622 gtk_font_selection_select_best_size (fontsel);
1627 /* This searches the given property table and returns the index of the given
1628 string, or 0, which is the wildcard '*' index, if it's not found. */
1630 gtk_font_selection_field_to_index (gchar **table,
1636 for (i = 0; i < ntable; i++)
1637 if (strcmp (field, table[i]) == 0)
1645 /* This attempts to load the current font, and returns TRUE if it succeeds. */
1647 gtk_font_selection_load_font (GtkFontSelection *fontsel)
1650 gchar *fontname, *label_text;
1653 gdk_font_unref (fontsel->font);
1654 fontsel->font = NULL;
1656 /* If no family has been selected yet, just return FALSE. */
1657 if (fontsel->font_index == -1)
1660 fontname = gtk_font_selection_get_font_name (fontsel);
1663 #ifdef FONTSEL_DEBUG
1664 g_message("Loading: %s\n", fontname);
1666 font = gdk_font_load (fontname);
1671 fontsel->font = font;
1672 /* Make sure the message label is empty, but don't change it unless
1673 it's necessary as it results in a resize of the whole window! */
1674 gtk_label_get(GTK_LABEL(fontsel->message_label), &label_text);
1675 if (strcmp(label_text, ""))
1676 gtk_label_set(GTK_LABEL(fontsel->message_label), "");
1677 gtk_font_selection_update_preview (fontsel);
1682 gtk_label_set(GTK_LABEL(fontsel->message_label),
1683 "The selected font is not available.");
1688 gtk_label_set(GTK_LABEL(fontsel->message_label),
1689 "The selected font is not a valid font.");
1696 /* This sets the font in the preview entry to the selected font, and tries to
1697 make sure that the preview entry is a reasonable size, i.e. so that the
1698 text can be seen with a bit of space to spare. But it tries to avoid
1699 resizing the entry every time the font changes.
1700 This also used to shrink the preview if the font size was decreased, but
1701 that made it awkward if the user wanted to resize the window themself. */
1703 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1705 GtkWidget *preview_entry;
1707 gint text_height, new_height;
1711 #ifdef FONTSEL_DEBUG
1712 g_message("In update_preview\n");
1714 style = gtk_style_new ();
1715 gdk_font_unref (style->font);
1716 style->font = fontsel->font;
1717 gdk_font_ref (style->font);
1719 preview_entry = fontsel->preview_entry;
1720 gtk_widget_set_style (preview_entry, style);
1721 gtk_style_unref(style);
1723 text_height = preview_entry->style->font->ascent
1724 + preview_entry->style->font->descent;
1725 /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1726 new_height = text_height + 20;
1727 if (new_height < INITIAL_PREVIEW_HEIGHT)
1728 new_height = INITIAL_PREVIEW_HEIGHT;
1729 if (new_height > MAX_PREVIEW_HEIGHT)
1730 new_height = MAX_PREVIEW_HEIGHT;
1732 if ((preview_entry->requisition.height < text_height + 10)
1733 || (preview_entry->requisition.height > text_height + 40))
1734 gtk_widget_set_usize(preview_entry, -1, new_height);
1736 /* This sets the preview text, if it hasn't been set already. */
1737 text = gtk_entry_get_text(GTK_ENTRY(fontsel->preview_entry));
1738 if (strlen(text) == 0)
1739 gtk_entry_set_text(GTK_ENTRY(fontsel->preview_entry), PREVIEW_TEXT);
1740 gtk_entry_set_position(GTK_ENTRY(fontsel->preview_entry), 0);
1742 /* If this is a 2-byte font display a message to say it may not be
1743 displayed properly. */
1744 xfs = GDK_FONT_XFONT(fontsel->font);
1745 if (xfs->min_byte1 != 0 || xfs->max_byte1 != 0)
1746 gtk_label_set(GTK_LABEL(fontsel->message_label),
1747 "This is a 2-byte font and may not be displayed correctly.");
1752 gtk_font_selection_switch_page (GtkWidget *w,
1753 GtkNotebookPage *page,
1757 GtkFontSelection *fontsel = GTK_FONT_SELECTION(data);
1759 /* This function strangely gets called when the window is destroyed,
1760 so we check here to see if the notebook is visible. */
1761 if (!GTK_WIDGET_VISIBLE(w))
1765 gtk_font_selection_update_filter(fontsel);
1766 else if (page_num == 1)
1767 gtk_font_selection_show_font_info(fontsel);
1772 gtk_font_selection_show_font_info (GtkFontSelection *fontsel)
1774 Atom font_atom, atom;
1778 gchar field_buffer[XLFD_MAX_FIELD_LEN];
1781 gboolean shown_actual_fields = FALSE;
1783 fontname = gtk_font_selection_get_font_name(fontsel);
1784 gtk_entry_set_text(GTK_ENTRY(fontsel->requested_font_name),
1785 fontname ? fontname : "");
1787 gtk_clist_freeze (GTK_CLIST(fontsel->info_clist));
1788 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1791 field = gtk_font_selection_get_xlfd_field (fontname, i, field_buffer);
1796 if (i == XLFD_SLANT)
1797 field = gtk_font_selection_expand_slant_code(field);
1798 else if (i == XLFD_SPACING)
1799 field = gtk_font_selection_expand_spacing_code(field);
1801 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 1,
1802 field ? field : "");
1807 font_atom = XInternAtom(GDK_DISPLAY(), "FONT", True);
1808 if (font_atom != None)
1810 status = XGetFontProperty(GDK_FONT_XFONT(fontsel->font), font_atom,
1814 name = XGetAtomName(GDK_DISPLAY(), atom);
1815 gtk_entry_set_text(GTK_ENTRY(fontsel->actual_font_name), name);
1817 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1819 field = gtk_font_selection_get_xlfd_field (name, i,
1821 if (i == XLFD_SLANT)
1822 field = gtk_font_selection_expand_slant_code(field);
1823 else if (i == XLFD_SPACING)
1824 field = gtk_font_selection_expand_spacing_code(field);
1825 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 2,
1826 field ? field : "");
1828 shown_actual_fields = TRUE;
1833 if (!shown_actual_fields)
1835 gtk_entry_set_text(GTK_ENTRY(fontsel->actual_font_name), "");
1836 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1838 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 2,
1839 fontname ? "(unknown)" : "");
1842 gtk_clist_thaw (GTK_CLIST(fontsel->info_clist));
1848 gtk_font_selection_expand_slant_code(gchar *slant)
1850 if (!g_strcasecmp(slant, "r")) return("roman");
1851 else if (!g_strcasecmp(slant, "i")) return("italic");
1852 else if (!g_strcasecmp(slant, "o")) return("oblique");
1853 else if (!g_strcasecmp(slant, "ri")) return("reverse italic");
1854 else if (!g_strcasecmp(slant, "ro")) return("reverse oblique");
1855 else if (!g_strcasecmp(slant, "ot")) return("other");
1860 gtk_font_selection_expand_spacing_code(gchar *spacing)
1862 if (!g_strcasecmp(spacing, "p")) return("proportional");
1863 else if (!g_strcasecmp(spacing, "m")) return("monospaced");
1864 else if (!g_strcasecmp(spacing, "c")) return("char cell");
1869 /*****************************************************************************
1870 * These functions all deal with the Filter page and filtering the fonts.
1871 *****************************************************************************/
1873 /* This is called when an item is selected in one of the filter clists.
1874 We make sure that the first row of the clist, i.e. the wildcard '*', is
1875 selected if and only if none of the other items are selected.
1876 Also doesn't allow selections of values filtered out by base filter.
1877 We may need to be careful about triggering other signals. */
1879 gtk_font_selection_select_filter (GtkWidget *w,
1882 GdkEventButton *bevent,
1883 GtkFontSelection *fontsel)
1885 gint i, prop, index;
1889 for (i = 1; i < GTK_CLIST(w)->rows; i++)
1890 gtk_clist_unselect_row(GTK_CLIST(w), i, 0);
1894 /* Find out which property this is. */
1895 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
1896 if (fontsel->filter_clists[prop] == w)
1898 index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(w), row));
1899 if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_BASE,
1900 prop, index) == NOT_FILTERED)
1901 gtk_clist_unselect_row(GTK_CLIST(w), row, 0);
1903 gtk_clist_unselect_row(GTK_CLIST(w), 0, 0);
1908 /* Here a filter item is being deselected. If there are now no items selected
1909 we select the first '*' item, unless that it is the item being deselected,
1910 in which case we select all of the other items. This makes it easy to
1911 select all items in the list except one or two. */
1913 gtk_font_selection_unselect_filter (GtkWidget *w,
1916 GdkEventButton *bevent,
1917 GtkFontSelection *fontsel)
1919 gint i, prop, index;
1921 if (!GTK_CLIST(w)->selection)
1925 /* Find out which property this is. */
1926 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
1927 if (fontsel->filter_clists[prop] == w)
1930 for (i = 1; i < GTK_CLIST(w)->rows; i++)
1932 index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(w),
1934 if (gtk_font_selection_filter_state (fontsel,
1935 GTK_FONT_FILTER_BASE,
1938 gtk_clist_select_row(GTK_CLIST(w), i, 0);
1943 gtk_clist_select_row(GTK_CLIST(w), 0, 0);
1949 /* This is called when the main notebook page is selected. It checks if the
1950 filter has changed, an if so it creates the filter settings, and filters the
1951 fonts shown. If an empty filter (all '*'s) is applied, then filtering is
1954 gtk_font_selection_update_filter (GtkFontSelection *fontsel)
1958 gboolean default_filter = TRUE, filter_changed = FALSE;
1959 gint prop, nselected, i, row, index;
1960 GtkFontFilter *filter = &fontsel->filters[GTK_FONT_FILTER_USER];
1961 gint base_font_type, user_font_type, new_font_type;
1963 #ifdef FONTSEL_DEBUG
1964 g_message("In update_filter\n");
1967 /* Check if the user filter has changed, and also if it is the default
1968 filter, i.e. bitmap & scalable fonts and all '*'s selected.
1969 We only look at the bits which are not already filtered out by the base
1970 filter, since that overrides the user filter. */
1971 base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
1973 user_font_type = fontsel->filters[GTK_FONT_FILTER_USER].font_type
1975 new_font_type = GTK_TOGGLE_BUTTON(fontsel->type_bitmaps_button)->active
1976 ? GTK_FONT_BITMAP : 0;
1977 new_font_type |= (GTK_TOGGLE_BUTTON(fontsel->type_scalable_button)->active
1978 ? GTK_FONT_SCALABLE : 0);
1979 new_font_type |= (GTK_TOGGLE_BUTTON(fontsel->type_scaled_bitmaps_button)->active ? GTK_FONT_SCALABLE_BITMAP : 0);
1980 new_font_type &= base_font_type;
1981 new_font_type |= (~base_font_type & user_font_type);
1982 if (new_font_type != (GTK_FONT_BITMAP | GTK_FONT_SCALABLE))
1983 default_filter = FALSE;
1985 if (new_font_type != user_font_type)
1986 filter_changed = TRUE;
1987 fontsel->filters[GTK_FONT_FILTER_USER].font_type = new_font_type;
1989 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
1991 clist = fontsel->filter_clists[prop];
1992 selection = GTK_CLIST(clist)->selection;
1993 nselected = g_list_length(selection);
1994 if (nselected != 1 || GPOINTER_TO_INT (selection->data) != 0)
1996 default_filter = FALSE;
1998 if (filter->property_nfilters[prop] != nselected)
1999 filter_changed = TRUE;
2002 for (i = 0; i < nselected; i++)
2004 row = GPOINTER_TO_INT (selection->data);
2005 index = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (clist), row));
2006 if (filter->property_filters[prop][i] != index)
2007 filter_changed = TRUE;
2008 selection = selection->next;
2014 if (filter->property_nfilters[prop] != 0)
2015 filter_changed = TRUE;
2019 /* If the filter hasn't changed we just return. */
2020 if (!filter_changed)
2023 #ifdef FONTSEL_DEBUG
2024 g_message(" update_fonts: filter has changed\n");
2027 /* Free the old filter data and create the new arrays. */
2028 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2030 g_free(filter->property_filters[prop]);
2032 clist = fontsel->filter_clists[prop];
2033 selection = GTK_CLIST(clist)->selection;
2034 nselected = g_list_length(selection);
2035 if (nselected == 1 && GPOINTER_TO_INT (selection->data) == 0)
2037 filter->property_filters[prop] = NULL;
2038 filter->property_nfilters[prop] = 0;
2042 filter->property_filters[prop] = g_new(guint16, nselected);
2043 filter->property_nfilters[prop] = nselected;
2044 for (i = 0; i < nselected; i++)
2046 row = GPOINTER_TO_INT (selection->data);
2047 index = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (clist), row));
2048 filter->property_filters[prop][i] = index;
2049 selection = selection->next;
2054 /* Set the 'Reset Filter' button sensitive if a filter is in effect, and
2055 also set the label above the font list to show this as well. */
2058 gtk_widget_set_sensitive(fontsel->filter_button, FALSE);
2059 gtk_label_set(GTK_LABEL(fontsel->font_label), "Font:");
2063 gtk_widget_set_sensitive(fontsel->filter_button, TRUE);
2064 gtk_label_set(GTK_LABEL(fontsel->font_label), "Font: (Filter Applied)");
2066 gtk_font_selection_show_available_fonts(fontsel);
2070 /* This shows all the available fonts in the font clist. */
2072 gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
2074 FontInfo *font_info, *font;
2075 GtkFontFilter *filter;
2076 gint nfonts, i, j, k, row, style, font_row = -1;
2077 gchar font_buffer[XLFD_MAX_FIELD_LEN * 2 + 4];
2079 gboolean matched, matched_style;
2081 #ifdef FONTSEL_DEBUG
2082 g_message("In show_available_fonts\n");
2084 font_info = fontsel_info->font_info;
2085 nfonts = fontsel_info->nfonts;
2087 /* Filter the list of fonts. */
2088 gtk_clist_freeze (GTK_CLIST(fontsel->font_clist));
2089 gtk_clist_clear (GTK_CLIST(fontsel->font_clist));
2090 for (i = 0; i < nfonts; i++)
2092 font = &font_info[i];
2094 /* Check if the foundry passes through all filters. */
2096 for (k = 0; k < GTK_NUM_FONT_FILTERS; k++)
2098 filter = &fontsel->filters[k];
2100 if (filter->property_nfilters[FOUNDRY] != 0)
2103 for (j = 0; j < filter->property_nfilters[FOUNDRY]; j++)
2105 if (font->foundry == filter->property_filters[FOUNDRY][j])
2118 /* Now check if the other properties are matched in at least one style.*/
2119 matched_style = FALSE;
2120 for (style = 0; style < font->nstyles; style++)
2122 if (gtk_font_selection_style_visible(fontsel, font, style))
2124 matched_style = TRUE;
2131 /* Insert the font in the clist. */
2132 if ((i > 0 && font->family == font_info[i-1].family)
2133 || (i < nfonts - 1 && font->family == font_info[i+1].family))
2135 sprintf(font_buffer, "%s (%s)", font->family,
2136 fontsel_info->properties[FOUNDRY][font->foundry]);
2137 font_item = font_buffer;
2138 row = gtk_clist_append(GTK_CLIST(fontsel->font_clist), &font_item);
2142 row = gtk_clist_append(GTK_CLIST(fontsel->font_clist),
2145 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_clist), row,
2146 GINT_TO_POINTER (i));
2147 if (fontsel->font_index == i)
2150 gtk_clist_thaw (GTK_CLIST(fontsel->font_clist));
2152 /* If the currently-selected font isn't in the new list, reset the
2156 fontsel->font_index = -1;
2158 gdk_font_unref(fontsel->font);
2159 fontsel->font = NULL;
2160 gtk_entry_set_text(GTK_ENTRY(fontsel->font_entry), "");
2161 gtk_clist_clear (GTK_CLIST(fontsel->font_style_clist));
2162 gtk_entry_set_text(GTK_ENTRY(fontsel->font_style_entry), "");
2166 gtk_clist_select_row(GTK_CLIST(fontsel->font_clist), font_row, 0);
2167 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_clist), font_row)
2168 != GTK_VISIBILITY_FULL)
2169 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), font_row, -1, 0.5, 0);
2171 gtk_font_selection_show_available_styles (fontsel);
2172 gtk_font_selection_select_best_style (fontsel, FALSE);
2176 /* Returns TRUE if the style is not currently filtered out. */
2178 gtk_font_selection_style_visible(GtkFontSelection *fontsel,
2182 FontStyle *styles, *style;
2183 GtkFontFilter *filter;
2189 styles = &fontsel_info->font_styles[font->style_index];
2190 style = &styles[style_index];
2192 /* Check if font_type of style is filtered. */
2193 type_filter = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
2194 & fontsel->filters[GTK_FONT_FILTER_USER].font_type;
2195 if (!(style->flags & type_filter))
2198 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2200 value = style->properties[prop];
2202 /* Check each filter. */
2203 for (i = 0; i < GTK_NUM_FONT_FILTERS; i++)
2205 filter = &fontsel->filters[i];
2207 if (filter->property_nfilters[prop] != 0)
2210 for (j = 0; j < filter->property_nfilters[prop]; j++)
2212 if (value == filter->property_filters[prop][j])
2227 /* This resets the font type to bitmap or scalable, and sets all the filter
2228 clists to the wildcard '*' options. */
2230 gtk_font_selection_reset_filter (GtkWidget *w,
2231 GtkFontSelection *fontsel)
2233 gint prop, base_font_type;
2235 fontsel->filters[GTK_FONT_FILTER_USER].font_type = GTK_FONT_BITMAP
2236 | GTK_FONT_SCALABLE;
2238 base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type;
2239 if (base_font_type & GTK_FONT_BITMAP)
2240 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), TRUE);
2241 if (base_font_type & GTK_FONT_SCALABLE)
2242 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), TRUE);
2243 if (base_font_type & GTK_FONT_SCALABLE_BITMAP)
2244 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), FALSE);
2246 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2247 gtk_clist_select_row(GTK_CLIST(fontsel->filter_clists[prop]), 0, 0);
2251 /* This clears the filter, showing all fonts and styles again. */
2253 gtk_font_selection_on_clear_filter (GtkWidget *w,
2254 GtkFontSelection *fontsel)
2256 gtk_font_selection_clear_filter(fontsel);
2260 /* This resets the user filter, showing all fonts and styles which pass the
2261 base filter again. Note that the font type is set to bitmaps and scalable
2262 fonts - scaled bitmaps are not shown. */
2264 gtk_font_selection_clear_filter (GtkFontSelection *fontsel)
2266 GtkFontFilter *filter;
2269 #ifdef FONTSEL_DEBUG
2270 g_message("In clear_filter\n");
2272 /* Clear the filter data. */
2273 filter = &fontsel->filters[GTK_FONT_FILTER_USER];
2274 filter->font_type = GTK_FONT_BITMAP | GTK_FONT_SCALABLE;
2275 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2277 g_free(filter->property_filters[prop]);
2278 filter->property_filters[prop] = NULL;
2279 filter->property_nfilters[prop] = 0;
2282 /* Select all the '*'s on the filter page. */
2283 gtk_font_selection_reset_filter(NULL, fontsel);
2285 /* Update the main notebook page. */
2286 gtk_widget_set_sensitive(fontsel->filter_button, FALSE);
2287 gtk_label_set(GTK_LABEL(fontsel->font_label), "Font:");
2289 gtk_font_selection_show_available_fonts(fontsel);
2294 gtk_font_selection_set_filter (GtkFontSelection *fontsel,
2295 GtkFontFilterType filter_type,
2296 GtkFontType font_type,
2304 GtkFontFilter *filter;
2305 gchar **filter_strings [GTK_NUM_FONT_PROPERTIES];
2306 gchar *filter_string;
2307 gchar *property, *property_alt;
2308 gint prop, nfilters, i, j, num_found;
2309 gint base_font_type, user_font_type;
2310 gboolean filter_set;
2312 /* Put them into an array so we can use a simple loop. */
2313 filter_strings[FOUNDRY] = foundries;
2314 filter_strings[WEIGHT] = weights;
2315 filter_strings[SLANT] = slants;
2316 filter_strings[SET_WIDTH] = setwidths;
2317 filter_strings[SPACING] = spacings;
2318 filter_strings[CHARSET] = charsets;
2320 filter = &fontsel->filters[filter_type];
2321 filter->font_type = font_type;
2323 /* Free the old filter data, and insert the new. */
2324 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2326 g_free(filter->property_filters[prop]);
2327 filter->property_filters[prop] = NULL;
2328 filter->property_nfilters[prop] = 0;
2330 if (filter_strings[prop])
2332 /* Count how many items in the new array. */
2334 while (filter_strings[prop][nfilters])
2337 filter->property_filters[prop] = g_new(guint16, nfilters);
2338 filter->property_nfilters[prop] = 0;
2340 /* Now convert the strings to property indices. */
2342 for (i = 0; i < nfilters; i++)
2344 filter_string = filter_strings[prop][i];
2345 for (j = 0; j < fontsel_info->nproperties[prop]; j++)
2347 property = fontsel_info->properties[prop][j];
2348 property_alt = NULL;
2350 property_alt = gtk_font_selection_expand_slant_code(property);
2351 else if (prop == SPACING)
2352 property_alt = gtk_font_selection_expand_spacing_code(property);
2353 if (!strcmp (filter_string, property)
2354 || (property_alt && !strcmp (filter_string, property_alt)))
2356 filter->property_filters[prop][num_found] = j;
2362 filter->property_nfilters[prop] = num_found;
2366 /* Now set the clists on the filter page according to the new filter. */
2367 gtk_font_selection_update_filter_lists (fontsel);
2369 if (filter_type == GTK_FONT_FILTER_BASE)
2371 user_font_type = fontsel->filters[GTK_FONT_FILTER_USER].font_type;
2372 if (font_type & GTK_FONT_BITMAP)
2374 gtk_widget_set_sensitive (fontsel->type_bitmaps_button, TRUE);
2375 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), user_font_type & GTK_FONT_BITMAP);
2379 gtk_widget_set_sensitive (fontsel->type_bitmaps_button, FALSE);
2380 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), FALSE);
2383 if (font_type & GTK_FONT_SCALABLE)
2385 gtk_widget_set_sensitive (fontsel->type_scalable_button, TRUE);
2386 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), user_font_type & GTK_FONT_SCALABLE);
2390 gtk_widget_set_sensitive (fontsel->type_scalable_button, FALSE);
2391 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), FALSE);
2394 if (font_type & GTK_FONT_SCALABLE_BITMAP)
2396 gtk_widget_set_sensitive (fontsel->type_scaled_bitmaps_button, TRUE);
2397 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), user_font_type & GTK_FONT_SCALABLE_BITMAP);
2401 gtk_widget_set_sensitive (fontsel->type_scaled_bitmaps_button, FALSE);
2402 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), FALSE);
2407 base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type;
2408 if (base_font_type & GTK_FONT_BITMAP)
2409 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), font_type & GTK_FONT_BITMAP);
2411 if (base_font_type & GTK_FONT_SCALABLE)
2412 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), font_type & GTK_FONT_SCALABLE);
2414 if (base_font_type & GTK_FONT_SCALABLE_BITMAP)
2415 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), font_type & GTK_FONT_SCALABLE_BITMAP);
2417 /* If the user filter is not the default, make the 'Reset Filter' button
2420 if (font_type != (GTK_FONT_BITMAP | GTK_FONT_SCALABLE))
2422 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2424 if (filter->property_nfilters[prop] != 0)
2428 gtk_widget_set_sensitive (fontsel->filter_button, TRUE);
2431 gtk_font_selection_show_available_fonts (fontsel);
2435 /* This sets the colour of each property in the filter clists according to
2436 the base filter. i.e. Filtered properties are shown as insensitive. */
2438 gtk_font_selection_update_filter_lists (GtkFontSelection *fontsel)
2441 GdkColor *inactive_fg, *inactive_bg, *fg, *bg;
2442 gint prop, row, index;
2444 /* We have to make sure the clist is realized to use the colours. */
2445 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2447 clist = fontsel->filter_clists[prop];
2448 gtk_widget_realize (clist);
2449 inactive_fg = &clist->style->fg[GTK_STATE_INSENSITIVE];
2450 inactive_bg = &clist->style->bg[GTK_STATE_INSENSITIVE];
2451 for (row = 1; row < GTK_CLIST(clist)->rows; row++)
2453 index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(clist),
2455 /* Set the colour according to the base filter. */
2456 if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_BASE,
2457 prop, index) == NOT_FILTERED)
2467 gtk_clist_set_foreground(GTK_CLIST(clist), row, fg);
2468 gtk_clist_set_background(GTK_CLIST(clist), row, bg);
2470 /* Set the selection state according to the user filter. */
2471 if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_USER,
2472 prop, index) == FILTERED
2474 gtk_clist_select_row (GTK_CLIST (clist), row, 0);
2476 gtk_clist_unselect_row (GTK_CLIST (clist), row, 0);
2482 /* Returns whether a property value is in the filter or not, or if the
2483 property has no filter set. */
2484 static GtkFontPropertyFilterState
2485 gtk_font_selection_filter_state (GtkFontSelection *fontsel,
2486 GtkFontFilterType filter_type,
2490 GtkFontFilter *filter;
2493 filter = &fontsel->filters[filter_type];
2494 if (filter->property_nfilters[property] == 0)
2497 for (i = 0; i < filter->property_nfilters[property]; i++)
2499 if (filter->property_filters[property][i] == index)
2502 return NOT_FILTERED;
2506 /*****************************************************************************
2507 * These functions all deal with creating the main class arrays containing
2508 * the data about all available fonts.
2509 *****************************************************************************/
2511 gtk_font_selection_get_fonts (void)
2518 gint i, prop, style, size;
2519 gint npixel_sizes = 0, npoint_sizes = 0;
2521 FontStyle *current_style, *prev_style, *tmp_style;
2522 gboolean matched_style, found_size;
2523 gint pixels, points, res_x, res_y;
2524 gchar field_buffer[XLFD_MAX_FIELD_LEN];
2527 guint16 *pixel_sizes, *point_sizes, *tmp_sizes;
2529 fontsel_info = g_new (GtkFontSelInfo, 1);
2531 /* Get a maximum of MAX_FONTS fontnames from the X server.
2532 Use "-*" as the pattern rather than "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" since
2533 the latter may result in fonts being returned which don't actually exist.
2534 xlsfonts also uses "*" so I think it's OK. "-*" gets rid of aliases. */
2535 xfontnames = XListFonts (GDK_DISPLAY(), "-*", MAX_FONTS, &num_fonts);
2536 /* Output a warning if we actually get MAX_FONTS fonts. */
2537 if (num_fonts == MAX_FONTS)
2538 g_warning("MAX_FONTS exceeded. Some fonts may be missing.");
2540 /* The maximum size of all these tables is the number of font names
2541 returned. We realloc them later when we know exactly how many
2542 unique entries there are. */
2543 fontsel_info->font_info = g_new (FontInfo, num_fonts);
2544 fontsel_info->font_styles = g_new (FontStyle, num_fonts);
2545 fontsel_info->pixel_sizes = g_new (guint16, num_fonts);
2546 fontsel_info->point_sizes = g_new (guint16, num_fonts);
2548 fontnames = g_new (GSList*, num_fonts);
2550 /* Create the initial arrays for the property value strings, though they
2551 may be realloc'ed later. Put the wildcard '*' in the first elements. */
2552 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2554 fontsel_info->properties[prop] = g_new(gchar*, PROPERTY_ARRAY_INCREMENT);
2555 fontsel_info->space_allocated[prop] = PROPERTY_ARRAY_INCREMENT;
2556 fontsel_info->nproperties[prop] = 1;
2557 fontsel_info->properties[prop][0] = "*";
2561 /* Insert the font families into the main table, sorted by family and
2562 foundry (fonts with different foundries are placed in seaparate FontInfos.
2563 All fontnames in each family + foundry are placed into the fontnames
2565 fontsel_info->nfonts = 0;
2566 for (i = 0; i < num_fonts; i++)
2568 #ifdef FONTSEL_DEBUG
2569 g_message("%s\n", xfontnames[i]);
2571 if (gtk_font_selection_is_xlfd_font_name (xfontnames[i]))
2572 gtk_font_selection_insert_font (fontnames, &fontsel_info->nfonts, xfontnames[i]);
2575 #ifdef FONTSEL_DEBUG
2576 g_warning("Skipping invalid font: %s", xfontnames[i]);
2582 /* Since many font names will be in the same FontInfo not all of the
2583 allocated FontInfo table will be used, so we will now reallocate it
2584 with the real size. */
2585 fontsel_info->font_info = g_realloc(fontsel_info->font_info,
2586 sizeof(FontInfo) * fontsel_info->nfonts);
2589 /* Now we work out which choices of weight/slant etc. are valid for each
2591 fontsel_info->nstyles = 0;
2592 current_style = fontsel_info->font_styles;
2593 for (i = 0; i < fontsel_info->nfonts; i++)
2595 font = &fontsel_info->font_info[i];
2597 /* Use the next free position in the styles array. */
2598 font->style_index = fontsel_info->nstyles;
2600 /* Now step through each of the fontnames with this family, and create
2601 a style for each fontname. Each style contains the index into the
2602 weights/slants etc. arrays, and a number of pixel/point sizes. */
2604 temp_list = fontnames[i];
2607 fontname = temp_list->data;
2608 temp_list = temp_list->next;
2610 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2612 current_style->properties[prop]
2613 = gtk_font_selection_insert_field (fontname, prop);
2615 current_style->pixel_sizes_index = npixel_sizes;
2616 current_style->npixel_sizes = 0;
2617 current_style->point_sizes_index = npoint_sizes;
2618 current_style->npoint_sizes = 0;
2619 current_style->flags = 0;
2622 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_PIXELS,
2624 pixels = atoi(field);
2626 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_POINTS,
2628 points = atoi(field);
2630 field = gtk_font_selection_get_xlfd_field (fontname,
2633 res_x = atoi(field);
2635 field = gtk_font_selection_get_xlfd_field (fontname,
2638 res_y = atoi(field);
2640 if (pixels == 0 && points == 0)
2642 if (res_x == 0 && res_y == 0)
2643 flags = GTK_FONT_SCALABLE;
2645 flags = GTK_FONT_SCALABLE_BITMAP;
2648 flags = GTK_FONT_BITMAP;
2650 /* Now we check to make sure that the style is unique. If it isn't
2652 prev_style = fontsel_info->font_styles + font->style_index;
2653 matched_style = FALSE;
2654 while (prev_style < current_style)
2656 matched_style = TRUE;
2657 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2659 if (prev_style->properties[prop]
2660 != current_style->properties[prop])
2662 matched_style = FALSE;
2671 /* If we matched an existing style, we need to add the pixels &
2672 point sizes to the style. If not, we insert the pixel & point
2673 sizes into our new style. Note that we don't add sizes for
2677 prev_style->flags |= flags;
2678 if (flags == GTK_FONT_BITMAP)
2680 pixel_sizes = fontsel_info->pixel_sizes
2681 + prev_style->pixel_sizes_index;
2683 for (size = 0; size < prev_style->npixel_sizes; size++)
2685 if (pixels == *pixel_sizes)
2690 else if (pixels < *pixel_sizes)
2694 /* We need to move all the following pixel sizes up, and also
2695 update the indexes of any following styles. */
2698 for (tmp_sizes = fontsel_info->pixel_sizes + npixel_sizes;
2699 tmp_sizes > pixel_sizes; tmp_sizes--)
2700 *tmp_sizes = *(tmp_sizes - 1);
2702 *pixel_sizes = pixels;
2704 prev_style->npixel_sizes++;
2706 tmp_style = prev_style + 1;
2707 while (tmp_style < current_style)
2709 tmp_style->pixel_sizes_index++;
2714 point_sizes = fontsel_info->point_sizes
2715 + prev_style->point_sizes_index;
2717 for (size = 0; size < prev_style->npoint_sizes; size++)
2719 if (points == *point_sizes)
2724 else if (points < *point_sizes)
2728 /* We need to move all the following point sizes up, and also
2729 update the indexes of any following styles. */
2732 for (tmp_sizes = fontsel_info->point_sizes + npoint_sizes;
2733 tmp_sizes > point_sizes; tmp_sizes--)
2734 *tmp_sizes = *(tmp_sizes - 1);
2736 *point_sizes = points;
2738 prev_style->npoint_sizes++;
2740 tmp_style = prev_style + 1;
2741 while (tmp_style < current_style)
2743 tmp_style->point_sizes_index++;
2751 current_style->flags = flags;
2752 if (flags == GTK_FONT_BITMAP)
2754 fontsel_info->pixel_sizes[npixel_sizes++] = pixels;
2755 current_style->npixel_sizes = 1;
2756 fontsel_info->point_sizes[npoint_sizes++] = points;
2757 current_style->npoint_sizes = 1;
2760 fontsel_info->nstyles++;
2764 g_slist_free(fontnames[i]);
2766 /* Set nstyles to the real value, minus duplicated fontnames.
2767 Note that we aren't using all the allocated memory if fontnames are
2769 font->nstyles = style;
2772 /* Since some repeated styles may be skipped we won't have used all the
2773 allocated space, so we will now reallocate it with the real size. */
2774 fontsel_info->font_styles = g_realloc(fontsel_info->font_styles,
2775 sizeof(FontStyle) * fontsel_info->nstyles);
2776 fontsel_info->pixel_sizes = g_realloc(fontsel_info->pixel_sizes,
2777 sizeof(guint16) * npixel_sizes);
2778 fontsel_info->point_sizes = g_realloc(fontsel_info->point_sizes,
2779 sizeof(guint16) * npoint_sizes);
2781 XFreeFontNames (xfontnames);
2784 /* Debugging Output */
2785 /* This outputs all FontInfos. */
2786 #ifdef FONTSEL_DEBUG
2787 g_message("\n\n Font Family Weight Slant Set Width Spacing Charset\n\n");
2788 for (i = 0; i < fontsel_info->nfonts; i++)
2790 FontInfo *font = &fontsel_info->font_info[i];
2791 FontStyle *styles = fontsel_info->font_styles + font->style_index;
2792 for (style = 0; style < font->nstyles; style++)
2794 g_message("%5i %-16.16s ", i, font->family);
2795 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2796 g_message("%-9.9s ",
2797 fontsel_info->properties[prop][styles->properties[prop]]);
2800 if (styles->flags & GTK_FONT_BITMAP)
2801 g_message("Bitmapped font ");
2802 if (styles->flags & GTK_FONT_SCALABLE)
2803 g_message("Scalable font ");
2804 if (styles->flags & GTK_FONT_SCALABLE_BITMAP)
2805 g_message("Scalable-Bitmapped font ");
2808 if (styles->npixel_sizes)
2810 g_message(" Pixel sizes: ");
2811 tmp_sizes = fontsel_info->pixel_sizes + styles->pixel_sizes_index;
2812 for (size = 0; size < styles->npixel_sizes; size++)
2813 g_message("%i ", *tmp_sizes++);
2817 if (styles->npoint_sizes)
2819 g_message(" Point sizes: ");
2820 tmp_sizes = fontsel_info->point_sizes + styles->point_sizes_index;
2821 for (size = 0; size < styles->npoint_sizes; size++)
2822 g_message("%i ", *tmp_sizes++);
2830 /* This outputs all available properties. */
2831 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2833 g_message("Property: %s\n", xlfd_field_names[xlfd_index[prop]]);
2834 for (i = 0; i < fontsel_info->nproperties[prop]; i++)
2835 g_message(" %s\n", fontsel_info->properties[prop][i]);
2840 /* This inserts the given fontname into the FontInfo table.
2841 If a FontInfo already exists with the same family and foundry, then the
2842 fontname is added to the FontInfos list of fontnames, else a new FontInfo
2843 is created and inserted in alphabetical order in the table. */
2845 gtk_font_selection_insert_font (GSList *fontnames[],
2851 GSList *temp_fontname;
2853 gboolean family_exists = FALSE;
2857 gchar family_buffer[XLFD_MAX_FIELD_LEN];
2859 table = fontsel_info->font_info;
2861 /* insert a fontname into a table */
2862 family = gtk_font_selection_get_xlfd_field (fontname, XLFD_FAMILY,
2867 foundry = gtk_font_selection_insert_field (fontname, FOUNDRY);
2872 /* Do a binary search to determine if we have already encountered
2873 * a font with this family & foundry. */
2875 while (lower < upper)
2877 middle = (lower + upper) >> 1;
2879 cmp = strcmp (family, table[middle].family);
2880 /* If the family matches we sort by the foundry. */
2883 family_exists = TRUE;
2884 family = table[middle].family;
2885 cmp = strcmp(fontsel_info->properties[FOUNDRY][foundry],
2886 fontsel_info->properties[FOUNDRY][table[middle].foundry]);
2891 fontnames[middle] = g_slist_prepend (fontnames[middle],
2902 /* Add another entry to the table for this new font family */
2903 temp_info.family = family_exists ? family : g_strdup(family);
2904 temp_info.foundry = foundry;
2905 temp_fontname = g_slist_prepend (NULL, fontname);
2909 /* Quickly insert the entry into the table in sorted order
2910 * using a modification of insertion sort and the knowledge
2911 * that the entries proper position in the table was determined
2912 * above in the binary search and is contained in the "lower"
2916 upper = *ntable - 1;
2917 while (lower != upper)
2919 table[upper] = table[upper-1];
2920 fontnames[upper] = fontnames[upper-1];
2924 table[lower] = temp_info;
2925 fontnames[lower] = temp_fontname;
2929 /* This checks that the specified field of the given fontname is in the
2930 appropriate properties array. If not it is added. Thus eventually we get
2931 arrays of all possible weights/slants etc. It returns the array index. */
2933 gtk_font_selection_insert_field (gchar *fontname,
2936 gchar field_buffer[XLFD_MAX_FIELD_LEN];
2940 field = gtk_font_selection_get_xlfd_field (fontname, xlfd_index[prop],
2945 /* If the field is already in the array just return its index. */
2946 for (index = 0; index < fontsel_info->nproperties[prop]; index++)
2947 if (!strcmp(field, fontsel_info->properties[prop][index]))
2950 /* Make sure we have enough space to add the field. */
2951 if (fontsel_info->nproperties[prop] == fontsel_info->space_allocated[prop])
2953 fontsel_info->space_allocated[prop] += PROPERTY_ARRAY_INCREMENT;
2954 fontsel_info->properties[prop] = g_realloc(fontsel_info->properties[prop],
2956 * fontsel_info->space_allocated[prop]);
2959 /* Add the new field. */
2960 index = fontsel_info->nproperties[prop];
2961 fontsel_info->properties[prop][index] = g_strdup(field);
2962 fontsel_info->nproperties[prop]++;
2967 /*****************************************************************************
2968 * These functions are the main public interface for getting/setting the font.
2969 *****************************************************************************/
2972 gtk_font_selection_get_font (GtkFontSelection *fontsel)
2974 g_return_val_if_fail (fontsel != NULL, NULL);
2975 return fontsel->font;
2980 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
2983 gchar *family_str, *foundry_str;
2984 gchar *property_str[GTK_NUM_STYLE_PROPERTIES];
2987 g_return_val_if_fail (fontsel != NULL, NULL);
2988 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
2990 /* If no family has been selected return NULL. */
2991 if (fontsel->font_index == -1)
2994 font = &fontsel_info->font_info[fontsel->font_index];
2995 family_str = font->family;
2996 foundry_str = fontsel_info->properties[FOUNDRY][font->foundry];
2998 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
3001 = fontsel_info->properties[prop][fontsel->property_values[prop]];
3002 if (strcmp (property_str[prop], "(nil)") == 0)
3003 property_str[prop] = "";
3006 return gtk_font_selection_create_xlfd (fontsel->size,
3010 property_str[WEIGHT],
3011 property_str[SLANT],
3012 property_str[SET_WIDTH],
3013 property_str[SPACING],
3014 property_str[CHARSET]);
3018 /* This returns the style with the best match to the current fontsel setting,
3019 i.e. with the highest number of matching property values. */
3021 gtk_font_selection_get_best_match(GtkFontSelection *fontsel)
3025 gint prop, style, best_style = 0, matched, best_matched = 0;
3027 font = &fontsel_info->font_info[fontsel->font_index];
3028 styles = &fontsel_info->font_styles[font->style_index];
3030 /* Find the style with the most matches. */
3031 for (style = 0; style < font->nstyles; style++)
3034 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
3036 if (fontsel->property_values[prop] == styles[style].properties[prop])
3039 if (matched > best_matched)
3041 best_matched = matched;
3050 /* This sets the current font, selecting the appropriate clist rows.
3051 First we check the fontname is valid and try to find the font family
3052 - i.e. the name in the main list. If we can't find that, then just return.
3053 Next we try to set each of the properties according to the fontname.
3054 Finally we select the font family & style in the clists. */
3056 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
3057 const gchar *fontname)
3059 gchar *family, *field;
3060 gint index, prop, size;
3061 guint16 foundry, value;
3062 gchar family_buffer[XLFD_MAX_FIELD_LEN];
3063 gchar field_buffer[XLFD_MAX_FIELD_LEN];
3066 g_return_val_if_fail (fontsel != NULL, FALSE);
3067 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
3068 g_return_val_if_fail (fontname != NULL, FALSE);
3070 /* Check it is a valid fontname. */
3071 if (!gtk_font_selection_is_xlfd_font_name(fontname))
3074 family = gtk_font_selection_get_xlfd_field (fontname, XLFD_FAMILY,
3079 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_FOUNDRY,
3081 foundry = gtk_font_selection_field_to_index (fontsel_info->properties[FOUNDRY],
3082 fontsel_info->nproperties[FOUNDRY],
3085 index = gtk_font_selection_find_font(fontsel, family, foundry);
3089 /* Convert the property fields into indices and set them. */
3090 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
3092 field = gtk_font_selection_get_xlfd_field (fontname, xlfd_index[prop],
3094 value = gtk_font_selection_field_to_index (fontsel_info->properties[prop],
3095 fontsel_info->nproperties[prop],
3097 fontsel->property_values[prop] = value;
3100 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_POINTS,
3107 fontsel->size = fontsel->selected_size = size;
3108 fontsel->metric = GTK_FONT_METRIC_POINTS;
3109 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->points_button),
3112 sprintf (buffer, "%i", size / 10);
3114 sprintf (buffer, "%i.%i", size / 10, size % 10);
3118 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_PIXELS,
3123 fontsel->size = fontsel->selected_size = size;
3124 fontsel->metric = GTK_FONT_METRIC_PIXELS;
3125 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->pixels_button),
3127 sprintf (buffer, "%i", size);
3129 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
3131 /* Clear any current filter. */
3132 gtk_font_selection_clear_filter(fontsel);
3134 /* Now find the best style match. */
3135 fontsel->font_index = index;
3136 gtk_clist_select_row(GTK_CLIST(fontsel->font_clist), index, 0);
3137 if (GTK_WIDGET_MAPPED (fontsel->font_clist))
3138 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), index, -1, 0.5, 0);
3140 gtk_font_selection_show_available_styles (fontsel);
3141 /* This will load the font. */
3142 gtk_font_selection_select_best_style (fontsel, FALSE);
3148 /* Returns the index of the given family, or -1 if not found */
3150 gtk_font_selection_find_font (GtkFontSelection *fontsel,
3154 FontInfo *font_info;
3155 gint lower, upper, middle = -1, cmp, nfonts;
3157 font_info = fontsel_info->font_info;
3158 nfonts = fontsel_info->nfonts;
3162 /* Do a binary search to find the font family. */
3165 while (lower < upper)
3167 middle = (lower + upper) >> 1;
3169 cmp = strcmp (family, font_info[middle].family);
3171 cmp = strcmp(fontsel_info->properties[FOUNDRY][foundry],
3172 fontsel_info->properties[FOUNDRY][font_info[middle].foundry]);
3182 /* If we can't match family & foundry see if just the family matches */
3183 if (!strcmp (family, font_info[middle].family))
3190 /* This returns the text in the preview entry. You should copy the returned
3191 text if you need it. */
3193 gtk_font_selection_get_preview_text (GtkFontSelection *fontsel)
3195 return gtk_entry_get_text(GTK_ENTRY(fontsel->preview_entry));
3199 /* This sets the text in the preview entry. */
3201 gtk_font_selection_set_preview_text (GtkFontSelection *fontsel,
3204 gtk_entry_set_text(GTK_ENTRY(fontsel->preview_entry), text);
3208 /*****************************************************************************
3209 * These functions all deal with X Logical Font Description (XLFD) fontnames.
3210 * See the freely available documentation about this.
3211 *****************************************************************************/
3214 * Returns TRUE if the fontname is a valid XLFD.
3215 * (It just checks if the number of dashes is 14, and that each
3216 * field < XLFD_MAX_FIELD_LEN characters long - that's not in the XLFD but it
3217 * makes it easier for me).
3220 gtk_font_selection_is_xlfd_font_name (const gchar *fontname)
3227 if (*fontname++ == '-')
3229 if (field_len > XLFD_MAX_FIELD_LEN) return FALSE;
3237 return (i == 14) ? TRUE : FALSE;
3241 * This fills the buffer with the specified field from the X Logical Font
3242 * Description name, and returns it. If fontname is NULL or the field is
3243 * longer than XFLD_MAX_FIELD_LEN it returns NULL.
3244 * Note: For the charset field, we also return the encoding, e.g. 'iso8859-1'.
3247 gtk_font_selection_get_xlfd_field (const gchar *fontname,
3248 FontField field_num,
3251 const gchar *t1, *t2;
3252 gint countdown, len, num_dashes;
3257 /* we assume this is a valid fontname...that is, it has 14 fields */
3259 countdown = field_num;
3261 while (*t1 && (countdown >= 0))
3265 num_dashes = (field_num == XLFD_CHARSET) ? 2 : 1;
3266 for (t2 = t1; *t2; t2++)
3268 if (*t2 == '-' && --num_dashes == 0)
3274 /* Check we don't overflow the buffer */
3275 len = (long) t2 - (long) t1;
3276 if (len > XLFD_MAX_FIELD_LEN - 1)
3278 strncpy (buffer, t1, len);
3281 /* Convert to lower case. */
3285 strcpy(buffer, "(nil)");
3291 * This returns a X Logical Font Description font name, given all the pieces.
3292 * Note: this retval must be freed by the caller.
3295 gtk_font_selection_create_xlfd (gint size,
3296 GtkFontMetricType metric,
3306 gchar *pixel_size = "*", *point_size = "*", *fontname;
3312 sprintf (buffer, "%d", (int) size);
3313 if (metric == GTK_FONT_METRIC_PIXELS)
3314 pixel_size = buffer;
3316 point_size = buffer;
3318 /* Note: be careful here - don't overrun the allocated memory. */
3319 length = strlen(foundry) + strlen(family) + strlen(weight) + strlen(slant)
3320 + strlen(set_width) + strlen(pixel_size) + strlen(point_size)
3321 + strlen(spacing) + strlen(charset)
3322 + 1 + 1 + 1 + 1 + 1 + 3 + 1 + 5 + 3
3323 + 1 /* for the terminating '\0'. */;
3325 fontname = g_new(gchar, length);
3326 /* **NOTE**: If you change this string please change length above! */
3327 sprintf(fontname, "-%s-%s-%s-%s-%s-*-%s-%s-*-*-%s-*-%s",
3328 foundry, family, weight, slant, set_width, pixel_size,
3329 point_size, spacing, charset);
3335 /*****************************************************************************
3336 * GtkFontSelectionDialog
3337 *****************************************************************************/
3340 gtk_font_selection_dialog_get_type (void)
3342 static guint font_selection_dialog_type = 0;
3344 if (!font_selection_dialog_type)
3346 GtkTypeInfo fontsel_diag_info =
3348 "GtkFontSelectionDialog",
3349 sizeof (GtkFontSelectionDialog),
3350 sizeof (GtkFontSelectionDialogClass),
3351 (GtkClassInitFunc) gtk_font_selection_dialog_class_init,
3352 (GtkObjectInitFunc) gtk_font_selection_dialog_init,
3353 /* reserved_1 */ NULL,
3354 /* reserved_2 */ NULL,
3355 (GtkClassInitFunc) NULL,
3358 font_selection_dialog_type = gtk_type_unique (GTK_TYPE_WINDOW, &fontsel_diag_info);
3361 return font_selection_dialog_type;
3365 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
3367 GtkObjectClass *object_class;
3369 object_class = (GtkObjectClass*) klass;
3371 font_selection_dialog_parent_class = gtk_type_class (GTK_TYPE_WINDOW);
3375 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
3377 fontseldiag->dialog_width = -1;
3378 fontseldiag->auto_resize = TRUE;
3380 gtk_widget_set_events(GTK_WIDGET(fontseldiag), GDK_STRUCTURE_MASK);
3381 gtk_signal_connect (GTK_OBJECT (fontseldiag), "configure_event",
3382 (GtkSignalFunc) gtk_font_selection_dialog_on_configure,
3385 gtk_container_border_width (GTK_CONTAINER (fontseldiag), 4);
3386 gtk_window_set_policy(GTK_WINDOW(fontseldiag), FALSE, TRUE, TRUE);
3388 fontseldiag->main_vbox = gtk_vbox_new (FALSE, 4);
3389 gtk_widget_show (fontseldiag->main_vbox);
3390 gtk_container_add (GTK_CONTAINER (fontseldiag), fontseldiag->main_vbox);
3392 fontseldiag->fontsel = gtk_font_selection_new();
3393 gtk_widget_show (fontseldiag->fontsel);
3394 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
3395 fontseldiag->fontsel, TRUE, TRUE, 0);
3397 /* Create the action area */
3398 fontseldiag->action_area = gtk_hbutton_box_new ();
3399 gtk_button_box_set_layout(GTK_BUTTON_BOX(fontseldiag->action_area),
3401 gtk_button_box_set_spacing(GTK_BUTTON_BOX(fontseldiag->action_area), 5);
3402 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
3403 fontseldiag->action_area, FALSE, FALSE, 0);
3404 gtk_widget_show (fontseldiag->action_area);
3406 fontseldiag->ok_button = gtk_button_new_with_label("OK");
3407 GTK_WIDGET_SET_FLAGS (fontseldiag->ok_button, GTK_CAN_DEFAULT);
3408 gtk_widget_show(fontseldiag->ok_button);
3409 gtk_box_pack_start (GTK_BOX (fontseldiag->action_area),
3410 fontseldiag->ok_button, TRUE, TRUE, 0);
3411 gtk_widget_grab_default (fontseldiag->ok_button);
3413 fontseldiag->apply_button = gtk_button_new_with_label("Apply");
3414 GTK_WIDGET_SET_FLAGS (fontseldiag->apply_button, GTK_CAN_DEFAULT);
3415 /*gtk_widget_show(fontseldiag->apply_button);*/
3416 gtk_box_pack_start (GTK_BOX(fontseldiag->action_area),
3417 fontseldiag->apply_button, TRUE, TRUE, 0);
3419 fontseldiag->cancel_button = gtk_button_new_with_label("Cancel");
3420 GTK_WIDGET_SET_FLAGS (fontseldiag->cancel_button, GTK_CAN_DEFAULT);
3421 gtk_widget_show(fontseldiag->cancel_button);
3422 gtk_box_pack_start (GTK_BOX(fontseldiag->action_area),
3423 fontseldiag->cancel_button, TRUE, TRUE, 0);
3429 gtk_font_selection_dialog_new (const gchar *title)
3431 GtkFontSelectionDialog *fontseldiag;
3433 fontseldiag = gtk_type_new (GTK_TYPE_FONT_SELECTION_DIALOG);
3434 gtk_window_set_title (GTK_WINDOW (fontseldiag),
3435 title ? title : "Font Selection");
3437 return GTK_WIDGET (fontseldiag);
3441 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
3443 return gtk_font_selection_get_font_name(GTK_FONT_SELECTION(fsd->fontsel));
3447 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
3449 return gtk_font_selection_get_font(GTK_FONT_SELECTION(fsd->fontsel));
3453 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
3454 const gchar *fontname)
3456 return gtk_font_selection_set_font_name(GTK_FONT_SELECTION(fsd->fontsel),
3461 gtk_font_selection_dialog_set_filter (GtkFontSelectionDialog *fsd,
3462 GtkFontFilterType filter_type,
3463 GtkFontType font_type,
3471 gtk_font_selection_set_filter (GTK_FONT_SELECTION (fsd->fontsel),
3472 filter_type, font_type,
3473 foundries, weights, slants, setwidths,
3474 spacings, charsets);
3478 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
3480 return gtk_font_selection_get_preview_text(GTK_FONT_SELECTION(fsd->fontsel));
3484 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
3487 gtk_font_selection_set_preview_text(GTK_FONT_SELECTION(fsd->fontsel), text);
3491 /* This turns auto-shrink off if the user resizes the width of the dialog.
3492 It also turns it back on again if the user resizes it back to its normal
3495 gtk_font_selection_dialog_on_configure (GtkWidget *widget,
3496 GdkEventConfigure *event,
3497 GtkFontSelectionDialog *fsd)
3499 /* This sets the initial width. */
3500 if (fsd->dialog_width == -1)
3501 fsd->dialog_width = event->width;
3502 else if (fsd->auto_resize && fsd->dialog_width != event->width)
3504 fsd->auto_resize = FALSE;
3505 gtk_window_set_policy(GTK_WINDOW(fsd), FALSE, TRUE, FALSE);
3507 else if (!fsd->auto_resize && fsd->dialog_width == event->width)
3509 fsd->auto_resize = TRUE;
3510 gtk_window_set_policy(GTK_WINDOW(fsd), FALSE, TRUE, TRUE);