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"
84 #include "gtkscrolledwindow.h"
86 /* The maximum number of fontnames requested with XListFonts(). */
87 #define MAX_FONTS 32767
89 /* This is the largest field length we will accept. If a fontname has a field
90 larger than this we will skip it. */
91 #define XLFD_MAX_FIELD_LEN 64
93 /* These are what we use as the standard font sizes, for the size clist.
94 Note that when using points we still show these integer point values but
95 we work internally in decipoints (and decipoint values can be typed in). */
96 static guint16 font_sizes[] = {
97 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28,
98 32, 36, 40, 48, 56, 64, 72
101 /* Initial font metric & size (Remember point sizes are in decipoints).
102 The font size should match one of those in the font_sizes array. */
103 #define INITIAL_METRIC GTK_FONT_METRIC_POINTS
104 #define INITIAL_FONT_SIZE 140
106 /* This is the default text shown in the preview entry, though the user
107 can set it. Remember that some fonts only have capital letters. */
108 #define PREVIEW_TEXT "abcdefghijk ABCDEFGHIJK"
110 /* This is the initial and maximum height of the preview entry (it expands
111 when large font sizes are selected). Initial height is also the minimum. */
112 #define INITIAL_PREVIEW_HEIGHT 44
113 #define MAX_PREVIEW_HEIGHT 300
115 /* These are the sizes of the font, style & size clists. */
116 #define FONT_LIST_HEIGHT 136
117 #define FONT_LIST_WIDTH 180
118 #define FONT_STYLE_LIST_WIDTH 160
119 #define FONT_SIZE_LIST_WIDTH 60
121 /* This is the number of fields in an X Logical Font Description font name.
122 Note that we count the registry & encoding as 1. */
123 #define GTK_XLFD_NUM_FIELDS 13
125 typedef struct _GtkFontSelInfo GtkFontSelInfo;
126 typedef struct _FontInfo FontInfo;
127 typedef struct _FontStyle FontStyle;
129 /* This struct represents one family of fonts (with one foundry), e.g. adobe
130 courier or sony fixed. It stores the family name, the index of the foundry
131 name, and the index of and number of available styles. */
140 /* This represents one style, as displayed in the Font Style clist. It can
141 have a number of available pixel sizes and point sizes. The indexes point
142 into the two big fontsel_info->pixel_sizes & fontsel_info->point_sizes
143 arrays. The displayed flag is used when displaying styles to remember which
144 styles have already been displayed. Note that it is combined with the
145 GtkFontType in the flags field. */
146 #define GTK_FONT_DISPLAYED (1 << 7)
149 guint16 properties[GTK_NUM_STYLE_PROPERTIES];
150 gint pixel_sizes_index;
151 guint16 npixel_sizes;
152 gint point_sizes_index;
153 guint16 npoint_sizes;
157 struct _GtkFontSelInfo {
159 /* This is a table with each FontInfo representing one font family+foundry */
163 /* This stores all the valid combinations of properties for every family.
164 Each FontInfo holds an index into its own space in this one big array. */
165 FontStyle *font_styles;
168 /* This stores all the font sizes available for every style.
169 Each style holds an index into these arrays. */
170 guint16 *pixel_sizes;
171 guint16 *point_sizes;
173 /* These are the arrays of strings of all possible weights, slants,
174 set widths, spacings, charsets & foundries, and the amount of space
175 allocated for each array. */
176 gchar **properties[GTK_NUM_FONT_PROPERTIES];
177 guint16 nproperties[GTK_NUM_FONT_PROPERTIES];
178 guint16 space_allocated[GTK_NUM_FONT_PROPERTIES];
181 /* These are the field numbers in the X Logical Font Description fontnames,
182 e.g. -adobe-courier-bold-o-normal--25-180-100-100-m-150-iso8859-1 */
193 XLFD_RESOLUTION_X = 8,
194 XLFD_RESOLUTION_Y = 9,
196 XLFD_AVERAGE_WIDTH = 11,
200 /* These are the names of the fields, used on the info & filter page. */
201 static gchar* xlfd_field_names[GTK_XLFD_NUM_FIELDS] = {
217 /* These are the array indices of the font properties used in several arrays,
218 and should match the xlfd_index array below. */
229 /* This is used to look up a field in a fontname given one of the above
231 static FontField xlfd_index[GTK_NUM_FONT_PROPERTIES] = {
240 /* These are the positions of the properties in the filter table - x, y. */
241 static gint filter_positions[GTK_NUM_FONT_PROPERTIES][2] = {
242 { 1, 0 }, { 0, 2 }, { 1, 2 }, { 2, 2 }, { 2, 0 }, { 0, 0 }
244 static gint filter_heights[GTK_NUM_FONT_PROPERTIES] = {
245 100, 70, 70, 40, 100, 100
248 /* This is returned by gtk_font_selection_filter_state to describe if a
249 property value is filtered. e.g. if 'bold' has been selected on the filter
250 page, then that will return 'FILTERED' and 'black' will be 'NOT_FILTERED'.
251 If none of the weight values are selected, they all return 'NOT_SET'. */
257 } GtkFontPropertyFilterState;
259 static GtkFontSelInfo *fontsel_info = NULL;
261 /* The initial size and increment of each of the arrays of property values. */
262 #define PROPERTY_ARRAY_INCREMENT 16
264 static void gtk_font_selection_class_init (GtkFontSelectionClass *klass);
265 static void gtk_font_selection_init (GtkFontSelection *fontsel);
266 static void gtk_font_selection_destroy (GtkObject *object);
268 /* These are all used for class initialization - loading in the fonts etc. */
269 static void gtk_font_selection_get_fonts (void);
270 static void gtk_font_selection_insert_font (GSList *fontnames[],
273 static gint gtk_font_selection_insert_field (gchar *fontname,
276 /* These are the callbacks & related functions. */
277 static void gtk_font_selection_select_font (GtkWidget *w,
280 GdkEventButton *bevent,
282 static gint gtk_font_selection_on_clist_key_press (GtkWidget *clist,
284 GtkFontSelection *fs);
285 static gboolean gtk_font_selection_select_next (GtkFontSelection *fs,
288 static void gtk_font_selection_show_available_styles
289 (GtkFontSelection *fs);
290 static void gtk_font_selection_select_best_style (GtkFontSelection *fs,
292 static gint gtk_font_selection_get_best_match (GtkFontSelection *fs);
294 static void gtk_font_selection_select_style (GtkWidget *w,
297 GdkEventButton *bevent,
299 static void gtk_font_selection_show_available_sizes
300 (GtkFontSelection *fs);
301 static gint gtk_font_selection_size_key_press (GtkWidget *w,
304 static void gtk_font_selection_select_best_size (GtkFontSelection *fs);
305 static void gtk_font_selection_select_size (GtkWidget *w,
308 GdkEventButton *bevent,
311 static void gtk_font_selection_metric_callback (GtkWidget *w,
313 static void gtk_font_selection_expose_list (GtkWidget *w,
314 GdkEventExpose *event,
317 static void gtk_font_selection_switch_page (GtkWidget *w,
318 GtkNotebookPage *page,
321 static void gtk_font_selection_show_font_info (GtkFontSelection *fs);
323 static void gtk_font_selection_select_filter (GtkWidget *w,
326 GdkEventButton *bevent,
327 GtkFontSelection *fs);
328 static void gtk_font_selection_unselect_filter (GtkWidget *w,
331 GdkEventButton *bevent,
332 GtkFontSelection *fs);
333 static void gtk_font_selection_update_filter (GtkFontSelection *fs);
334 static gboolean gtk_font_selection_style_visible (GtkFontSelection *fs,
337 static void gtk_font_selection_reset_filter (GtkWidget *w,
338 GtkFontSelection *fs);
339 static void gtk_font_selection_on_clear_filter (GtkWidget *w,
340 GtkFontSelection *fs);
341 static void gtk_font_selection_show_available_fonts
342 (GtkFontSelection *fs);
343 static void gtk_font_selection_clear_filter (GtkFontSelection *fs);
344 static void gtk_font_selection_update_filter_lists(GtkFontSelection *fs);
345 static GtkFontPropertyFilterState gtk_font_selection_filter_state
346 (GtkFontSelection *fs,
347 GtkFontFilterType filter_type,
351 /* Misc. utility functions. */
352 static gboolean gtk_font_selection_load_font (GtkFontSelection *fs);
353 static void gtk_font_selection_update_preview (GtkFontSelection *fs);
355 static gint gtk_font_selection_find_font (GtkFontSelection *fs,
358 static guint16 gtk_font_selection_field_to_index (gchar **table,
362 static gchar* gtk_font_selection_expand_slant_code (gchar *slant);
363 static gchar* gtk_font_selection_expand_spacing_code(gchar *spacing);
365 /* Functions for handling X Logical Font Description fontnames. */
366 static gboolean gtk_font_selection_is_xlfd_font_name (const gchar *fontname);
367 static char* gtk_font_selection_get_xlfd_field (const gchar *fontname,
370 static gchar * gtk_font_selection_create_xlfd (gint size,
371 GtkFontMetricType metric,
381 /* FontSelectionDialog */
382 static void gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass);
383 static void gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag);
385 static gint gtk_font_selection_dialog_on_configure(GtkWidget *widget,
386 GdkEventConfigure *event,
387 GtkFontSelectionDialog *fsd);
389 static GtkWindowClass *font_selection_parent_class = NULL;
390 static GtkNotebookClass *font_selection_dialog_parent_class = NULL;
393 gtk_font_selection_get_type()
395 static GtkType font_selection_type = 0;
397 if(!font_selection_type)
399 GtkTypeInfo fontsel_type_info =
402 sizeof (GtkFontSelection),
403 sizeof (GtkFontSelectionClass),
404 (GtkClassInitFunc) gtk_font_selection_class_init,
405 (GtkObjectInitFunc) gtk_font_selection_init,
406 /* reserved_1 */ NULL,
407 /* reserved_2 */ NULL,
408 (GtkClassInitFunc) NULL,
411 font_selection_type = gtk_type_unique (GTK_TYPE_NOTEBOOK,
415 return font_selection_type;
419 gtk_font_selection_class_init(GtkFontSelectionClass *klass)
421 GtkObjectClass *object_class;
423 object_class = (GtkObjectClass *) klass;
425 font_selection_parent_class = gtk_type_class (GTK_TYPE_NOTEBOOK);
427 object_class->destroy = gtk_font_selection_destroy;
429 gtk_font_selection_get_fonts ();
433 gtk_font_selection_init(GtkFontSelection *fontsel)
435 GtkWidget *scrolled_win;
436 GtkWidget *text_frame;
437 GtkWidget *text_box, *frame;
438 GtkWidget *table, *label, *hbox, *hbox2, *clist, *button, *vbox, *alignment;
440 gchar *titles[] = { "Font Property", "Requested Value", "Actual Value" };
445 gchar *property, *text;
448 /* Initialize the GtkFontSelection struct. We do this here in case any
449 callbacks are triggered while creating the interface. */
450 fontsel->font = NULL;
451 fontsel->font_index = -1;
453 fontsel->metric = INITIAL_METRIC;
454 fontsel->size = INITIAL_FONT_SIZE;
455 fontsel->selected_size = INITIAL_FONT_SIZE;
457 fontsel->filters[GTK_FONT_FILTER_BASE].font_type = GTK_FONT_ALL;
458 fontsel->filters[GTK_FONT_FILTER_USER].font_type = GTK_FONT_BITMAP
462 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
464 fontsel->filters[GTK_FONT_FILTER_BASE].property_filters[prop] = NULL;
465 fontsel->filters[GTK_FONT_FILTER_BASE].property_nfilters[prop] = 0;
466 fontsel->filters[GTK_FONT_FILTER_USER].property_filters[prop] = NULL;
467 fontsel->filters[GTK_FONT_FILTER_USER].property_nfilters[prop] = 0;
470 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
471 fontsel->property_values[prop] = 0;
473 /* Create the main notebook page. */
474 fontsel->main_vbox = gtk_vbox_new (FALSE, 4);
475 gtk_widget_show (fontsel->main_vbox);
476 gtk_container_border_width (GTK_CONTAINER (fontsel->main_vbox), 6);
477 label = gtk_label_new("Font");
478 gtk_widget_set_usize (label, 120, -1);
479 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
480 fontsel->main_vbox, label);
482 /* Create the table of font, style & size. */
483 table = gtk_table_new (3, 3, FALSE);
484 gtk_widget_show (table);
485 gtk_table_set_col_spacings(GTK_TABLE(table), 8);
486 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), table, TRUE, TRUE, 0);
488 fontsel->font_label = gtk_label_new("Font:");
489 gtk_misc_set_alignment (GTK_MISC (fontsel->font_label), 0.0, 0.5);
490 gtk_widget_show (fontsel->font_label);
491 gtk_table_attach (GTK_TABLE (table), fontsel->font_label, 0, 1, 0, 1,
493 label = gtk_label_new("Font Style:");
494 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
495 gtk_widget_show (label);
496 gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1,
498 label = gtk_label_new("Size:");
499 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
500 gtk_widget_show (label);
501 gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
504 fontsel->font_entry = gtk_entry_new();
505 gtk_entry_set_editable(GTK_ENTRY(fontsel->font_entry), FALSE);
506 gtk_widget_set_usize (fontsel->font_entry, 20, -1);
507 gtk_widget_show (fontsel->font_entry);
508 gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
510 fontsel->font_style_entry = gtk_entry_new();
511 gtk_entry_set_editable(GTK_ENTRY(fontsel->font_style_entry), FALSE);
512 gtk_widget_set_usize (fontsel->font_style_entry, 20, -1);
513 gtk_widget_show (fontsel->font_style_entry);
514 gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
516 fontsel->size_entry = gtk_entry_new();
517 gtk_widget_set_usize (fontsel->size_entry, 20, -1);
518 gtk_widget_show (fontsel->size_entry);
519 gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
521 gtk_signal_connect (GTK_OBJECT (fontsel->size_entry), "key_press_event",
522 (GtkSignalFunc) gtk_font_selection_size_key_press,
525 /* Create the clists */
526 fontsel->font_clist = gtk_clist_new(1);
527 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->font_clist));
528 gtk_clist_set_column_width (GTK_CLIST(fontsel->font_clist), 0, 300);
529 gtk_widget_set_usize (fontsel->font_clist, FONT_LIST_WIDTH,
531 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
532 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->font_clist);
533 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
534 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
535 gtk_widget_show(fontsel->font_clist);
536 gtk_widget_show(scrolled_win);
538 gtk_table_attach (GTK_TABLE (table), scrolled_win, 0, 1, 2, 3,
539 GTK_EXPAND | GTK_FILL,
540 GTK_EXPAND | GTK_FILL, 0, 0);
542 fontsel->font_style_clist = gtk_clist_new(1);
543 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->font_style_clist));
544 gtk_clist_set_column_width (GTK_CLIST(fontsel->font_style_clist), 0, 300);
545 gtk_widget_set_usize (fontsel->font_style_clist, FONT_STYLE_LIST_WIDTH, -1);
546 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
547 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->font_style_clist);
548 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
549 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
550 gtk_widget_show(fontsel->font_style_clist);
551 gtk_widget_show(scrolled_win);
552 gtk_table_attach (GTK_TABLE (table), scrolled_win, 1, 2, 2, 3,
553 GTK_EXPAND | GTK_FILL,
554 GTK_EXPAND | GTK_FILL, 0, 0);
556 fontsel->size_clist = gtk_clist_new(1);
557 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->size_clist));
558 gtk_widget_set_usize (fontsel->size_clist, FONT_SIZE_LIST_WIDTH, -1);
559 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
560 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->size_clist);
561 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
562 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
563 gtk_widget_show(fontsel->size_clist);
564 gtk_widget_show(scrolled_win);
565 gtk_table_attach (GTK_TABLE (table), scrolled_win, 2, 3, 2, 3,
566 GTK_FILL, GTK_FILL, 0, 0);
569 /* Insert the fonts. If there exist fonts with the same family but
570 different foundries, then the foundry name is appended in brackets. */
571 gtk_font_selection_show_available_fonts(fontsel);
573 gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "select_row",
574 GTK_SIGNAL_FUNC(gtk_font_selection_select_font),
576 GTK_WIDGET_SET_FLAGS (fontsel->font_clist, GTK_CAN_FOCUS);
577 gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "key_press_event",
578 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
580 gtk_signal_connect_after (GTK_OBJECT (fontsel->font_clist), "expose_event",
581 GTK_SIGNAL_FUNC(gtk_font_selection_expose_list),
584 gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist), "select_row",
585 GTK_SIGNAL_FUNC(gtk_font_selection_select_style),
587 GTK_WIDGET_SET_FLAGS (fontsel->font_style_clist, GTK_CAN_FOCUS);
588 gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist),
590 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
593 /* Insert the standard font sizes */
594 gtk_clist_freeze (GTK_CLIST(fontsel->size_clist));
595 size_to_match = INITIAL_FONT_SIZE;
596 if (INITIAL_METRIC == GTK_FONT_METRIC_POINTS)
597 size_to_match = size_to_match / 10;
598 for (i = 0; i < sizeof(font_sizes) / sizeof(font_sizes[0]); i++)
600 sprintf(buffer, "%i", font_sizes[i]);
602 gtk_clist_append(GTK_CLIST(fontsel->size_clist), &size);
603 if (font_sizes[i] == size_to_match)
605 gtk_clist_select_row(GTK_CLIST(fontsel->size_clist), i, 0);
606 gtk_entry_set_text(GTK_ENTRY(fontsel->size_entry), buffer);
609 gtk_clist_thaw (GTK_CLIST(fontsel->size_clist));
611 gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "select_row",
612 GTK_SIGNAL_FUNC(gtk_font_selection_select_size),
614 GTK_WIDGET_SET_FLAGS (fontsel->size_clist, GTK_CAN_FOCUS);
615 gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "key_press_event",
616 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
620 /* create the Reset Filter & Metric buttons */
621 hbox = gtk_hbox_new(FALSE, 8);
622 gtk_widget_show (hbox);
623 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), hbox, FALSE, TRUE, 0);
625 fontsel->filter_button = gtk_button_new_with_label(" Reset Filter ");
626 gtk_widget_show(fontsel->filter_button);
627 gtk_box_pack_start (GTK_BOX (hbox), fontsel->filter_button, FALSE, FALSE, 0);
628 gtk_widget_set_sensitive (fontsel->filter_button, FALSE);
629 gtk_signal_connect (GTK_OBJECT (fontsel->filter_button), "clicked",
630 GTK_SIGNAL_FUNC(gtk_font_selection_on_clear_filter),
633 hbox2 = gtk_hbox_new(FALSE, 0);
634 gtk_widget_show (hbox2);
635 gtk_box_pack_end (GTK_BOX (hbox), hbox2, FALSE, FALSE, 0);
637 label = gtk_label_new("Metric:");
638 gtk_widget_show (label);
639 gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 8);
641 fontsel->points_button = gtk_radio_button_new_with_label(NULL, "Points");
642 gtk_widget_show (fontsel->points_button);
643 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->points_button, FALSE, TRUE, 0);
644 if (INITIAL_METRIC == GTK_FONT_METRIC_POINTS)
645 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->points_button),
648 fontsel->pixels_button = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(fontsel->points_button), "Pixels");
649 gtk_widget_show (fontsel->pixels_button);
650 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->pixels_button, FALSE, TRUE, 0);
651 if (INITIAL_METRIC == GTK_FONT_METRIC_PIXELS)
652 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->pixels_button),
655 gtk_signal_connect(GTK_OBJECT(fontsel->points_button), "toggled",
656 (GtkSignalFunc) gtk_font_selection_metric_callback,
658 gtk_signal_connect(GTK_OBJECT(fontsel->pixels_button), "toggled",
659 (GtkSignalFunc) gtk_font_selection_metric_callback,
663 /* create the text entry widget */
664 text_frame = gtk_frame_new ("Preview:");
665 gtk_widget_show (text_frame);
666 gtk_frame_set_shadow_type(GTK_FRAME(text_frame), GTK_SHADOW_ETCHED_IN);
667 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), text_frame,
670 /* This is just used to get a 4-pixel space around the preview entry. */
671 text_box = gtk_hbox_new (FALSE, 0);
672 gtk_widget_show (text_box);
673 gtk_container_add (GTK_CONTAINER (text_frame), text_box);
674 gtk_container_border_width (GTK_CONTAINER (text_box), 4);
676 fontsel->preview_entry = gtk_entry_new ();
677 gtk_widget_show (fontsel->preview_entry);
678 gtk_widget_set_usize (fontsel->preview_entry, -1, INITIAL_PREVIEW_HEIGHT);
679 gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
682 /* Create the message area */
683 fontsel->message_label = gtk_label_new("");
684 gtk_widget_show (fontsel->message_label);
685 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), fontsel->message_label,
689 /* Create the font info page */
690 fontsel->info_vbox = gtk_vbox_new (FALSE, 4);
691 gtk_widget_show (fontsel->info_vbox);
692 gtk_container_border_width (GTK_CONTAINER (fontsel->info_vbox), 2);
693 label = gtk_label_new("Font Information");
694 gtk_widget_set_usize (label, 120, -1);
695 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
696 fontsel->info_vbox, label);
698 fontsel->info_clist = gtk_clist_new_with_titles (3, titles);
699 gtk_widget_set_usize (fontsel->info_clist, 390, 150);
700 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 0, 130);
701 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 1, 130);
702 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 2, 130);
703 gtk_clist_column_titles_passive(GTK_CLIST(fontsel->info_clist));
704 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
705 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->info_clist);
706 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
707 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
708 gtk_widget_show(fontsel->info_clist);
709 gtk_widget_show(scrolled_win);
710 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), scrolled_win,
713 /* Insert the property names */
714 gtk_clist_freeze (GTK_CLIST(fontsel->info_clist));
717 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
719 row_text[0] = xlfd_field_names[i];
720 gtk_clist_append(GTK_CLIST(fontsel->info_clist), row_text);
721 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 0, 0, 4);
722 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 1, 0, 4);
723 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 2, 0, 4);
725 gtk_clist_thaw (GTK_CLIST(fontsel->info_clist));
727 label = gtk_label_new("Requested Font Name:");
728 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
729 gtk_widget_show (label);
730 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, TRUE, 0);
732 fontsel->requested_font_name = gtk_entry_new();
733 gtk_entry_set_editable(GTK_ENTRY(fontsel->requested_font_name), FALSE);
734 gtk_widget_show (fontsel->requested_font_name);
735 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox),
736 fontsel->requested_font_name, FALSE, TRUE, 0);
738 label = gtk_label_new("Actual Font Name:");
739 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
740 gtk_widget_show (label);
741 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, TRUE, 0);
743 fontsel->actual_font_name = gtk_entry_new();
744 gtk_entry_set_editable(GTK_ENTRY(fontsel->actual_font_name), FALSE);
745 gtk_widget_show (fontsel->actual_font_name);
746 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox),
747 fontsel->actual_font_name, FALSE, TRUE, 0);
749 sprintf(buffer, "%i fonts available with a total of %i styles.",
750 fontsel_info->nfonts, fontsel_info->nstyles);
751 label = gtk_label_new(buffer);
752 gtk_widget_show (label);
753 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, FALSE, 0);
755 gtk_signal_connect (GTK_OBJECT (fontsel), "switch_page",
756 GTK_SIGNAL_FUNC(gtk_font_selection_switch_page),
760 /* Create the Filter page. */
761 fontsel->filter_vbox = gtk_vbox_new (FALSE, 4);
762 gtk_widget_show (fontsel->filter_vbox);
763 gtk_container_border_width (GTK_CONTAINER (fontsel->filter_vbox), 2);
764 label = gtk_label_new("Filter");
765 gtk_widget_set_usize (label, 120, -1);
766 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
767 fontsel->filter_vbox, label);
769 /* Create the font type checkbuttons. */
770 frame = gtk_frame_new (NULL);
771 gtk_widget_show (frame);
772 gtk_box_pack_start (GTK_BOX (fontsel->filter_vbox), frame, FALSE, TRUE, 0);
774 hbox = gtk_hbox_new (FALSE, 20);
775 gtk_widget_show (hbox);
776 gtk_container_add (GTK_CONTAINER (frame), hbox);
778 label = gtk_label_new("Font Types:");
779 gtk_widget_show (label);
780 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 10);
782 hbox2 = gtk_hbox_new (TRUE, 0);
783 gtk_widget_show (hbox2);
784 gtk_box_pack_start (GTK_BOX (hbox), hbox2, FALSE, TRUE, 0);
786 fontsel->type_bitmaps_button = gtk_check_button_new_with_label ("Bitmap");
787 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), TRUE);
788 gtk_widget_show (fontsel->type_bitmaps_button);
789 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_bitmaps_button,
792 fontsel->type_scalable_button = gtk_check_button_new_with_label ("Scalable");
793 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), TRUE);
794 gtk_widget_show (fontsel->type_scalable_button);
795 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_scalable_button,
798 fontsel->type_scaled_bitmaps_button = gtk_check_button_new_with_label ("Scaled Bitmap");
799 gtk_widget_show (fontsel->type_scaled_bitmaps_button);
800 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_scaled_bitmaps_button,
803 table = gtk_table_new (4, 3, FALSE);
804 gtk_table_set_col_spacings(GTK_TABLE(table), 2);
805 gtk_widget_show (table);
806 gtk_box_pack_start (GTK_BOX (fontsel->filter_vbox), table, TRUE, TRUE, 0);
808 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
810 gint left = filter_positions[prop][0];
811 gint top = filter_positions[prop][1];
813 label = gtk_label_new(xlfd_field_names[xlfd_index[prop]]);
814 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 1.0);
815 gtk_misc_set_padding (GTK_MISC (label), 0, 2);
816 gtk_widget_show(label);
817 gtk_table_attach (GTK_TABLE (table), label, left, left + 1,
818 top, top + 1, GTK_FILL, GTK_FILL, 0, 0);
820 clist = gtk_clist_new(1);
821 gtk_widget_set_usize (clist, 100, filter_heights[prop]);
822 gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_MULTIPLE);
823 gtk_clist_column_titles_hide(GTK_CLIST(clist));
824 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
825 gtk_container_add (GTK_CONTAINER (scrolled_win), clist);
826 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
827 GTK_POLICY_AUTOMATIC,
828 GTK_POLICY_AUTOMATIC);
829 gtk_widget_show(clist);
830 gtk_widget_show(scrolled_win);
832 /* For the bottom-right cell we add the 'Reset Filter' button. */
833 if (top == 2 && left == 2)
835 vbox = gtk_vbox_new(FALSE, 0);
836 gtk_widget_show(vbox);
837 gtk_table_attach (GTK_TABLE (table), vbox, left, left + 1,
838 top + 1, top + 2, GTK_FILL, GTK_FILL, 0, 0);
840 gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0);
842 alignment = gtk_alignment_new(0.5, 0.0, 0.8, 0.0);
843 gtk_widget_show(alignment);
844 gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, TRUE, 4);
846 button = gtk_button_new_with_label("Reset Filter");
847 gtk_widget_show(button);
848 gtk_container_add(GTK_CONTAINER(alignment), button);
849 gtk_signal_connect (GTK_OBJECT (button), "clicked",
850 GTK_SIGNAL_FUNC(gtk_font_selection_reset_filter),
854 gtk_table_attach (GTK_TABLE (table), scrolled_win,
855 left, left + 1, top + 1, top + 2,
856 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
858 gtk_signal_connect (GTK_OBJECT (clist), "select_row",
859 GTK_SIGNAL_FUNC(gtk_font_selection_select_filter),
861 gtk_signal_connect (GTK_OBJECT (clist), "unselect_row",
862 GTK_SIGNAL_FUNC(gtk_font_selection_unselect_filter),
865 /* Insert the property names, expanded, and in sorted order.
866 But we make sure that the wildcard '*' is first. */
867 gtk_clist_freeze (GTK_CLIST(clist));
869 gtk_clist_append(GTK_CLIST(clist), &property);
871 for (i = 1; i < fontsel_info->nproperties[prop]; i++) {
872 property = fontsel_info->properties[prop][i];
874 property = gtk_font_selection_expand_slant_code(property);
875 else if (prop == SPACING)
876 property = gtk_font_selection_expand_spacing_code(property);
879 for (row = 1; row < GTK_CLIST(clist)->rows; row++)
881 gtk_clist_get_text(GTK_CLIST(clist), row, 0, &text);
882 if (strcmp(property, text) < 0)
885 gtk_clist_insert(GTK_CLIST(clist), row, &property);
890 row = gtk_clist_append(GTK_CLIST(clist), &property);
891 gtk_clist_set_row_data(GTK_CLIST(clist), row, GINT_TO_POINTER (i));
893 gtk_clist_select_row(GTK_CLIST(clist), 0, 0);
894 gtk_clist_thaw (GTK_CLIST(clist));
895 fontsel->filter_clists[prop] = clist;
900 gtk_font_selection_new()
902 GtkFontSelection *fontsel;
904 fontsel = gtk_type_new (GTK_TYPE_FONT_SELECTION);
906 return GTK_WIDGET (fontsel);
910 gtk_font_selection_destroy (GtkObject *object)
912 GtkFontSelection *fontsel;
914 g_return_if_fail (object != NULL);
915 g_return_if_fail (GTK_IS_FONT_SELECTION (object));
917 fontsel = GTK_FONT_SELECTION (object);
919 /* All we have to do is unref the font, if we have one. */
921 gdk_font_unref (fontsel->font);
923 if (GTK_OBJECT_CLASS (font_selection_parent_class)->destroy)
924 (* GTK_OBJECT_CLASS (font_selection_parent_class)->destroy) (object);
928 /* This is called when the clist is exposed. Here we scroll to the current
929 font if necessary. */
931 gtk_font_selection_expose_list (GtkWidget *widget,
932 GdkEventExpose *event,
935 GtkFontSelection *fontsel;
941 g_message("In expose_list\n");
943 fontsel = GTK_FONT_SELECTION(data);
945 font_info = fontsel_info->font_info;
947 /* Try to scroll the font family clist to the selected item */
948 selection = GTK_CLIST(fontsel->font_clist)->selection;
951 index = GPOINTER_TO_INT (selection->data);
952 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_clist), index)
953 != GTK_VISIBILITY_FULL)
954 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), index, -1, 0.5, 0);
957 /* Try to scroll the font style clist to the selected item */
958 selection = GTK_CLIST(fontsel->font_style_clist)->selection;
961 index = GPOINTER_TO_INT (selection->data);
962 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_style_clist), index)
963 != GTK_VISIBILITY_FULL)
964 gtk_clist_moveto(GTK_CLIST(fontsel->font_style_clist), index, -1,
968 /* Try to scroll the font size clist to the selected item */
969 selection = GTK_CLIST(fontsel->size_clist)->selection;
972 index = GPOINTER_TO_INT (selection->data);
973 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->size_clist), index)
974 != GTK_VISIBILITY_FULL)
975 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), index, -1, 0.5, 0);
980 /* This is called when a family is selected in the list. */
982 gtk_font_selection_select_font (GtkWidget *w,
985 GdkEventButton *bevent,
988 GtkFontSelection *fontsel;
993 g_message("In select_font\n");
995 fontsel = GTK_FONT_SELECTION(data);
996 font_info = fontsel_info->font_info;
998 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
999 gtk_widget_grab_focus (w);
1001 row = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_clist), row));
1002 font = &font_info[row];
1003 gtk_entry_set_text(GTK_ENTRY(fontsel->font_entry), font->family);
1005 /* If it is already the current font, just return. */
1006 if (fontsel->font_index == row)
1009 fontsel->font_index = row;
1010 gtk_font_selection_show_available_styles (fontsel);
1011 gtk_font_selection_select_best_style (fontsel, TRUE);
1016 gtk_font_selection_on_clist_key_press (GtkWidget *clist,
1018 GtkFontSelection *fontsel)
1020 #ifdef FONTSEL_DEBUG
1021 g_message("In on_clist_key_press\n");
1023 if (event->keyval == GDK_Up)
1024 return gtk_font_selection_select_next (fontsel, clist, -1);
1025 else if (event->keyval == GDK_Down)
1026 return gtk_font_selection_select_next (fontsel, clist, 1);
1033 gtk_font_selection_select_next (GtkFontSelection *fontsel,
1038 gint current_row, row;
1040 selection = GTK_CLIST(clist)->selection;
1043 current_row = GPOINTER_TO_INT (selection->data);
1045 /* Stop the normal clist key handler from being run. */
1046 gtk_signal_emit_stop_by_name (GTK_OBJECT (clist), "key_press_event");
1048 for (row = current_row + step;
1049 row >= 0 && row < GTK_CLIST(clist)->rows;
1052 /* If this is the style clist, make sure that the item is not a charset
1054 if (clist == fontsel->font_style_clist)
1055 if (GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(clist), row)) == -1)
1058 /* Now we've found the row to select. */
1059 if (gtk_clist_row_is_visible(GTK_CLIST(clist), row)
1060 != GTK_VISIBILITY_FULL)
1061 gtk_clist_moveto(GTK_CLIST(clist), row, -1, (step < 0) ? 0 : 1, 0);
1062 gtk_clist_select_row(GTK_CLIST(clist), row, 0);
1069 /* This fills the font style clist with all the possible style combinations
1070 for the current font family. */
1072 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
1076 gint style, tmpstyle, row;
1077 gint weight_index, slant_index, set_width_index, spacing_index;
1079 gchar *weight, *slant, *set_width, *spacing;
1080 gchar *charset = NULL;
1082 gchar buffer[XLFD_MAX_FIELD_LEN * 6 + 2];
1083 GdkColor *inactive_fg, *inactive_bg;
1084 gboolean show_charset;
1086 #ifdef FONTSEL_DEBUG
1087 g_message("In show_available_styles\n");
1089 font = &fontsel_info->font_info[fontsel->font_index];
1090 styles = &fontsel_info->font_styles[font->style_index];
1092 gtk_clist_freeze (GTK_CLIST(fontsel->font_style_clist));
1093 gtk_clist_clear (GTK_CLIST(fontsel->font_style_clist));
1095 /* First we mark all visible styles as not having been displayed yet,
1096 and check if every style has the same charset. If not then we will
1097 display the charset in the list before the styles. */
1098 show_charset = FALSE;
1100 for (style = 0; style < font->nstyles; style++)
1102 if (gtk_font_selection_style_visible(fontsel, font, style))
1104 styles[style].flags &= ~GTK_FONT_DISPLAYED;
1106 if (charset_index == -1)
1107 charset_index = styles[style].properties[CHARSET];
1108 else if (charset_index != styles[style].properties[CHARSET])
1109 show_charset = TRUE;
1112 styles[style].flags |= GTK_FONT_DISPLAYED;
1115 /* Step through the undisplayed styles, finding the next charset which
1116 hasn't been displayed yet. Then display the charset on one line, if
1117 necessary, and the visible styles indented beneath it. */
1118 inactive_fg = &fontsel->font_style_clist->style->fg[GTK_STATE_INSENSITIVE];
1119 inactive_bg = &fontsel->font_style_clist->style->bg[GTK_STATE_INSENSITIVE];
1121 for (style = 0; style < font->nstyles; style++)
1123 if (styles[style].flags & GTK_FONT_DISPLAYED)
1128 charset_index = styles[style].properties[CHARSET];
1129 charset = fontsel_info->properties[CHARSET] [charset_index];
1130 row = gtk_clist_append(GTK_CLIST(fontsel->font_style_clist),
1132 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_style_clist), row,
1134 gtk_clist_set_foreground(GTK_CLIST(fontsel->font_style_clist),
1136 gtk_clist_set_background(GTK_CLIST(fontsel->font_style_clist),
1140 for (tmpstyle = style; tmpstyle < font->nstyles; tmpstyle++)
1142 if (styles[tmpstyle].flags & GTK_FONT_DISPLAYED
1143 || charset_index != styles[tmpstyle].properties[CHARSET])
1146 styles[tmpstyle].flags |= GTK_FONT_DISPLAYED;
1148 weight_index = styles[tmpstyle].properties[WEIGHT];
1149 slant_index = styles[tmpstyle].properties[SLANT];
1150 set_width_index = styles[tmpstyle].properties[SET_WIDTH];
1151 spacing_index = styles[tmpstyle].properties[SPACING];
1152 weight = fontsel_info->properties[WEIGHT] [weight_index];
1153 slant = fontsel_info->properties[SLANT] [slant_index];
1154 set_width = fontsel_info->properties[SET_WIDTH][set_width_index];
1155 spacing = fontsel_info->properties[SPACING] [spacing_index];
1157 /* Convert '(nil)' weights to 'regular', since it looks nicer. */
1158 if (!g_strcasecmp(weight, "(nil)")) weight = "regular";
1160 /* We don't show default values or (nil) in the other properties. */
1161 if (!g_strcasecmp(slant, "r")) slant = NULL;
1162 else if (!g_strcasecmp(slant, "(nil)")) slant = NULL;
1163 else if (!g_strcasecmp(slant, "i")) slant = "italic";
1164 else if (!g_strcasecmp(slant, "o")) slant = "oblique";
1165 else if (!g_strcasecmp(slant, "ri")) slant = "reverse italic";
1166 else if (!g_strcasecmp(slant, "ro")) slant = "reverse oblique";
1167 else if (!g_strcasecmp(slant, "ot")) slant = "other";
1169 if (!g_strcasecmp(set_width, "normal")) set_width = NULL;
1170 else if (!g_strcasecmp(set_width, "(nil)")) set_width = NULL;
1172 if (!g_strcasecmp(spacing, "p")) spacing = NULL;
1173 else if (!g_strcasecmp(spacing, "(nil)")) spacing = NULL;
1174 else if (!g_strcasecmp(spacing, "m")) spacing = "[M]";
1175 else if (!g_strcasecmp(spacing, "c")) spacing = "[C]";
1177 /* Add the strings together, making sure there is 1 space between
1179 strcpy(buffer, weight);
1182 strcat(buffer, " ");
1183 strcat(buffer, slant);
1187 strcat(buffer, " ");
1188 strcat(buffer, set_width);
1192 strcat(buffer, " ");
1193 strcat(buffer, spacing);
1197 row = gtk_clist_append(GTK_CLIST(fontsel->font_style_clist),
1200 gtk_clist_set_shift(GTK_CLIST(fontsel->font_style_clist), row, 0,
1202 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_style_clist), row,
1203 GINT_TO_POINTER (tmpstyle));
1207 gtk_clist_thaw (GTK_CLIST(fontsel->font_style_clist));
1211 /* This selects a style when the user selects a font. It just uses the first
1212 available style at present. I was thinking of trying to maintain the
1213 selected style, e.g. bold italic, when the user selects different fonts.
1214 However, the interface is so easy to use now I'm not sure it's worth it.
1215 Note: This will load a font. */
1217 gtk_font_selection_select_best_style(GtkFontSelection *fontsel,
1222 gint row, prop, style = -1, style_to_find;
1223 gboolean found = FALSE;
1225 #ifdef FONTSEL_DEBUG
1226 g_message("In select_best_style\n");
1228 font = &fontsel_info->font_info[fontsel->font_index];
1229 styles = &fontsel_info->font_styles[font->style_index];
1231 /* If use_first is set, we just find the first style in the list, not
1232 including charset items. */
1233 style_to_find = use_first ? -1 : gtk_font_selection_get_best_match (fontsel);
1235 for (row = 0; row < GTK_CLIST(fontsel->font_style_clist)->rows; row++)
1237 style = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_style_clist), row));
1238 if (style != -1 && (style_to_find == -1 || style_to_find == style))
1244 g_return_if_fail (found);
1246 fontsel->style = style;
1248 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1249 fontsel->property_values[prop] = styles[fontsel->style].properties[prop];
1251 gtk_clist_select_row(GTK_CLIST(fontsel->font_style_clist), row, 0);
1252 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_style_clist), row)
1253 != GTK_VISIBILITY_FULL)
1254 gtk_clist_moveto(GTK_CLIST(fontsel->font_style_clist), row, -1, 0.5, 0);
1255 gtk_font_selection_show_available_sizes (fontsel);
1256 gtk_font_selection_select_best_size (fontsel);
1260 /* This is called when a style is selected in the list. */
1262 gtk_font_selection_select_style (GtkWidget *w,
1265 GdkEventButton *bevent,
1268 GtkFontSelection *fontsel;
1269 FontInfo *font_info;
1275 #ifdef FONTSEL_DEBUG
1276 g_message("In select_style\n");
1278 fontsel = GTK_FONT_SELECTION(data);
1279 font_info = fontsel_info->font_info;
1280 font = &font_info[fontsel->font_index];
1281 styles = &fontsel_info->font_styles[font->style_index];
1283 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1284 gtk_widget_grab_focus (w);
1286 /* The style index is stored in the row data, so we just need to copy
1287 the style values into the fontsel and reload the font. */
1288 style = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(fontsel->font_style_clist), row));
1290 /* Don't allow selection of charset rows. */
1293 gtk_clist_unselect_row(GTK_CLIST(fontsel->font_style_clist), row, 0);
1297 gtk_clist_get_text(GTK_CLIST(fontsel->font_style_clist), row, 0, &text);
1298 gtk_entry_set_text(GTK_ENTRY(fontsel->font_style_entry), text);
1300 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1301 fontsel->property_values[prop] = styles[style].properties[prop];
1303 if (fontsel->style == style)
1306 fontsel->style = style;
1307 gtk_font_selection_show_available_sizes (fontsel);
1308 gtk_font_selection_select_best_size (fontsel);
1312 /* This shows all the available sizes in the size clist, according to the
1313 current metric and the current font & style. */
1315 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel)
1318 FontStyle *styles, *style;
1319 guint16 *standard_sizes, *bitmapped_sizes, bitmap_size;
1320 gint nstandard_sizes, nbitmapped_sizes;
1321 gchar buffer[16], *size;
1322 gfloat bitmap_size_float;
1326 #ifdef FONTSEL_DEBUG
1327 g_message("In show_available_sizes\n");
1329 font = &fontsel_info->font_info[fontsel->font_index];
1330 styles = &fontsel_info->font_styles[font->style_index];
1331 style = &styles[fontsel->style];
1333 standard_sizes = font_sizes;
1334 nstandard_sizes = sizeof(font_sizes) / sizeof(font_sizes[0]);
1335 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1337 bitmapped_sizes = &fontsel_info->point_sizes[style->point_sizes_index];
1338 nbitmapped_sizes = style->npoint_sizes;
1342 bitmapped_sizes = &fontsel_info->pixel_sizes[style->pixel_sizes_index];
1343 nbitmapped_sizes = style->npixel_sizes;
1346 /* Only show the standard sizes if a scalable font is available. */
1347 type_filter = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
1348 & fontsel->filters[GTK_FONT_FILTER_USER].font_type;
1350 if (!((style->flags & GTK_FONT_SCALABLE_BITMAP
1351 && type_filter & GTK_FONT_SCALABLE_BITMAP)
1352 || (style->flags & GTK_FONT_SCALABLE
1353 && type_filter & GTK_FONT_SCALABLE)))
1354 nstandard_sizes = 0;
1356 gtk_clist_freeze (GTK_CLIST(fontsel->size_clist));
1357 gtk_clist_clear (GTK_CLIST(fontsel->size_clist));
1359 /* Interleave the standard sizes with the bitmapped sizes so we get a list
1360 of ascending sizes. If the metric is points, we have to convert the
1361 decipoints to points. */
1362 while (nstandard_sizes || nbitmapped_sizes)
1365 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1367 if (*bitmapped_sizes % 10 != 0)
1369 bitmap_size = *bitmapped_sizes / 10;
1370 bitmap_size_float = *bitmapped_sizes / 10;
1374 bitmap_size = *bitmapped_sizes;
1375 bitmap_size_float = *bitmapped_sizes;
1378 if (can_match && nstandard_sizes && nbitmapped_sizes
1379 && *standard_sizes == bitmap_size)
1381 sprintf(buffer, "%i *", *standard_sizes);
1387 else if (nstandard_sizes
1388 && (!nbitmapped_sizes
1389 || (gfloat)*standard_sizes < bitmap_size_float))
1391 sprintf(buffer, "%i", *standard_sizes);
1397 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1399 if (*bitmapped_sizes % 10 == 0)
1400 sprintf(buffer, "%i *", *bitmapped_sizes / 10);
1402 sprintf(buffer, "%i.%i *", *bitmapped_sizes / 10,
1403 *bitmapped_sizes % 10);
1407 sprintf(buffer, "%i *", *bitmapped_sizes);
1413 gtk_clist_append(GTK_CLIST(fontsel->size_clist), &size);
1415 gtk_clist_thaw (GTK_CLIST(fontsel->size_clist));
1419 /* If the user hits return in the font size entry, we change to the new font
1422 gtk_font_selection_size_key_press (GtkWidget *w,
1426 GtkFontSelection *fontsel;
1428 gfloat new_size_float;
1431 #ifdef FONTSEL_DEBUG
1432 g_message("In size_key_press\n");
1434 fontsel = GTK_FONT_SELECTION(data);
1436 if (event->keyval == GDK_Return)
1438 text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1439 if (fontsel->metric == GTK_FONT_METRIC_PIXELS)
1441 new_size = atoi (text);
1447 new_size_float = atof (text) * 10;
1448 new_size = (gint) new_size_float;
1453 /* Remember that this size was set explicitly. */
1454 fontsel->selected_size = new_size;
1456 /* Check if the font size has changed, and return if it hasn't. */
1457 if (fontsel->size == new_size)
1460 fontsel->size = new_size;
1461 gtk_font_selection_select_best_size (fontsel);
1469 /* This tries to select the closest size to the current size, though it
1470 may have to change the size if only unscaled bitmaps are available.
1471 Note: this will load a font. */
1473 gtk_font_selection_select_best_size(GtkFontSelection *fontsel)
1476 FontStyle *styles, *style;
1478 gint row, best_row = 0, size, size_fraction, best_size = 0, nmatched;
1479 gboolean found = FALSE;
1484 #ifdef FONTSEL_DEBUG
1485 g_message("In select_best_size\n");
1487 font = &fontsel_info->font_info[fontsel->font_index];
1488 styles = &fontsel_info->font_styles[font->style_index];
1489 style = &styles[fontsel->style];
1491 /* Find the closest size available in the size clist. If the exact size is
1492 in the list set found to TRUE. */
1493 for (row = 0; row < GTK_CLIST(fontsel->size_clist)->rows; row++)
1495 gtk_clist_get_text(GTK_CLIST(fontsel->size_clist), row, 0, &text);
1496 nmatched = sscanf(text, "%i.%i", &size, &size_fraction);
1497 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1501 size += size_fraction;
1504 if (size == fontsel->selected_size)
1511 else if (best_size == 0
1512 || abs(size - fontsel->selected_size)
1513 < (abs(best_size - fontsel->selected_size)))
1520 /* If we aren't scaling bitmapped fonts and this is a bitmapped font, we
1521 need to use the closest size found. */
1522 type_filter = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
1523 & fontsel->filters[GTK_FONT_FILTER_USER].font_type;
1525 if (!((style->flags & GTK_FONT_SCALABLE_BITMAP
1526 && type_filter & GTK_FONT_SCALABLE_BITMAP)
1527 || (style->flags & GTK_FONT_SCALABLE
1528 && type_filter & GTK_FONT_SCALABLE)))
1533 fontsel->size = best_size;
1534 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), best_row, -1, 0.5, 0);
1535 gtk_clist_select_row(GTK_CLIST(fontsel->size_clist), best_row, 0);
1539 fontsel->size = fontsel->selected_size;
1540 selection = GTK_CLIST(fontsel->size_clist)->selection;
1542 gtk_clist_unselect_row(GTK_CLIST(fontsel->size_clist),
1543 GPOINTER_TO_INT (selection->data), 0);
1544 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), best_row, -1, 0.5, 0);
1546 /* Show the size in the size entry. */
1547 if (fontsel->metric == GTK_FONT_METRIC_PIXELS)
1548 sprintf(buffer, "%i", fontsel->size);
1551 if (fontsel->size % 10 == 0)
1552 sprintf(buffer, "%i", fontsel->size / 10);
1554 sprintf(buffer, "%i.%i", fontsel->size / 10, fontsel->size % 10);
1556 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
1558 gtk_font_selection_load_font (fontsel);
1562 /* This is called when a size is selected in the list. */
1564 gtk_font_selection_select_size (GtkWidget *w,
1567 GdkEventButton *bevent,
1570 GtkFontSelection *fontsel;
1576 #ifdef FONTSEL_DEBUG
1577 g_message("In select_size\n");
1579 fontsel = GTK_FONT_SELECTION(data);
1581 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1582 gtk_widget_grab_focus (w);
1584 /* Copy the size from the clist to the size entry, but without the bitmapped
1586 gtk_clist_get_text(GTK_CLIST(fontsel->size_clist), row, 0, &text);
1588 while (i < 15 && (text[i] == '.' || (text[i] >= '0' && text[i] <= '9')))
1590 buffer[i] = text[i];
1594 gtk_entry_set_text(GTK_ENTRY(fontsel->size_entry), buffer);
1596 /* Check if the font size has changed, and return if it hasn't. */
1597 new_size = atoi(text);
1598 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1601 if (fontsel->size == new_size)
1604 /* If the size was selected by the user we set the selected_size. */
1605 fontsel->selected_size = new_size;
1607 fontsel->size = new_size;
1608 gtk_font_selection_load_font (fontsel);
1612 /* This is called when the pixels or points radio buttons are pressed. */
1614 gtk_font_selection_metric_callback (GtkWidget *w,
1617 GtkFontSelection *fontsel = GTK_FONT_SELECTION(data);
1619 #ifdef FONTSEL_DEBUG
1620 g_message("In metric_callback\n");
1622 if (GTK_TOGGLE_BUTTON(fontsel->pixels_button)->active)
1624 if (fontsel->metric == GTK_FONT_METRIC_PIXELS)
1626 fontsel->metric = GTK_FONT_METRIC_PIXELS;
1627 fontsel->size = (fontsel->size + 5) / 10;
1628 fontsel->selected_size = (fontsel->selected_size + 5) / 10;
1632 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1634 fontsel->metric = GTK_FONT_METRIC_POINTS;
1635 fontsel->size *= 10;
1636 fontsel->selected_size *= 10;
1638 if (fontsel->font_index != -1)
1640 gtk_font_selection_show_available_sizes (fontsel);
1641 gtk_font_selection_select_best_size (fontsel);
1646 /* This searches the given property table and returns the index of the given
1647 string, or 0, which is the wildcard '*' index, if it's not found. */
1649 gtk_font_selection_field_to_index (gchar **table,
1655 for (i = 0; i < ntable; i++)
1656 if (strcmp (field, table[i]) == 0)
1664 /* This attempts to load the current font, and returns TRUE if it succeeds. */
1666 gtk_font_selection_load_font (GtkFontSelection *fontsel)
1669 gchar *fontname, *label_text;
1672 gdk_font_unref (fontsel->font);
1673 fontsel->font = NULL;
1675 /* If no family has been selected yet, just return FALSE. */
1676 if (fontsel->font_index == -1)
1679 fontname = gtk_font_selection_get_font_name (fontsel);
1682 #ifdef FONTSEL_DEBUG
1683 g_message("Loading: %s\n", fontname);
1685 font = gdk_font_load (fontname);
1690 fontsel->font = font;
1691 /* Make sure the message label is empty, but don't change it unless
1692 it's necessary as it results in a resize of the whole window! */
1693 gtk_label_get(GTK_LABEL(fontsel->message_label), &label_text);
1694 if (strcmp(label_text, ""))
1695 gtk_label_set(GTK_LABEL(fontsel->message_label), "");
1696 gtk_font_selection_update_preview (fontsel);
1701 gtk_label_set(GTK_LABEL(fontsel->message_label),
1702 "The selected font is not available.");
1707 gtk_label_set(GTK_LABEL(fontsel->message_label),
1708 "The selected font is not a valid font.");
1715 /* This sets the font in the preview entry to the selected font, and tries to
1716 make sure that the preview entry is a reasonable size, i.e. so that the
1717 text can be seen with a bit of space to spare. But it tries to avoid
1718 resizing the entry every time the font changes.
1719 This also used to shrink the preview if the font size was decreased, but
1720 that made it awkward if the user wanted to resize the window themself. */
1722 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1724 GtkWidget *preview_entry;
1726 gint text_height, new_height;
1730 #ifdef FONTSEL_DEBUG
1731 g_message("In update_preview\n");
1733 style = gtk_style_new ();
1734 gdk_font_unref (style->font);
1735 style->font = fontsel->font;
1736 gdk_font_ref (style->font);
1738 preview_entry = fontsel->preview_entry;
1739 gtk_widget_set_style (preview_entry, style);
1740 gtk_style_unref(style);
1742 text_height = preview_entry->style->font->ascent
1743 + preview_entry->style->font->descent;
1744 /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1745 new_height = text_height + 20;
1746 if (new_height < INITIAL_PREVIEW_HEIGHT)
1747 new_height = INITIAL_PREVIEW_HEIGHT;
1748 if (new_height > MAX_PREVIEW_HEIGHT)
1749 new_height = MAX_PREVIEW_HEIGHT;
1751 if ((preview_entry->requisition.height < text_height + 10)
1752 || (preview_entry->requisition.height > text_height + 40))
1753 gtk_widget_set_usize(preview_entry, -1, new_height);
1755 /* This sets the preview text, if it hasn't been set already. */
1756 text = gtk_entry_get_text(GTK_ENTRY(fontsel->preview_entry));
1757 if (strlen(text) == 0)
1758 gtk_entry_set_text(GTK_ENTRY(fontsel->preview_entry), PREVIEW_TEXT);
1759 gtk_entry_set_position(GTK_ENTRY(fontsel->preview_entry), 0);
1761 /* If this is a 2-byte font display a message to say it may not be
1762 displayed properly. */
1763 xfs = GDK_FONT_XFONT(fontsel->font);
1764 if (xfs->min_byte1 != 0 || xfs->max_byte1 != 0)
1765 gtk_label_set(GTK_LABEL(fontsel->message_label),
1766 "This is a 2-byte font and may not be displayed correctly.");
1771 gtk_font_selection_switch_page (GtkWidget *w,
1772 GtkNotebookPage *page,
1776 GtkFontSelection *fontsel = GTK_FONT_SELECTION(data);
1778 /* This function strangely gets called when the window is destroyed,
1779 so we check here to see if the notebook is visible. */
1780 if (!GTK_WIDGET_VISIBLE(w))
1784 gtk_font_selection_update_filter(fontsel);
1785 else if (page_num == 1)
1786 gtk_font_selection_show_font_info(fontsel);
1791 gtk_font_selection_show_font_info (GtkFontSelection *fontsel)
1793 Atom font_atom, atom;
1797 gchar field_buffer[XLFD_MAX_FIELD_LEN];
1800 gboolean shown_actual_fields = FALSE;
1802 fontname = gtk_font_selection_get_font_name(fontsel);
1803 gtk_entry_set_text(GTK_ENTRY(fontsel->requested_font_name),
1804 fontname ? fontname : "");
1806 gtk_clist_freeze (GTK_CLIST(fontsel->info_clist));
1807 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1810 field = gtk_font_selection_get_xlfd_field (fontname, i, field_buffer);
1815 if (i == XLFD_SLANT)
1816 field = gtk_font_selection_expand_slant_code(field);
1817 else if (i == XLFD_SPACING)
1818 field = gtk_font_selection_expand_spacing_code(field);
1820 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 1,
1821 field ? field : "");
1826 font_atom = XInternAtom(GDK_DISPLAY(), "FONT", True);
1827 if (font_atom != None)
1829 status = XGetFontProperty(GDK_FONT_XFONT(fontsel->font), font_atom,
1833 name = XGetAtomName(GDK_DISPLAY(), atom);
1834 gtk_entry_set_text(GTK_ENTRY(fontsel->actual_font_name), name);
1836 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1838 field = gtk_font_selection_get_xlfd_field (name, i,
1840 if (i == XLFD_SLANT)
1841 field = gtk_font_selection_expand_slant_code(field);
1842 else if (i == XLFD_SPACING)
1843 field = gtk_font_selection_expand_spacing_code(field);
1844 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 2,
1845 field ? field : "");
1847 shown_actual_fields = TRUE;
1852 if (!shown_actual_fields)
1854 gtk_entry_set_text(GTK_ENTRY(fontsel->actual_font_name), "");
1855 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1857 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 2,
1858 fontname ? "(unknown)" : "");
1861 gtk_clist_thaw (GTK_CLIST(fontsel->info_clist));
1867 gtk_font_selection_expand_slant_code(gchar *slant)
1869 if (!g_strcasecmp(slant, "r")) return("roman");
1870 else if (!g_strcasecmp(slant, "i")) return("italic");
1871 else if (!g_strcasecmp(slant, "o")) return("oblique");
1872 else if (!g_strcasecmp(slant, "ri")) return("reverse italic");
1873 else if (!g_strcasecmp(slant, "ro")) return("reverse oblique");
1874 else if (!g_strcasecmp(slant, "ot")) return("other");
1879 gtk_font_selection_expand_spacing_code(gchar *spacing)
1881 if (!g_strcasecmp(spacing, "p")) return("proportional");
1882 else if (!g_strcasecmp(spacing, "m")) return("monospaced");
1883 else if (!g_strcasecmp(spacing, "c")) return("char cell");
1888 /*****************************************************************************
1889 * These functions all deal with the Filter page and filtering the fonts.
1890 *****************************************************************************/
1892 /* This is called when an item is selected in one of the filter clists.
1893 We make sure that the first row of the clist, i.e. the wildcard '*', is
1894 selected if and only if none of the other items are selected.
1895 Also doesn't allow selections of values filtered out by base filter.
1896 We may need to be careful about triggering other signals. */
1898 gtk_font_selection_select_filter (GtkWidget *w,
1901 GdkEventButton *bevent,
1902 GtkFontSelection *fontsel)
1904 gint i, prop, index;
1908 for (i = 1; i < GTK_CLIST(w)->rows; i++)
1909 gtk_clist_unselect_row(GTK_CLIST(w), i, 0);
1913 /* Find out which property this is. */
1914 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
1915 if (fontsel->filter_clists[prop] == w)
1917 index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(w), row));
1918 if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_BASE,
1919 prop, index) == NOT_FILTERED)
1920 gtk_clist_unselect_row(GTK_CLIST(w), row, 0);
1922 gtk_clist_unselect_row(GTK_CLIST(w), 0, 0);
1927 /* Here a filter item is being deselected. If there are now no items selected
1928 we select the first '*' item, unless that it is the item being deselected,
1929 in which case we select all of the other items. This makes it easy to
1930 select all items in the list except one or two. */
1932 gtk_font_selection_unselect_filter (GtkWidget *w,
1935 GdkEventButton *bevent,
1936 GtkFontSelection *fontsel)
1938 gint i, prop, index;
1940 if (!GTK_CLIST(w)->selection)
1944 /* Find out which property this is. */
1945 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
1946 if (fontsel->filter_clists[prop] == w)
1949 for (i = 1; i < GTK_CLIST(w)->rows; i++)
1951 index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(w),
1953 if (gtk_font_selection_filter_state (fontsel,
1954 GTK_FONT_FILTER_BASE,
1957 gtk_clist_select_row(GTK_CLIST(w), i, 0);
1962 gtk_clist_select_row(GTK_CLIST(w), 0, 0);
1968 /* This is called when the main notebook page is selected. It checks if the
1969 filter has changed, an if so it creates the filter settings, and filters the
1970 fonts shown. If an empty filter (all '*'s) is applied, then filtering is
1973 gtk_font_selection_update_filter (GtkFontSelection *fontsel)
1977 gboolean default_filter = TRUE, filter_changed = FALSE;
1978 gint prop, nselected, i, row, index;
1979 GtkFontFilter *filter = &fontsel->filters[GTK_FONT_FILTER_USER];
1980 gint base_font_type, user_font_type, new_font_type;
1982 #ifdef FONTSEL_DEBUG
1983 g_message("In update_filter\n");
1986 /* Check if the user filter has changed, and also if it is the default
1987 filter, i.e. bitmap & scalable fonts and all '*'s selected.
1988 We only look at the bits which are not already filtered out by the base
1989 filter, since that overrides the user filter. */
1990 base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
1992 user_font_type = fontsel->filters[GTK_FONT_FILTER_USER].font_type
1994 new_font_type = GTK_TOGGLE_BUTTON(fontsel->type_bitmaps_button)->active
1995 ? GTK_FONT_BITMAP : 0;
1996 new_font_type |= (GTK_TOGGLE_BUTTON(fontsel->type_scalable_button)->active
1997 ? GTK_FONT_SCALABLE : 0);
1998 new_font_type |= (GTK_TOGGLE_BUTTON(fontsel->type_scaled_bitmaps_button)->active ? GTK_FONT_SCALABLE_BITMAP : 0);
1999 new_font_type &= base_font_type;
2000 new_font_type |= (~base_font_type & user_font_type);
2001 if (new_font_type != (GTK_FONT_BITMAP | GTK_FONT_SCALABLE))
2002 default_filter = FALSE;
2004 if (new_font_type != user_font_type)
2005 filter_changed = TRUE;
2006 fontsel->filters[GTK_FONT_FILTER_USER].font_type = new_font_type;
2008 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2010 clist = fontsel->filter_clists[prop];
2011 selection = GTK_CLIST(clist)->selection;
2012 nselected = g_list_length(selection);
2013 if (nselected != 1 || GPOINTER_TO_INT (selection->data) != 0)
2015 default_filter = FALSE;
2017 if (filter->property_nfilters[prop] != nselected)
2018 filter_changed = TRUE;
2021 for (i = 0; i < nselected; i++)
2023 row = GPOINTER_TO_INT (selection->data);
2024 index = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (clist), row));
2025 if (filter->property_filters[prop][i] != index)
2026 filter_changed = TRUE;
2027 selection = selection->next;
2033 if (filter->property_nfilters[prop] != 0)
2034 filter_changed = TRUE;
2038 /* If the filter hasn't changed we just return. */
2039 if (!filter_changed)
2042 #ifdef FONTSEL_DEBUG
2043 g_message(" update_fonts: filter has changed\n");
2046 /* Free the old filter data and create the new arrays. */
2047 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2049 g_free(filter->property_filters[prop]);
2051 clist = fontsel->filter_clists[prop];
2052 selection = GTK_CLIST(clist)->selection;
2053 nselected = g_list_length(selection);
2054 if (nselected == 1 && GPOINTER_TO_INT (selection->data) == 0)
2056 filter->property_filters[prop] = NULL;
2057 filter->property_nfilters[prop] = 0;
2061 filter->property_filters[prop] = g_new(guint16, nselected);
2062 filter->property_nfilters[prop] = nselected;
2063 for (i = 0; i < nselected; i++)
2065 row = GPOINTER_TO_INT (selection->data);
2066 index = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (clist), row));
2067 filter->property_filters[prop][i] = index;
2068 selection = selection->next;
2073 /* Set the 'Reset Filter' button sensitive if a filter is in effect, and
2074 also set the label above the font list to show this as well. */
2077 gtk_widget_set_sensitive(fontsel->filter_button, FALSE);
2078 gtk_label_set(GTK_LABEL(fontsel->font_label), "Font:");
2082 gtk_widget_set_sensitive(fontsel->filter_button, TRUE);
2083 gtk_label_set(GTK_LABEL(fontsel->font_label), "Font: (Filter Applied)");
2085 gtk_font_selection_show_available_fonts(fontsel);
2089 /* This shows all the available fonts in the font clist. */
2091 gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
2093 FontInfo *font_info, *font;
2094 GtkFontFilter *filter;
2095 gint nfonts, i, j, k, row, style, font_row = -1;
2096 gchar font_buffer[XLFD_MAX_FIELD_LEN * 2 + 4];
2098 gboolean matched, matched_style;
2100 #ifdef FONTSEL_DEBUG
2101 g_message("In show_available_fonts\n");
2103 font_info = fontsel_info->font_info;
2104 nfonts = fontsel_info->nfonts;
2106 /* Filter the list of fonts. */
2107 gtk_clist_freeze (GTK_CLIST(fontsel->font_clist));
2108 gtk_clist_clear (GTK_CLIST(fontsel->font_clist));
2109 for (i = 0; i < nfonts; i++)
2111 font = &font_info[i];
2113 /* Check if the foundry passes through all filters. */
2115 for (k = 0; k < GTK_NUM_FONT_FILTERS; k++)
2117 filter = &fontsel->filters[k];
2119 if (filter->property_nfilters[FOUNDRY] != 0)
2122 for (j = 0; j < filter->property_nfilters[FOUNDRY]; j++)
2124 if (font->foundry == filter->property_filters[FOUNDRY][j])
2137 /* Now check if the other properties are matched in at least one style.*/
2138 matched_style = FALSE;
2139 for (style = 0; style < font->nstyles; style++)
2141 if (gtk_font_selection_style_visible(fontsel, font, style))
2143 matched_style = TRUE;
2150 /* Insert the font in the clist. */
2151 if ((i > 0 && font->family == font_info[i-1].family)
2152 || (i < nfonts - 1 && font->family == font_info[i+1].family))
2154 sprintf(font_buffer, "%s (%s)", font->family,
2155 fontsel_info->properties[FOUNDRY][font->foundry]);
2156 font_item = font_buffer;
2157 row = gtk_clist_append(GTK_CLIST(fontsel->font_clist), &font_item);
2161 row = gtk_clist_append(GTK_CLIST(fontsel->font_clist),
2164 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_clist), row,
2165 GINT_TO_POINTER (i));
2166 if (fontsel->font_index == i)
2169 gtk_clist_thaw (GTK_CLIST(fontsel->font_clist));
2171 /* If the currently-selected font isn't in the new list, reset the
2175 fontsel->font_index = -1;
2177 gdk_font_unref(fontsel->font);
2178 fontsel->font = NULL;
2179 gtk_entry_set_text(GTK_ENTRY(fontsel->font_entry), "");
2180 gtk_clist_clear (GTK_CLIST(fontsel->font_style_clist));
2181 gtk_entry_set_text(GTK_ENTRY(fontsel->font_style_entry), "");
2185 gtk_clist_select_row(GTK_CLIST(fontsel->font_clist), font_row, 0);
2186 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_clist), font_row)
2187 != GTK_VISIBILITY_FULL)
2188 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), font_row, -1, 0.5, 0);
2190 gtk_font_selection_show_available_styles (fontsel);
2191 gtk_font_selection_select_best_style (fontsel, FALSE);
2195 /* Returns TRUE if the style is not currently filtered out. */
2197 gtk_font_selection_style_visible(GtkFontSelection *fontsel,
2201 FontStyle *styles, *style;
2202 GtkFontFilter *filter;
2208 styles = &fontsel_info->font_styles[font->style_index];
2209 style = &styles[style_index];
2211 /* Check if font_type of style is filtered. */
2212 type_filter = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
2213 & fontsel->filters[GTK_FONT_FILTER_USER].font_type;
2214 if (!(style->flags & type_filter))
2217 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2219 value = style->properties[prop];
2221 /* Check each filter. */
2222 for (i = 0; i < GTK_NUM_FONT_FILTERS; i++)
2224 filter = &fontsel->filters[i];
2226 if (filter->property_nfilters[prop] != 0)
2229 for (j = 0; j < filter->property_nfilters[prop]; j++)
2231 if (value == filter->property_filters[prop][j])
2246 /* This resets the font type to bitmap or scalable, and sets all the filter
2247 clists to the wildcard '*' options. */
2249 gtk_font_selection_reset_filter (GtkWidget *w,
2250 GtkFontSelection *fontsel)
2252 gint prop, base_font_type;
2254 fontsel->filters[GTK_FONT_FILTER_USER].font_type = GTK_FONT_BITMAP
2255 | GTK_FONT_SCALABLE;
2257 base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type;
2258 if (base_font_type & GTK_FONT_BITMAP)
2259 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), TRUE);
2260 if (base_font_type & GTK_FONT_SCALABLE)
2261 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), TRUE);
2262 if (base_font_type & GTK_FONT_SCALABLE_BITMAP)
2263 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), FALSE);
2265 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2266 gtk_clist_select_row(GTK_CLIST(fontsel->filter_clists[prop]), 0, 0);
2270 /* This clears the filter, showing all fonts and styles again. */
2272 gtk_font_selection_on_clear_filter (GtkWidget *w,
2273 GtkFontSelection *fontsel)
2275 gtk_font_selection_clear_filter(fontsel);
2279 /* This resets the user filter, showing all fonts and styles which pass the
2280 base filter again. Note that the font type is set to bitmaps and scalable
2281 fonts - scaled bitmaps are not shown. */
2283 gtk_font_selection_clear_filter (GtkFontSelection *fontsel)
2285 GtkFontFilter *filter;
2288 #ifdef FONTSEL_DEBUG
2289 g_message("In clear_filter\n");
2291 /* Clear the filter data. */
2292 filter = &fontsel->filters[GTK_FONT_FILTER_USER];
2293 filter->font_type = GTK_FONT_BITMAP | GTK_FONT_SCALABLE;
2294 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2296 g_free(filter->property_filters[prop]);
2297 filter->property_filters[prop] = NULL;
2298 filter->property_nfilters[prop] = 0;
2301 /* Select all the '*'s on the filter page. */
2302 gtk_font_selection_reset_filter(NULL, fontsel);
2304 /* Update the main notebook page. */
2305 gtk_widget_set_sensitive(fontsel->filter_button, FALSE);
2306 gtk_label_set(GTK_LABEL(fontsel->font_label), "Font:");
2308 gtk_font_selection_show_available_fonts(fontsel);
2313 gtk_font_selection_set_filter (GtkFontSelection *fontsel,
2314 GtkFontFilterType filter_type,
2315 GtkFontType font_type,
2323 GtkFontFilter *filter;
2324 gchar **filter_strings [GTK_NUM_FONT_PROPERTIES];
2325 gchar *filter_string;
2326 gchar *property, *property_alt;
2327 gint prop, nfilters, i, j, num_found;
2328 gint base_font_type, user_font_type;
2329 gboolean filter_set;
2331 /* Put them into an array so we can use a simple loop. */
2332 filter_strings[FOUNDRY] = foundries;
2333 filter_strings[WEIGHT] = weights;
2334 filter_strings[SLANT] = slants;
2335 filter_strings[SET_WIDTH] = setwidths;
2336 filter_strings[SPACING] = spacings;
2337 filter_strings[CHARSET] = charsets;
2339 filter = &fontsel->filters[filter_type];
2340 filter->font_type = font_type;
2342 /* Free the old filter data, and insert the new. */
2343 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2345 g_free(filter->property_filters[prop]);
2346 filter->property_filters[prop] = NULL;
2347 filter->property_nfilters[prop] = 0;
2349 if (filter_strings[prop])
2351 /* Count how many items in the new array. */
2353 while (filter_strings[prop][nfilters])
2356 filter->property_filters[prop] = g_new(guint16, nfilters);
2357 filter->property_nfilters[prop] = 0;
2359 /* Now convert the strings to property indices. */
2361 for (i = 0; i < nfilters; i++)
2363 filter_string = filter_strings[prop][i];
2364 for (j = 0; j < fontsel_info->nproperties[prop]; j++)
2366 property = fontsel_info->properties[prop][j];
2367 property_alt = NULL;
2369 property_alt = gtk_font_selection_expand_slant_code(property);
2370 else if (prop == SPACING)
2371 property_alt = gtk_font_selection_expand_spacing_code(property);
2372 if (!strcmp (filter_string, property)
2373 || (property_alt && !strcmp (filter_string, property_alt)))
2375 filter->property_filters[prop][num_found] = j;
2381 filter->property_nfilters[prop] = num_found;
2385 /* Now set the clists on the filter page according to the new filter. */
2386 gtk_font_selection_update_filter_lists (fontsel);
2388 if (filter_type == GTK_FONT_FILTER_BASE)
2390 user_font_type = fontsel->filters[GTK_FONT_FILTER_USER].font_type;
2391 if (font_type & GTK_FONT_BITMAP)
2393 gtk_widget_set_sensitive (fontsel->type_bitmaps_button, TRUE);
2394 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), user_font_type & GTK_FONT_BITMAP);
2398 gtk_widget_set_sensitive (fontsel->type_bitmaps_button, FALSE);
2399 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), FALSE);
2402 if (font_type & GTK_FONT_SCALABLE)
2404 gtk_widget_set_sensitive (fontsel->type_scalable_button, TRUE);
2405 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), user_font_type & GTK_FONT_SCALABLE);
2409 gtk_widget_set_sensitive (fontsel->type_scalable_button, FALSE);
2410 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), FALSE);
2413 if (font_type & GTK_FONT_SCALABLE_BITMAP)
2415 gtk_widget_set_sensitive (fontsel->type_scaled_bitmaps_button, TRUE);
2416 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), user_font_type & GTK_FONT_SCALABLE_BITMAP);
2420 gtk_widget_set_sensitive (fontsel->type_scaled_bitmaps_button, FALSE);
2421 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), FALSE);
2426 base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type;
2427 if (base_font_type & GTK_FONT_BITMAP)
2428 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), font_type & GTK_FONT_BITMAP);
2430 if (base_font_type & GTK_FONT_SCALABLE)
2431 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), font_type & GTK_FONT_SCALABLE);
2433 if (base_font_type & GTK_FONT_SCALABLE_BITMAP)
2434 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), font_type & GTK_FONT_SCALABLE_BITMAP);
2436 /* If the user filter is not the default, make the 'Reset Filter' button
2439 if (font_type != (GTK_FONT_BITMAP | GTK_FONT_SCALABLE))
2441 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2443 if (filter->property_nfilters[prop] != 0)
2447 gtk_widget_set_sensitive (fontsel->filter_button, TRUE);
2450 gtk_font_selection_show_available_fonts (fontsel);
2454 /* This sets the colour of each property in the filter clists according to
2455 the base filter. i.e. Filtered properties are shown as insensitive. */
2457 gtk_font_selection_update_filter_lists (GtkFontSelection *fontsel)
2460 GdkColor *inactive_fg, *inactive_bg, *fg, *bg;
2461 gint prop, row, index;
2463 /* We have to make sure the clist is realized to use the colours. */
2464 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2466 clist = fontsel->filter_clists[prop];
2467 gtk_widget_realize (clist);
2468 inactive_fg = &clist->style->fg[GTK_STATE_INSENSITIVE];
2469 inactive_bg = &clist->style->bg[GTK_STATE_INSENSITIVE];
2470 for (row = 1; row < GTK_CLIST(clist)->rows; row++)
2472 index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(clist),
2474 /* Set the colour according to the base filter. */
2475 if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_BASE,
2476 prop, index) == NOT_FILTERED)
2486 gtk_clist_set_foreground(GTK_CLIST(clist), row, fg);
2487 gtk_clist_set_background(GTK_CLIST(clist), row, bg);
2489 /* Set the selection state according to the user filter. */
2490 if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_USER,
2491 prop, index) == FILTERED
2493 gtk_clist_select_row (GTK_CLIST (clist), row, 0);
2495 gtk_clist_unselect_row (GTK_CLIST (clist), row, 0);
2501 /* Returns whether a property value is in the filter or not, or if the
2502 property has no filter set. */
2503 static GtkFontPropertyFilterState
2504 gtk_font_selection_filter_state (GtkFontSelection *fontsel,
2505 GtkFontFilterType filter_type,
2509 GtkFontFilter *filter;
2512 filter = &fontsel->filters[filter_type];
2513 if (filter->property_nfilters[property] == 0)
2516 for (i = 0; i < filter->property_nfilters[property]; i++)
2518 if (filter->property_filters[property][i] == index)
2521 return NOT_FILTERED;
2525 /*****************************************************************************
2526 * These functions all deal with creating the main class arrays containing
2527 * the data about all available fonts.
2528 *****************************************************************************/
2530 gtk_font_selection_get_fonts (void)
2537 gint i, prop, style, size;
2538 gint npixel_sizes = 0, npoint_sizes = 0;
2540 FontStyle *current_style, *prev_style, *tmp_style;
2541 gboolean matched_style, found_size;
2542 gint pixels, points, res_x, res_y;
2543 gchar field_buffer[XLFD_MAX_FIELD_LEN];
2546 guint16 *pixel_sizes, *point_sizes, *tmp_sizes;
2548 fontsel_info = g_new (GtkFontSelInfo, 1);
2550 /* Get a maximum of MAX_FONTS fontnames from the X server.
2551 Use "-*" as the pattern rather than "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" since
2552 the latter may result in fonts being returned which don't actually exist.
2553 xlsfonts also uses "*" so I think it's OK. "-*" gets rid of aliases. */
2554 xfontnames = XListFonts (GDK_DISPLAY(), "-*", MAX_FONTS, &num_fonts);
2555 /* Output a warning if we actually get MAX_FONTS fonts. */
2556 if (num_fonts == MAX_FONTS)
2557 g_warning("MAX_FONTS exceeded. Some fonts may be missing.");
2559 /* The maximum size of all these tables is the number of font names
2560 returned. We realloc them later when we know exactly how many
2561 unique entries there are. */
2562 fontsel_info->font_info = g_new (FontInfo, num_fonts);
2563 fontsel_info->font_styles = g_new (FontStyle, num_fonts);
2564 fontsel_info->pixel_sizes = g_new (guint16, num_fonts);
2565 fontsel_info->point_sizes = g_new (guint16, num_fonts);
2567 fontnames = g_new (GSList*, num_fonts);
2569 /* Create the initial arrays for the property value strings, though they
2570 may be realloc'ed later. Put the wildcard '*' in the first elements. */
2571 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2573 fontsel_info->properties[prop] = g_new(gchar*, PROPERTY_ARRAY_INCREMENT);
2574 fontsel_info->space_allocated[prop] = PROPERTY_ARRAY_INCREMENT;
2575 fontsel_info->nproperties[prop] = 1;
2576 fontsel_info->properties[prop][0] = "*";
2580 /* Insert the font families into the main table, sorted by family and
2581 foundry (fonts with different foundries are placed in seaparate FontInfos.
2582 All fontnames in each family + foundry are placed into the fontnames
2584 fontsel_info->nfonts = 0;
2585 for (i = 0; i < num_fonts; i++)
2587 #ifdef FONTSEL_DEBUG
2588 g_message("%s\n", xfontnames[i]);
2590 if (gtk_font_selection_is_xlfd_font_name (xfontnames[i]))
2591 gtk_font_selection_insert_font (fontnames, &fontsel_info->nfonts, xfontnames[i]);
2594 #ifdef FONTSEL_DEBUG
2595 g_warning("Skipping invalid font: %s", xfontnames[i]);
2601 /* Since many font names will be in the same FontInfo not all of the
2602 allocated FontInfo table will be used, so we will now reallocate it
2603 with the real size. */
2604 fontsel_info->font_info = g_realloc(fontsel_info->font_info,
2605 sizeof(FontInfo) * fontsel_info->nfonts);
2608 /* Now we work out which choices of weight/slant etc. are valid for each
2610 fontsel_info->nstyles = 0;
2611 current_style = fontsel_info->font_styles;
2612 for (i = 0; i < fontsel_info->nfonts; i++)
2614 font = &fontsel_info->font_info[i];
2616 /* Use the next free position in the styles array. */
2617 font->style_index = fontsel_info->nstyles;
2619 /* Now step through each of the fontnames with this family, and create
2620 a style for each fontname. Each style contains the index into the
2621 weights/slants etc. arrays, and a number of pixel/point sizes. */
2623 temp_list = fontnames[i];
2626 fontname = temp_list->data;
2627 temp_list = temp_list->next;
2629 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2631 current_style->properties[prop]
2632 = gtk_font_selection_insert_field (fontname, prop);
2634 current_style->pixel_sizes_index = npixel_sizes;
2635 current_style->npixel_sizes = 0;
2636 current_style->point_sizes_index = npoint_sizes;
2637 current_style->npoint_sizes = 0;
2638 current_style->flags = 0;
2641 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_PIXELS,
2643 pixels = atoi(field);
2645 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_POINTS,
2647 points = atoi(field);
2649 field = gtk_font_selection_get_xlfd_field (fontname,
2652 res_x = atoi(field);
2654 field = gtk_font_selection_get_xlfd_field (fontname,
2657 res_y = atoi(field);
2659 if (pixels == 0 && points == 0)
2661 if (res_x == 0 && res_y == 0)
2662 flags = GTK_FONT_SCALABLE;
2664 flags = GTK_FONT_SCALABLE_BITMAP;
2667 flags = GTK_FONT_BITMAP;
2669 /* Now we check to make sure that the style is unique. If it isn't
2671 prev_style = fontsel_info->font_styles + font->style_index;
2672 matched_style = FALSE;
2673 while (prev_style < current_style)
2675 matched_style = TRUE;
2676 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2678 if (prev_style->properties[prop]
2679 != current_style->properties[prop])
2681 matched_style = FALSE;
2690 /* If we matched an existing style, we need to add the pixels &
2691 point sizes to the style. If not, we insert the pixel & point
2692 sizes into our new style. Note that we don't add sizes for
2696 prev_style->flags |= flags;
2697 if (flags == GTK_FONT_BITMAP)
2699 pixel_sizes = fontsel_info->pixel_sizes
2700 + prev_style->pixel_sizes_index;
2702 for (size = 0; size < prev_style->npixel_sizes; size++)
2704 if (pixels == *pixel_sizes)
2709 else if (pixels < *pixel_sizes)
2713 /* We need to move all the following pixel sizes up, and also
2714 update the indexes of any following styles. */
2717 for (tmp_sizes = fontsel_info->pixel_sizes + npixel_sizes;
2718 tmp_sizes > pixel_sizes; tmp_sizes--)
2719 *tmp_sizes = *(tmp_sizes - 1);
2721 *pixel_sizes = pixels;
2723 prev_style->npixel_sizes++;
2725 tmp_style = prev_style + 1;
2726 while (tmp_style < current_style)
2728 tmp_style->pixel_sizes_index++;
2733 point_sizes = fontsel_info->point_sizes
2734 + prev_style->point_sizes_index;
2736 for (size = 0; size < prev_style->npoint_sizes; size++)
2738 if (points == *point_sizes)
2743 else if (points < *point_sizes)
2747 /* We need to move all the following point sizes up, and also
2748 update the indexes of any following styles. */
2751 for (tmp_sizes = fontsel_info->point_sizes + npoint_sizes;
2752 tmp_sizes > point_sizes; tmp_sizes--)
2753 *tmp_sizes = *(tmp_sizes - 1);
2755 *point_sizes = points;
2757 prev_style->npoint_sizes++;
2759 tmp_style = prev_style + 1;
2760 while (tmp_style < current_style)
2762 tmp_style->point_sizes_index++;
2770 current_style->flags = flags;
2771 if (flags == GTK_FONT_BITMAP)
2773 fontsel_info->pixel_sizes[npixel_sizes++] = pixels;
2774 current_style->npixel_sizes = 1;
2775 fontsel_info->point_sizes[npoint_sizes++] = points;
2776 current_style->npoint_sizes = 1;
2779 fontsel_info->nstyles++;
2783 g_slist_free(fontnames[i]);
2785 /* Set nstyles to the real value, minus duplicated fontnames.
2786 Note that we aren't using all the allocated memory if fontnames are
2788 font->nstyles = style;
2791 /* Since some repeated styles may be skipped we won't have used all the
2792 allocated space, so we will now reallocate it with the real size. */
2793 fontsel_info->font_styles = g_realloc(fontsel_info->font_styles,
2794 sizeof(FontStyle) * fontsel_info->nstyles);
2795 fontsel_info->pixel_sizes = g_realloc(fontsel_info->pixel_sizes,
2796 sizeof(guint16) * npixel_sizes);
2797 fontsel_info->point_sizes = g_realloc(fontsel_info->point_sizes,
2798 sizeof(guint16) * npoint_sizes);
2800 XFreeFontNames (xfontnames);
2803 /* Debugging Output */
2804 /* This outputs all FontInfos. */
2805 #ifdef FONTSEL_DEBUG
2806 g_message("\n\n Font Family Weight Slant Set Width Spacing Charset\n\n");
2807 for (i = 0; i < fontsel_info->nfonts; i++)
2809 FontInfo *font = &fontsel_info->font_info[i];
2810 FontStyle *styles = fontsel_info->font_styles + font->style_index;
2811 for (style = 0; style < font->nstyles; style++)
2813 g_message("%5i %-16.16s ", i, font->family);
2814 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2815 g_message("%-9.9s ",
2816 fontsel_info->properties[prop][styles->properties[prop]]);
2819 if (styles->flags & GTK_FONT_BITMAP)
2820 g_message("Bitmapped font ");
2821 if (styles->flags & GTK_FONT_SCALABLE)
2822 g_message("Scalable font ");
2823 if (styles->flags & GTK_FONT_SCALABLE_BITMAP)
2824 g_message("Scalable-Bitmapped font ");
2827 if (styles->npixel_sizes)
2829 g_message(" Pixel sizes: ");
2830 tmp_sizes = fontsel_info->pixel_sizes + styles->pixel_sizes_index;
2831 for (size = 0; size < styles->npixel_sizes; size++)
2832 g_message("%i ", *tmp_sizes++);
2836 if (styles->npoint_sizes)
2838 g_message(" Point sizes: ");
2839 tmp_sizes = fontsel_info->point_sizes + styles->point_sizes_index;
2840 for (size = 0; size < styles->npoint_sizes; size++)
2841 g_message("%i ", *tmp_sizes++);
2849 /* This outputs all available properties. */
2850 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2852 g_message("Property: %s\n", xlfd_field_names[xlfd_index[prop]]);
2853 for (i = 0; i < fontsel_info->nproperties[prop]; i++)
2854 g_message(" %s\n", fontsel_info->properties[prop][i]);
2859 /* This inserts the given fontname into the FontInfo table.
2860 If a FontInfo already exists with the same family and foundry, then the
2861 fontname is added to the FontInfos list of fontnames, else a new FontInfo
2862 is created and inserted in alphabetical order in the table. */
2864 gtk_font_selection_insert_font (GSList *fontnames[],
2870 GSList *temp_fontname;
2872 gboolean family_exists = FALSE;
2876 gchar family_buffer[XLFD_MAX_FIELD_LEN];
2878 table = fontsel_info->font_info;
2880 /* insert a fontname into a table */
2881 family = gtk_font_selection_get_xlfd_field (fontname, XLFD_FAMILY,
2886 foundry = gtk_font_selection_insert_field (fontname, FOUNDRY);
2891 /* Do a binary search to determine if we have already encountered
2892 * a font with this family & foundry. */
2894 while (lower < upper)
2896 middle = (lower + upper) >> 1;
2898 cmp = strcmp (family, table[middle].family);
2899 /* If the family matches we sort by the foundry. */
2902 family_exists = TRUE;
2903 family = table[middle].family;
2904 cmp = strcmp(fontsel_info->properties[FOUNDRY][foundry],
2905 fontsel_info->properties[FOUNDRY][table[middle].foundry]);
2910 fontnames[middle] = g_slist_prepend (fontnames[middle],
2921 /* Add another entry to the table for this new font family */
2922 temp_info.family = family_exists ? family : g_strdup(family);
2923 temp_info.foundry = foundry;
2924 temp_fontname = g_slist_prepend (NULL, fontname);
2928 /* Quickly insert the entry into the table in sorted order
2929 * using a modification of insertion sort and the knowledge
2930 * that the entries proper position in the table was determined
2931 * above in the binary search and is contained in the "lower"
2935 upper = *ntable - 1;
2936 while (lower != upper)
2938 table[upper] = table[upper-1];
2939 fontnames[upper] = fontnames[upper-1];
2943 table[lower] = temp_info;
2944 fontnames[lower] = temp_fontname;
2948 /* This checks that the specified field of the given fontname is in the
2949 appropriate properties array. If not it is added. Thus eventually we get
2950 arrays of all possible weights/slants etc. It returns the array index. */
2952 gtk_font_selection_insert_field (gchar *fontname,
2955 gchar field_buffer[XLFD_MAX_FIELD_LEN];
2959 field = gtk_font_selection_get_xlfd_field (fontname, xlfd_index[prop],
2964 /* If the field is already in the array just return its index. */
2965 for (index = 0; index < fontsel_info->nproperties[prop]; index++)
2966 if (!strcmp(field, fontsel_info->properties[prop][index]))
2969 /* Make sure we have enough space to add the field. */
2970 if (fontsel_info->nproperties[prop] == fontsel_info->space_allocated[prop])
2972 fontsel_info->space_allocated[prop] += PROPERTY_ARRAY_INCREMENT;
2973 fontsel_info->properties[prop] = g_realloc(fontsel_info->properties[prop],
2975 * fontsel_info->space_allocated[prop]);
2978 /* Add the new field. */
2979 index = fontsel_info->nproperties[prop];
2980 fontsel_info->properties[prop][index] = g_strdup(field);
2981 fontsel_info->nproperties[prop]++;
2986 /*****************************************************************************
2987 * These functions are the main public interface for getting/setting the font.
2988 *****************************************************************************/
2991 gtk_font_selection_get_font (GtkFontSelection *fontsel)
2993 g_return_val_if_fail (fontsel != NULL, NULL);
2994 return fontsel->font;
2999 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
3002 gchar *family_str, *foundry_str;
3003 gchar *property_str[GTK_NUM_STYLE_PROPERTIES];
3006 g_return_val_if_fail (fontsel != NULL, NULL);
3007 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
3009 /* If no family has been selected return NULL. */
3010 if (fontsel->font_index == -1)
3013 font = &fontsel_info->font_info[fontsel->font_index];
3014 family_str = font->family;
3015 foundry_str = fontsel_info->properties[FOUNDRY][font->foundry];
3017 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
3020 = fontsel_info->properties[prop][fontsel->property_values[prop]];
3021 if (strcmp (property_str[prop], "(nil)") == 0)
3022 property_str[prop] = "";
3025 return gtk_font_selection_create_xlfd (fontsel->size,
3029 property_str[WEIGHT],
3030 property_str[SLANT],
3031 property_str[SET_WIDTH],
3032 property_str[SPACING],
3033 property_str[CHARSET]);
3037 /* This returns the style with the best match to the current fontsel setting,
3038 i.e. with the highest number of matching property values. */
3040 gtk_font_selection_get_best_match(GtkFontSelection *fontsel)
3044 gint prop, style, best_style = 0, matched, best_matched = 0;
3046 font = &fontsel_info->font_info[fontsel->font_index];
3047 styles = &fontsel_info->font_styles[font->style_index];
3049 /* Find the style with the most matches. */
3050 for (style = 0; style < font->nstyles; style++)
3053 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
3055 if (fontsel->property_values[prop] == styles[style].properties[prop])
3058 if (matched > best_matched)
3060 best_matched = matched;
3069 /* This sets the current font, selecting the appropriate clist rows.
3070 First we check the fontname is valid and try to find the font family
3071 - i.e. the name in the main list. If we can't find that, then just return.
3072 Next we try to set each of the properties according to the fontname.
3073 Finally we select the font family & style in the clists. */
3075 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
3076 const gchar *fontname)
3078 gchar *family, *field;
3079 gint index, prop, size;
3080 guint16 foundry, value;
3081 gchar family_buffer[XLFD_MAX_FIELD_LEN];
3082 gchar field_buffer[XLFD_MAX_FIELD_LEN];
3085 g_return_val_if_fail (fontsel != NULL, FALSE);
3086 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
3087 g_return_val_if_fail (fontname != NULL, FALSE);
3089 /* Check it is a valid fontname. */
3090 if (!gtk_font_selection_is_xlfd_font_name(fontname))
3093 family = gtk_font_selection_get_xlfd_field (fontname, XLFD_FAMILY,
3098 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_FOUNDRY,
3100 foundry = gtk_font_selection_field_to_index (fontsel_info->properties[FOUNDRY],
3101 fontsel_info->nproperties[FOUNDRY],
3104 index = gtk_font_selection_find_font(fontsel, family, foundry);
3108 /* Convert the property fields into indices and set them. */
3109 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
3111 field = gtk_font_selection_get_xlfd_field (fontname, xlfd_index[prop],
3113 value = gtk_font_selection_field_to_index (fontsel_info->properties[prop],
3114 fontsel_info->nproperties[prop],
3116 fontsel->property_values[prop] = value;
3119 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_POINTS,
3126 fontsel->size = fontsel->selected_size = size;
3127 fontsel->metric = GTK_FONT_METRIC_POINTS;
3128 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->points_button),
3131 sprintf (buffer, "%i", size / 10);
3133 sprintf (buffer, "%i.%i", size / 10, size % 10);
3137 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_PIXELS,
3142 fontsel->size = fontsel->selected_size = size;
3143 fontsel->metric = GTK_FONT_METRIC_PIXELS;
3144 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->pixels_button),
3146 sprintf (buffer, "%i", size);
3148 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
3150 /* Clear any current filter. */
3151 gtk_font_selection_clear_filter(fontsel);
3153 /* Now find the best style match. */
3154 fontsel->font_index = index;
3155 gtk_clist_select_row(GTK_CLIST(fontsel->font_clist), index, 0);
3156 if (GTK_WIDGET_MAPPED (fontsel->font_clist))
3157 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), index, -1, 0.5, 0);
3159 gtk_font_selection_show_available_styles (fontsel);
3160 /* This will load the font. */
3161 gtk_font_selection_select_best_style (fontsel, FALSE);
3167 /* Returns the index of the given family, or -1 if not found */
3169 gtk_font_selection_find_font (GtkFontSelection *fontsel,
3173 FontInfo *font_info;
3174 gint lower, upper, middle = -1, cmp, nfonts;
3176 font_info = fontsel_info->font_info;
3177 nfonts = fontsel_info->nfonts;
3181 /* Do a binary search to find the font family. */
3184 while (lower < upper)
3186 middle = (lower + upper) >> 1;
3188 cmp = strcmp (family, font_info[middle].family);
3190 cmp = strcmp(fontsel_info->properties[FOUNDRY][foundry],
3191 fontsel_info->properties[FOUNDRY][font_info[middle].foundry]);
3201 /* If we can't match family & foundry see if just the family matches */
3202 if (!strcmp (family, font_info[middle].family))
3209 /* This returns the text in the preview entry. You should copy the returned
3210 text if you need it. */
3212 gtk_font_selection_get_preview_text (GtkFontSelection *fontsel)
3214 return gtk_entry_get_text(GTK_ENTRY(fontsel->preview_entry));
3218 /* This sets the text in the preview entry. */
3220 gtk_font_selection_set_preview_text (GtkFontSelection *fontsel,
3223 gtk_entry_set_text(GTK_ENTRY(fontsel->preview_entry), text);
3227 /*****************************************************************************
3228 * These functions all deal with X Logical Font Description (XLFD) fontnames.
3229 * See the freely available documentation about this.
3230 *****************************************************************************/
3233 * Returns TRUE if the fontname is a valid XLFD.
3234 * (It just checks if the number of dashes is 14, and that each
3235 * field < XLFD_MAX_FIELD_LEN characters long - that's not in the XLFD but it
3236 * makes it easier for me).
3239 gtk_font_selection_is_xlfd_font_name (const gchar *fontname)
3246 if (*fontname++ == '-')
3248 if (field_len > XLFD_MAX_FIELD_LEN) return FALSE;
3256 return (i == 14) ? TRUE : FALSE;
3260 * This fills the buffer with the specified field from the X Logical Font
3261 * Description name, and returns it. If fontname is NULL or the field is
3262 * longer than XFLD_MAX_FIELD_LEN it returns NULL.
3263 * Note: For the charset field, we also return the encoding, e.g. 'iso8859-1'.
3266 gtk_font_selection_get_xlfd_field (const gchar *fontname,
3267 FontField field_num,
3270 const gchar *t1, *t2;
3271 gint countdown, len, num_dashes;
3276 /* we assume this is a valid fontname...that is, it has 14 fields */
3278 countdown = field_num;
3280 while (*t1 && (countdown >= 0))
3284 num_dashes = (field_num == XLFD_CHARSET) ? 2 : 1;
3285 for (t2 = t1; *t2; t2++)
3287 if (*t2 == '-' && --num_dashes == 0)
3293 /* Check we don't overflow the buffer */
3294 len = (long) t2 - (long) t1;
3295 if (len > XLFD_MAX_FIELD_LEN - 1)
3297 strncpy (buffer, t1, len);
3300 /* Convert to lower case. */
3304 strcpy(buffer, "(nil)");
3310 * This returns a X Logical Font Description font name, given all the pieces.
3311 * Note: this retval must be freed by the caller.
3314 gtk_font_selection_create_xlfd (gint size,
3315 GtkFontMetricType metric,
3325 gchar *pixel_size = "*", *point_size = "*", *fontname;
3331 sprintf (buffer, "%d", (int) size);
3332 if (metric == GTK_FONT_METRIC_PIXELS)
3333 pixel_size = buffer;
3335 point_size = buffer;
3337 /* Note: be careful here - don't overrun the allocated memory. */
3338 length = strlen(foundry) + strlen(family) + strlen(weight) + strlen(slant)
3339 + strlen(set_width) + strlen(pixel_size) + strlen(point_size)
3340 + strlen(spacing) + strlen(charset)
3341 + 1 + 1 + 1 + 1 + 1 + 3 + 1 + 5 + 3
3342 + 1 /* for the terminating '\0'. */;
3344 fontname = g_new(gchar, length);
3345 /* **NOTE**: If you change this string please change length above! */
3346 sprintf(fontname, "-%s-%s-%s-%s-%s-*-%s-%s-*-*-%s-*-%s",
3347 foundry, family, weight, slant, set_width, pixel_size,
3348 point_size, spacing, charset);
3354 /*****************************************************************************
3355 * GtkFontSelectionDialog
3356 *****************************************************************************/
3359 gtk_font_selection_dialog_get_type (void)
3361 static guint font_selection_dialog_type = 0;
3363 if (!font_selection_dialog_type)
3365 GtkTypeInfo fontsel_diag_info =
3367 "GtkFontSelectionDialog",
3368 sizeof (GtkFontSelectionDialog),
3369 sizeof (GtkFontSelectionDialogClass),
3370 (GtkClassInitFunc) gtk_font_selection_dialog_class_init,
3371 (GtkObjectInitFunc) gtk_font_selection_dialog_init,
3372 /* reserved_1 */ NULL,
3373 /* reserved_2 */ NULL,
3374 (GtkClassInitFunc) NULL,
3377 font_selection_dialog_type = gtk_type_unique (GTK_TYPE_WINDOW, &fontsel_diag_info);
3380 return font_selection_dialog_type;
3384 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
3386 GtkObjectClass *object_class;
3388 object_class = (GtkObjectClass*) klass;
3390 font_selection_dialog_parent_class = gtk_type_class (GTK_TYPE_WINDOW);
3394 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
3396 fontseldiag->dialog_width = -1;
3397 fontseldiag->auto_resize = TRUE;
3399 gtk_widget_set_events(GTK_WIDGET(fontseldiag), GDK_STRUCTURE_MASK);
3400 gtk_signal_connect (GTK_OBJECT (fontseldiag), "configure_event",
3401 (GtkSignalFunc) gtk_font_selection_dialog_on_configure,
3404 gtk_container_border_width (GTK_CONTAINER (fontseldiag), 4);
3405 gtk_window_set_policy(GTK_WINDOW(fontseldiag), FALSE, TRUE, TRUE);
3407 fontseldiag->main_vbox = gtk_vbox_new (FALSE, 4);
3408 gtk_widget_show (fontseldiag->main_vbox);
3409 gtk_container_add (GTK_CONTAINER (fontseldiag), fontseldiag->main_vbox);
3411 fontseldiag->fontsel = gtk_font_selection_new();
3412 gtk_widget_show (fontseldiag->fontsel);
3413 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
3414 fontseldiag->fontsel, TRUE, TRUE, 0);
3416 /* Create the action area */
3417 fontseldiag->action_area = gtk_hbutton_box_new ();
3418 gtk_button_box_set_layout(GTK_BUTTON_BOX(fontseldiag->action_area),
3420 gtk_button_box_set_spacing(GTK_BUTTON_BOX(fontseldiag->action_area), 5);
3421 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
3422 fontseldiag->action_area, FALSE, FALSE, 0);
3423 gtk_widget_show (fontseldiag->action_area);
3425 fontseldiag->ok_button = gtk_button_new_with_label("OK");
3426 GTK_WIDGET_SET_FLAGS (fontseldiag->ok_button, GTK_CAN_DEFAULT);
3427 gtk_widget_show(fontseldiag->ok_button);
3428 gtk_box_pack_start (GTK_BOX (fontseldiag->action_area),
3429 fontseldiag->ok_button, TRUE, TRUE, 0);
3430 gtk_widget_grab_default (fontseldiag->ok_button);
3432 fontseldiag->apply_button = gtk_button_new_with_label("Apply");
3433 GTK_WIDGET_SET_FLAGS (fontseldiag->apply_button, GTK_CAN_DEFAULT);
3434 /*gtk_widget_show(fontseldiag->apply_button);*/
3435 gtk_box_pack_start (GTK_BOX(fontseldiag->action_area),
3436 fontseldiag->apply_button, TRUE, TRUE, 0);
3438 fontseldiag->cancel_button = gtk_button_new_with_label("Cancel");
3439 GTK_WIDGET_SET_FLAGS (fontseldiag->cancel_button, GTK_CAN_DEFAULT);
3440 gtk_widget_show(fontseldiag->cancel_button);
3441 gtk_box_pack_start (GTK_BOX(fontseldiag->action_area),
3442 fontseldiag->cancel_button, TRUE, TRUE, 0);
3448 gtk_font_selection_dialog_new (const gchar *title)
3450 GtkFontSelectionDialog *fontseldiag;
3452 fontseldiag = gtk_type_new (GTK_TYPE_FONT_SELECTION_DIALOG);
3453 gtk_window_set_title (GTK_WINDOW (fontseldiag),
3454 title ? title : "Font Selection");
3456 return GTK_WIDGET (fontseldiag);
3460 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
3462 return gtk_font_selection_get_font_name(GTK_FONT_SELECTION(fsd->fontsel));
3466 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
3468 return gtk_font_selection_get_font(GTK_FONT_SELECTION(fsd->fontsel));
3472 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
3473 const gchar *fontname)
3475 return gtk_font_selection_set_font_name(GTK_FONT_SELECTION(fsd->fontsel),
3480 gtk_font_selection_dialog_set_filter (GtkFontSelectionDialog *fsd,
3481 GtkFontFilterType filter_type,
3482 GtkFontType font_type,
3490 gtk_font_selection_set_filter (GTK_FONT_SELECTION (fsd->fontsel),
3491 filter_type, font_type,
3492 foundries, weights, slants, setwidths,
3493 spacings, charsets);
3497 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
3499 return gtk_font_selection_get_preview_text(GTK_FONT_SELECTION(fsd->fontsel));
3503 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
3506 gtk_font_selection_set_preview_text(GTK_FONT_SELECTION(fsd->fontsel), text);
3510 /* This turns auto-shrink off if the user resizes the width of the dialog.
3511 It also turns it back on again if the user resizes it back to its normal
3514 gtk_font_selection_dialog_on_configure (GtkWidget *widget,
3515 GdkEventConfigure *event,
3516 GtkFontSelectionDialog *fsd)
3518 /* This sets the initial width. */
3519 if (fsd->dialog_width == -1)
3520 fsd->dialog_width = event->width;
3521 else if (fsd->auto_resize && fsd->dialog_width != event->width)
3523 fsd->auto_resize = FALSE;
3524 gtk_window_set_policy(GTK_WINDOW(fsd), FALSE, TRUE, FALSE);
3526 else if (!fsd->auto_resize && fsd->dialog_width == event->width)
3528 fsd->auto_resize = TRUE;
3529 gtk_window_set_policy(GTK_WINDOW(fsd), FALSE, TRUE, TRUE);