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 const 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 190
118 #define FONT_STYLE_LIST_WIDTH 170
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 const 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 const FontField xlfd_index[GTK_NUM_FONT_PROPERTIES] = {
240 /* These are the positions of the properties in the filter table - x, y. */
241 static const gint filter_positions[GTK_NUM_FONT_PROPERTIES][2] = {
242 { 1, 0 }, { 0, 2 }, { 1, 2 }, { 2, 2 }, { 2, 0 }, { 0, 0 }
244 static const gint filter_heights[GTK_NUM_FONT_PROPERTIES] = {
245 100, 70, 70, 40, 100, 100
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,
293 static void gtk_font_selection_select_style (GtkWidget *w,
296 GdkEventButton *bevent,
298 static void gtk_font_selection_show_available_sizes
299 (GtkFontSelection *fs);
300 static gint gtk_font_selection_size_key_press (GtkWidget *w,
303 static void gtk_font_selection_select_best_size (GtkFontSelection *fs);
304 static void gtk_font_selection_select_size (GtkWidget *w,
307 GdkEventButton *bevent,
310 static void gtk_font_selection_metric_callback (GtkWidget *w,
312 static void gtk_font_selection_expose_list (GtkWidget *w,
313 GdkEventExpose *event,
315 static void gtk_font_selection_realize_list (GtkWidget *widget,
318 static void gtk_font_selection_switch_page (GtkWidget *w,
319 GtkNotebookPage *page,
322 static void gtk_font_selection_show_font_info (GtkFontSelection *fs);
324 static void gtk_font_selection_select_filter (GtkWidget *w,
327 GdkEventButton *bevent,
328 GtkFontSelection *fs);
329 static void gtk_font_selection_unselect_filter (GtkWidget *w,
332 GdkEventButton *bevent,
333 GtkFontSelection *fs);
334 static void gtk_font_selection_update_filter (GtkFontSelection *fs);
335 static gboolean gtk_font_selection_style_visible (GtkFontSelection *fs,
338 static void gtk_font_selection_reset_filter (GtkWidget *w,
339 GtkFontSelection *fs);
340 static void gtk_font_selection_on_clear_filter (GtkWidget *w,
341 GtkFontSelection *fs);
342 static void gtk_font_selection_show_available_fonts
343 (GtkFontSelection *fs);
344 static void gtk_font_selection_clear_filter (GtkFontSelection *fs);
345 static void gtk_font_selection_update_filter_lists(GtkFontSelection *fs);
346 static GtkFontPropertyFilterState gtk_font_selection_filter_state
347 (GtkFontSelection *fs,
348 GtkFontFilterType filter_type,
352 /* Misc. utility functions. */
353 static gboolean gtk_font_selection_load_font (GtkFontSelection *fs);
354 static void gtk_font_selection_update_preview (GtkFontSelection *fs);
356 static gint gtk_font_selection_find_font (GtkFontSelection *fs,
359 static guint16 gtk_font_selection_field_to_index (gchar **table,
363 static gchar* gtk_font_selection_expand_slant_code (gchar *slant);
364 static gchar* gtk_font_selection_expand_spacing_code(gchar *spacing);
366 /* Functions for handling X Logical Font Description fontnames. */
367 static gboolean gtk_font_selection_is_xlfd_font_name (const gchar *fontname);
368 static char* gtk_font_selection_get_xlfd_field (const gchar *fontname,
371 static gchar * gtk_font_selection_create_xlfd (gint size,
372 GtkFontMetricType metric,
382 /* FontSelectionDialog */
383 static void gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass);
384 static void gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag);
386 static gint gtk_font_selection_dialog_on_configure(GtkWidget *widget,
387 GdkEventConfigure *event,
388 GtkFontSelectionDialog *fsd);
390 static GtkWindowClass *font_selection_parent_class = NULL;
391 static GtkNotebookClass *font_selection_dialog_parent_class = NULL;
394 gtk_font_selection_get_type()
396 static GtkType font_selection_type = 0;
398 if(!font_selection_type)
400 static const GtkTypeInfo fontsel_type_info =
403 sizeof (GtkFontSelection),
404 sizeof (GtkFontSelectionClass),
405 (GtkClassInitFunc) gtk_font_selection_class_init,
406 (GtkObjectInitFunc) gtk_font_selection_init,
407 /* reserved_1 */ NULL,
408 /* reserved_2 */ NULL,
409 (GtkClassInitFunc) NULL,
412 font_selection_type = gtk_type_unique (GTK_TYPE_NOTEBOOK,
416 return font_selection_type;
420 gtk_font_selection_class_init(GtkFontSelectionClass *klass)
422 GtkObjectClass *object_class;
424 object_class = (GtkObjectClass *) klass;
426 font_selection_parent_class = gtk_type_class (GTK_TYPE_NOTEBOOK);
428 object_class->destroy = gtk_font_selection_destroy;
430 gtk_font_selection_get_fonts ();
434 gtk_font_selection_init(GtkFontSelection *fontsel)
436 GtkWidget *scrolled_win;
437 GtkWidget *text_frame;
438 GtkWidget *text_box, *frame;
439 GtkWidget *table, *label, *hbox, *hbox2, *clist, *button, *vbox, *alignment;
441 gchar *titles[] = { "Font Property", "Requested Value", "Actual Value" };
445 const gchar *row_text[3];
446 gchar *property, *text;
449 /* Initialize the GtkFontSelection struct. We do this here in case any
450 callbacks are triggered while creating the interface. */
451 fontsel->font = NULL;
452 fontsel->font_index = -1;
454 fontsel->metric = INITIAL_METRIC;
455 fontsel->size = INITIAL_FONT_SIZE;
456 fontsel->selected_size = INITIAL_FONT_SIZE;
458 fontsel->filters[GTK_FONT_FILTER_BASE].font_type = GTK_FONT_ALL;
459 fontsel->filters[GTK_FONT_FILTER_USER].font_type = GTK_FONT_BITMAP
463 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
465 fontsel->filters[GTK_FONT_FILTER_BASE].property_filters[prop] = NULL;
466 fontsel->filters[GTK_FONT_FILTER_BASE].property_nfilters[prop] = 0;
467 fontsel->filters[GTK_FONT_FILTER_USER].property_filters[prop] = NULL;
468 fontsel->filters[GTK_FONT_FILTER_USER].property_nfilters[prop] = 0;
471 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
472 fontsel->property_values[prop] = 0;
474 /* Create the main notebook page. */
475 gtk_notebook_set_homogeneous_tabs (GTK_NOTEBOOK (fontsel), TRUE);
476 gtk_notebook_set_tab_hborder (GTK_NOTEBOOK (fontsel), 8);
477 fontsel->main_vbox = gtk_vbox_new (FALSE, 4);
478 gtk_widget_show (fontsel->main_vbox);
479 gtk_container_set_border_width (GTK_CONTAINER (fontsel->main_vbox), 6);
480 label = gtk_label_new("Font");
481 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
482 fontsel->main_vbox, label);
484 /* Create the table of font, style & size. */
485 table = gtk_table_new (3, 3, FALSE);
486 gtk_widget_show (table);
487 gtk_table_set_col_spacings(GTK_TABLE(table), 8);
488 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), table, TRUE, TRUE, 0);
490 fontsel->font_label = gtk_label_new("Font:");
491 gtk_misc_set_alignment (GTK_MISC (fontsel->font_label), 0.0, 0.5);
492 gtk_widget_show (fontsel->font_label);
493 gtk_table_attach (GTK_TABLE (table), fontsel->font_label, 0, 1, 0, 1,
495 label = gtk_label_new("Font Style:");
496 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
497 gtk_widget_show (label);
498 gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1,
500 label = gtk_label_new("Size:");
501 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
502 gtk_widget_show (label);
503 gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
506 fontsel->font_entry = gtk_entry_new();
507 gtk_entry_set_editable(GTK_ENTRY(fontsel->font_entry), FALSE);
508 gtk_widget_set_usize (fontsel->font_entry, 20, -1);
509 gtk_widget_show (fontsel->font_entry);
510 gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
512 fontsel->font_style_entry = gtk_entry_new();
513 gtk_entry_set_editable(GTK_ENTRY(fontsel->font_style_entry), FALSE);
514 gtk_widget_set_usize (fontsel->font_style_entry, 20, -1);
515 gtk_widget_show (fontsel->font_style_entry);
516 gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
518 fontsel->size_entry = gtk_entry_new();
519 gtk_widget_set_usize (fontsel->size_entry, 20, -1);
520 gtk_widget_show (fontsel->size_entry);
521 gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
523 gtk_signal_connect (GTK_OBJECT (fontsel->size_entry), "key_press_event",
524 (GtkSignalFunc) gtk_font_selection_size_key_press,
527 /* Create the clists */
528 fontsel->font_clist = gtk_clist_new(1);
529 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->font_clist));
530 gtk_clist_set_column_auto_resize (GTK_CLIST (fontsel->font_clist), 0, TRUE);
531 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
532 gtk_widget_set_usize (scrolled_win, FONT_LIST_WIDTH, FONT_LIST_HEIGHT);
533 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->font_clist);
534 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
535 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
536 gtk_widget_show(fontsel->font_clist);
537 gtk_widget_show(scrolled_win);
539 gtk_table_attach (GTK_TABLE (table), scrolled_win, 0, 1, 2, 3,
540 GTK_EXPAND | GTK_FILL,
541 GTK_EXPAND | GTK_FILL, 0, 0);
543 fontsel->font_style_clist = gtk_clist_new(1);
544 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->font_style_clist));
545 gtk_clist_set_column_auto_resize (GTK_CLIST (fontsel->font_style_clist),
547 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
548 gtk_widget_set_usize (scrolled_win, FONT_STYLE_LIST_WIDTH, -1);
549 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->font_style_clist);
550 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
551 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
552 gtk_widget_show(fontsel->font_style_clist);
553 gtk_widget_show(scrolled_win);
554 gtk_table_attach (GTK_TABLE (table), scrolled_win, 1, 2, 2, 3,
555 GTK_EXPAND | GTK_FILL,
556 GTK_EXPAND | GTK_FILL, 0, 0);
558 fontsel->size_clist = gtk_clist_new(1);
559 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->size_clist));
560 gtk_clist_set_column_width (GTK_CLIST(fontsel->size_clist), 0, 20);
561 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
562 gtk_widget_set_usize (scrolled_win, FONT_SIZE_LIST_WIDTH, -1);
563 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->size_clist);
564 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
565 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
566 gtk_widget_show(fontsel->size_clist);
567 gtk_widget_show(scrolled_win);
568 gtk_table_attach (GTK_TABLE (table), scrolled_win, 2, 3, 2, 3,
569 GTK_FILL, GTK_FILL, 0, 0);
572 /* Insert the fonts. If there exist fonts with the same family but
573 different foundries, then the foundry name is appended in brackets. */
574 gtk_font_selection_show_available_fonts(fontsel);
576 gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "select_row",
577 GTK_SIGNAL_FUNC(gtk_font_selection_select_font),
579 GTK_WIDGET_SET_FLAGS (fontsel->font_clist, GTK_CAN_FOCUS);
580 gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "key_press_event",
581 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
583 gtk_signal_connect_after (GTK_OBJECT (fontsel->font_clist), "expose_event",
584 GTK_SIGNAL_FUNC(gtk_font_selection_expose_list),
587 gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist), "select_row",
588 GTK_SIGNAL_FUNC(gtk_font_selection_select_style),
590 GTK_WIDGET_SET_FLAGS (fontsel->font_style_clist, GTK_CAN_FOCUS);
591 gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist),
593 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
595 gtk_signal_connect_after (GTK_OBJECT (fontsel->font_style_clist),
597 GTK_SIGNAL_FUNC(gtk_font_selection_realize_list),
600 /* Insert the standard font sizes */
601 gtk_clist_freeze (GTK_CLIST(fontsel->size_clist));
602 size_to_match = INITIAL_FONT_SIZE;
603 if (INITIAL_METRIC == GTK_FONT_METRIC_POINTS)
604 size_to_match = size_to_match / 10;
605 for (i = 0; i < sizeof(font_sizes) / sizeof(font_sizes[0]); i++)
607 sprintf(buffer, "%i", font_sizes[i]);
609 gtk_clist_append(GTK_CLIST(fontsel->size_clist), &size);
610 if (font_sizes[i] == size_to_match)
612 gtk_clist_select_row(GTK_CLIST(fontsel->size_clist), i, 0);
613 gtk_entry_set_text(GTK_ENTRY(fontsel->size_entry), buffer);
616 gtk_clist_thaw (GTK_CLIST(fontsel->size_clist));
618 gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "select_row",
619 GTK_SIGNAL_FUNC(gtk_font_selection_select_size),
621 GTK_WIDGET_SET_FLAGS (fontsel->size_clist, GTK_CAN_FOCUS);
622 gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "key_press_event",
623 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
627 /* create the Reset Filter & Metric buttons */
628 hbox = gtk_hbox_new(FALSE, 8);
629 gtk_widget_show (hbox);
630 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), hbox, FALSE, TRUE, 0);
632 fontsel->filter_button = gtk_button_new_with_label("Reset Filter");
633 gtk_misc_set_padding (GTK_MISC (GTK_BIN (fontsel->filter_button)->child),
635 gtk_widget_show(fontsel->filter_button);
636 gtk_box_pack_start (GTK_BOX (hbox), fontsel->filter_button, FALSE, FALSE, 0);
637 gtk_widget_set_sensitive (fontsel->filter_button, FALSE);
638 gtk_signal_connect (GTK_OBJECT (fontsel->filter_button), "clicked",
639 GTK_SIGNAL_FUNC(gtk_font_selection_on_clear_filter),
642 hbox2 = gtk_hbox_new(FALSE, 0);
643 gtk_widget_show (hbox2);
644 gtk_box_pack_end (GTK_BOX (hbox), hbox2, FALSE, FALSE, 0);
646 label = gtk_label_new("Metric:");
647 gtk_widget_show (label);
648 gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 8);
650 fontsel->points_button = gtk_radio_button_new_with_label(NULL, "Points");
651 gtk_widget_show (fontsel->points_button);
652 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->points_button, FALSE, TRUE, 0);
653 if (INITIAL_METRIC == GTK_FONT_METRIC_POINTS)
654 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->points_button),
657 fontsel->pixels_button = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(fontsel->points_button), "Pixels");
658 gtk_widget_show (fontsel->pixels_button);
659 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->pixels_button, FALSE, TRUE, 0);
660 if (INITIAL_METRIC == GTK_FONT_METRIC_PIXELS)
661 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->pixels_button),
664 gtk_signal_connect(GTK_OBJECT(fontsel->points_button), "toggled",
665 (GtkSignalFunc) gtk_font_selection_metric_callback,
667 gtk_signal_connect(GTK_OBJECT(fontsel->pixels_button), "toggled",
668 (GtkSignalFunc) gtk_font_selection_metric_callback,
672 /* create the text entry widget */
673 text_frame = gtk_frame_new ("Preview:");
674 gtk_widget_show (text_frame);
675 gtk_frame_set_shadow_type(GTK_FRAME(text_frame), GTK_SHADOW_ETCHED_IN);
676 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), text_frame,
679 /* This is just used to get a 4-pixel space around the preview entry. */
680 text_box = gtk_hbox_new (FALSE, 0);
681 gtk_widget_show (text_box);
682 gtk_container_add (GTK_CONTAINER (text_frame), text_box);
683 gtk_container_set_border_width (GTK_CONTAINER (text_box), 4);
685 fontsel->preview_entry = gtk_entry_new ();
686 gtk_widget_show (fontsel->preview_entry);
687 gtk_widget_set_usize (fontsel->preview_entry, -1, INITIAL_PREVIEW_HEIGHT);
688 gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
691 /* Create the message area */
692 fontsel->message_label = gtk_label_new("");
693 gtk_widget_show (fontsel->message_label);
694 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), fontsel->message_label,
698 /* Create the font info page */
699 fontsel->info_vbox = gtk_vbox_new (FALSE, 4);
700 gtk_widget_show (fontsel->info_vbox);
701 gtk_container_set_border_width (GTK_CONTAINER (fontsel->info_vbox), 2);
702 label = gtk_label_new("Font Information");
703 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
704 fontsel->info_vbox, label);
706 fontsel->info_clist = gtk_clist_new_with_titles (3, titles);
707 gtk_widget_set_usize (fontsel->info_clist, 390, 150);
708 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 0, 130);
709 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 1, 130);
710 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 2, 130);
711 gtk_clist_column_titles_passive(GTK_CLIST(fontsel->info_clist));
712 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
713 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->info_clist);
714 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
715 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
716 gtk_widget_show(fontsel->info_clist);
717 gtk_widget_show(scrolled_win);
718 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), scrolled_win,
721 /* Insert the property names */
722 gtk_clist_freeze (GTK_CLIST(fontsel->info_clist));
725 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
727 row_text[0] = xlfd_field_names[i];
728 gtk_clist_append(GTK_CLIST(fontsel->info_clist), row_text);
729 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 0, 0, 4);
730 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 1, 0, 4);
731 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 2, 0, 4);
733 gtk_clist_thaw (GTK_CLIST(fontsel->info_clist));
735 label = gtk_label_new("Requested Font Name:");
736 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
737 gtk_widget_show (label);
738 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, TRUE, 0);
740 fontsel->requested_font_name = gtk_entry_new();
741 gtk_entry_set_editable(GTK_ENTRY(fontsel->requested_font_name), FALSE);
742 gtk_widget_show (fontsel->requested_font_name);
743 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox),
744 fontsel->requested_font_name, FALSE, TRUE, 0);
746 label = gtk_label_new("Actual Font Name:");
747 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
748 gtk_widget_show (label);
749 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, TRUE, 0);
751 fontsel->actual_font_name = gtk_entry_new();
752 gtk_entry_set_editable(GTK_ENTRY(fontsel->actual_font_name), FALSE);
753 gtk_widget_show (fontsel->actual_font_name);
754 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox),
755 fontsel->actual_font_name, FALSE, TRUE, 0);
757 sprintf(buffer, "%i fonts available with a total of %i styles.",
758 fontsel_info->nfonts, fontsel_info->nstyles);
759 label = gtk_label_new(buffer);
760 gtk_widget_show (label);
761 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, FALSE, 0);
763 gtk_signal_connect (GTK_OBJECT (fontsel), "switch_page",
764 GTK_SIGNAL_FUNC(gtk_font_selection_switch_page),
768 /* Create the Filter page. */
769 fontsel->filter_vbox = gtk_vbox_new (FALSE, 4);
770 gtk_widget_show (fontsel->filter_vbox);
771 gtk_container_set_border_width (GTK_CONTAINER (fontsel->filter_vbox), 2);
772 label = gtk_label_new("Filter");
773 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
774 fontsel->filter_vbox, label);
776 /* Create the font type checkbuttons. */
777 frame = gtk_frame_new (NULL);
778 gtk_widget_show (frame);
779 gtk_box_pack_start (GTK_BOX (fontsel->filter_vbox), frame, FALSE, TRUE, 0);
781 hbox = gtk_hbox_new (FALSE, 20);
782 gtk_widget_show (hbox);
783 gtk_container_add (GTK_CONTAINER (frame), hbox);
785 label = gtk_label_new("Font Types:");
786 gtk_widget_show (label);
787 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 10);
789 hbox2 = gtk_hbox_new (TRUE, 0);
790 gtk_widget_show (hbox2);
791 gtk_box_pack_start (GTK_BOX (hbox), hbox2, FALSE, TRUE, 0);
793 fontsel->type_bitmaps_button = gtk_check_button_new_with_label ("Bitmap");
794 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), TRUE);
795 gtk_widget_show (fontsel->type_bitmaps_button);
796 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_bitmaps_button,
799 fontsel->type_scalable_button = gtk_check_button_new_with_label ("Scalable");
800 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), TRUE);
801 gtk_widget_show (fontsel->type_scalable_button);
802 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_scalable_button,
805 fontsel->type_scaled_bitmaps_button = gtk_check_button_new_with_label ("Scaled Bitmap");
806 gtk_widget_show (fontsel->type_scaled_bitmaps_button);
807 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_scaled_bitmaps_button,
810 table = gtk_table_new (4, 3, FALSE);
811 gtk_table_set_col_spacings(GTK_TABLE(table), 2);
812 gtk_widget_show (table);
813 gtk_box_pack_start (GTK_BOX (fontsel->filter_vbox), table, TRUE, TRUE, 0);
815 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
817 gint left = filter_positions[prop][0];
818 gint top = filter_positions[prop][1];
820 label = gtk_label_new(xlfd_field_names[xlfd_index[prop]]);
821 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 1.0);
822 gtk_misc_set_padding (GTK_MISC (label), 0, 2);
823 gtk_widget_show(label);
824 gtk_table_attach (GTK_TABLE (table), label, left, left + 1,
825 top, top + 1, GTK_FILL, GTK_FILL, 0, 0);
827 clist = gtk_clist_new(1);
828 gtk_widget_set_usize (clist, 100, filter_heights[prop]);
829 gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_MULTIPLE);
830 gtk_clist_column_titles_hide(GTK_CLIST(clist));
831 gtk_clist_set_column_auto_resize (GTK_CLIST (clist), 0, TRUE);
832 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
833 gtk_container_add (GTK_CONTAINER (scrolled_win), clist);
834 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
835 GTK_POLICY_AUTOMATIC,
836 GTK_POLICY_AUTOMATIC);
837 gtk_widget_show(clist);
838 gtk_widget_show(scrolled_win);
840 /* For the bottom-right cell we add the 'Reset Filter' button. */
841 if (top == 2 && left == 2)
843 vbox = gtk_vbox_new(FALSE, 0);
844 gtk_widget_show(vbox);
845 gtk_table_attach (GTK_TABLE (table), vbox, left, left + 1,
846 top + 1, top + 2, GTK_FILL, GTK_FILL, 0, 0);
848 gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0);
850 alignment = gtk_alignment_new(0.5, 0.0, 0.8, 0.0);
851 gtk_widget_show(alignment);
852 gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, TRUE, 4);
854 button = gtk_button_new_with_label("Reset Filter");
855 gtk_widget_show(button);
856 gtk_container_add(GTK_CONTAINER(alignment), button);
857 gtk_signal_connect (GTK_OBJECT (button), "clicked",
858 GTK_SIGNAL_FUNC(gtk_font_selection_reset_filter),
862 gtk_table_attach (GTK_TABLE (table), scrolled_win,
863 left, left + 1, top + 1, top + 2,
864 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
866 gtk_signal_connect (GTK_OBJECT (clist), "select_row",
867 GTK_SIGNAL_FUNC(gtk_font_selection_select_filter),
869 gtk_signal_connect (GTK_OBJECT (clist), "unselect_row",
870 GTK_SIGNAL_FUNC(gtk_font_selection_unselect_filter),
873 /* Insert the property names, expanded, and in sorted order.
874 But we make sure that the wildcard '*' is first. */
875 gtk_clist_freeze (GTK_CLIST(clist));
877 gtk_clist_append(GTK_CLIST(clist), &property);
879 for (i = 1; i < fontsel_info->nproperties[prop]; i++) {
880 property = fontsel_info->properties[prop][i];
882 property = gtk_font_selection_expand_slant_code(property);
883 else if (prop == SPACING)
884 property = gtk_font_selection_expand_spacing_code(property);
887 for (row = 1; row < GTK_CLIST(clist)->rows; row++)
889 gtk_clist_get_text(GTK_CLIST(clist), row, 0, &text);
890 if (strcmp(property, text) < 0)
893 gtk_clist_insert(GTK_CLIST(clist), row, &property);
898 row = gtk_clist_append(GTK_CLIST(clist), &property);
899 gtk_clist_set_row_data(GTK_CLIST(clist), row, GINT_TO_POINTER (i));
901 gtk_clist_select_row(GTK_CLIST(clist), 0, 0);
902 gtk_clist_thaw (GTK_CLIST(clist));
903 fontsel->filter_clists[prop] = clist;
908 gtk_font_selection_new()
910 GtkFontSelection *fontsel;
912 fontsel = gtk_type_new (GTK_TYPE_FONT_SELECTION);
914 return GTK_WIDGET (fontsel);
918 gtk_font_selection_destroy (GtkObject *object)
920 GtkFontSelection *fontsel;
922 g_return_if_fail (object != NULL);
923 g_return_if_fail (GTK_IS_FONT_SELECTION (object));
925 fontsel = GTK_FONT_SELECTION (object);
927 /* All we have to do is unref the font, if we have one. */
929 gdk_font_unref (fontsel->font);
931 if (GTK_OBJECT_CLASS (font_selection_parent_class)->destroy)
932 (* GTK_OBJECT_CLASS (font_selection_parent_class)->destroy) (object);
936 /* This is called when the clist is exposed. Here we scroll to the current
937 font if necessary. */
939 gtk_font_selection_expose_list (GtkWidget *widget,
940 GdkEventExpose *event,
943 GtkFontSelection *fontsel;
949 g_message("In expose_list\n");
951 fontsel = GTK_FONT_SELECTION(data);
953 font_info = fontsel_info->font_info;
955 /* Try to scroll the font family clist to the selected item */
956 selection = GTK_CLIST(fontsel->font_clist)->selection;
959 index = GPOINTER_TO_INT (selection->data);
960 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_clist), index)
961 != GTK_VISIBILITY_FULL)
962 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), index, -1, 0.5, 0);
965 /* Try to scroll the font style clist to the selected item */
966 selection = GTK_CLIST(fontsel->font_style_clist)->selection;
969 index = GPOINTER_TO_INT (selection->data);
970 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_style_clist), index)
971 != GTK_VISIBILITY_FULL)
972 gtk_clist_moveto(GTK_CLIST(fontsel->font_style_clist), index, -1,
976 /* Try to scroll the font size clist to the selected item */
977 selection = GTK_CLIST(fontsel->size_clist)->selection;
980 index = GPOINTER_TO_INT (selection->data);
981 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->size_clist), index)
982 != GTK_VISIBILITY_FULL)
983 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), index, -1, 0.5, 0);
988 /* This is called when the style clist is realized. We need to set any
989 charset rows to insensitive colours. */
991 gtk_font_selection_realize_list (GtkWidget *widget,
994 GtkFontSelection *fontsel;
996 GdkColor *inactive_fg, *inactive_bg;
999 g_message("In realize_list\n");
1001 fontsel = GTK_FONT_SELECTION (data);
1003 /* Set the colours for any charset rows to insensitive. */
1004 inactive_fg = &fontsel->font_style_clist->style->fg[GTK_STATE_INSENSITIVE];
1005 inactive_bg = &fontsel->font_style_clist->style->bg[GTK_STATE_INSENSITIVE];
1007 for (row = 0; row < GTK_CLIST (fontsel->font_style_clist)->rows; row++)
1009 if (GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_style_clist), row)) == -1)
1011 gtk_clist_set_foreground (GTK_CLIST (fontsel->font_style_clist),
1013 gtk_clist_set_background (GTK_CLIST (fontsel->font_style_clist),
1020 /* This is called when a family is selected in the list. */
1022 gtk_font_selection_select_font (GtkWidget *w,
1025 GdkEventButton *bevent,
1028 GtkFontSelection *fontsel;
1029 FontInfo *font_info;
1032 #ifdef FONTSEL_DEBUG
1033 g_message("In select_font\n");
1035 fontsel = GTK_FONT_SELECTION(data);
1036 font_info = fontsel_info->font_info;
1038 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1039 gtk_widget_grab_focus (w);
1041 row = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_clist), row));
1042 font = &font_info[row];
1043 gtk_entry_set_text(GTK_ENTRY(fontsel->font_entry), font->family);
1045 /* If it is already the current font, just return. */
1046 if (fontsel->font_index == row)
1049 fontsel->font_index = row;
1050 gtk_font_selection_show_available_styles (fontsel);
1051 gtk_font_selection_select_best_style (fontsel, TRUE);
1056 gtk_font_selection_on_clist_key_press (GtkWidget *clist,
1058 GtkFontSelection *fontsel)
1060 #ifdef FONTSEL_DEBUG
1061 g_message("In on_clist_key_press\n");
1063 if (event->keyval == GDK_Up)
1064 return gtk_font_selection_select_next (fontsel, clist, -1);
1065 else if (event->keyval == GDK_Down)
1066 return gtk_font_selection_select_next (fontsel, clist, 1);
1073 gtk_font_selection_select_next (GtkFontSelection *fontsel,
1078 gint current_row, row;
1080 selection = GTK_CLIST(clist)->selection;
1083 current_row = GPOINTER_TO_INT (selection->data);
1085 /* Stop the normal clist key handler from being run. */
1086 gtk_signal_emit_stop_by_name (GTK_OBJECT (clist), "key_press_event");
1088 for (row = current_row + step;
1089 row >= 0 && row < GTK_CLIST(clist)->rows;
1092 /* If this is the style clist, make sure that the item is not a charset
1094 if (clist == fontsel->font_style_clist)
1095 if (GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(clist), row)) == -1)
1098 /* Now we've found the row to select. */
1099 if (gtk_clist_row_is_visible(GTK_CLIST(clist), row)
1100 != GTK_VISIBILITY_FULL)
1101 gtk_clist_moveto(GTK_CLIST(clist), row, -1, (step < 0) ? 0 : 1, 0);
1102 gtk_clist_select_row(GTK_CLIST(clist), row, 0);
1109 /* This fills the font style clist with all the possible style combinations
1110 for the current font family. */
1112 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
1116 gint style, tmpstyle, row;
1117 gint weight_index, slant_index, set_width_index, spacing_index;
1119 gchar *weight, *slant, *set_width, *spacing;
1120 gchar *charset = NULL;
1122 gchar buffer[XLFD_MAX_FIELD_LEN * 6 + 2];
1123 GdkColor *inactive_fg, *inactive_bg;
1124 gboolean show_charset;
1126 #ifdef FONTSEL_DEBUG
1127 g_message("In show_available_styles\n");
1129 font = &fontsel_info->font_info[fontsel->font_index];
1130 styles = &fontsel_info->font_styles[font->style_index];
1132 gtk_clist_freeze (GTK_CLIST(fontsel->font_style_clist));
1133 gtk_clist_clear (GTK_CLIST(fontsel->font_style_clist));
1135 /* First we mark all visible styles as not having been displayed yet,
1136 and check if every style has the same charset. If not then we will
1137 display the charset in the list before the styles. */
1138 show_charset = FALSE;
1140 for (style = 0; style < font->nstyles; style++)
1142 if (gtk_font_selection_style_visible(fontsel, font, style))
1144 styles[style].flags &= ~GTK_FONT_DISPLAYED;
1146 if (charset_index == -1)
1147 charset_index = styles[style].properties[CHARSET];
1148 else if (charset_index != styles[style].properties[CHARSET])
1149 show_charset = TRUE;
1152 styles[style].flags |= GTK_FONT_DISPLAYED;
1155 /* Step through the undisplayed styles, finding the next charset which
1156 hasn't been displayed yet. Then display the charset on one line, if
1157 necessary, and the visible styles indented beneath it. */
1158 inactive_fg = &fontsel->font_style_clist->style->fg[GTK_STATE_INSENSITIVE];
1159 inactive_bg = &fontsel->font_style_clist->style->bg[GTK_STATE_INSENSITIVE];
1161 for (style = 0; style < font->nstyles; style++)
1163 if (styles[style].flags & GTK_FONT_DISPLAYED)
1168 charset_index = styles[style].properties[CHARSET];
1169 charset = fontsel_info->properties[CHARSET] [charset_index];
1170 row = gtk_clist_append(GTK_CLIST(fontsel->font_style_clist),
1172 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_style_clist), row,
1174 if (GTK_WIDGET_REALIZED (fontsel->font_style_clist))
1176 gtk_clist_set_foreground(GTK_CLIST(fontsel->font_style_clist),
1178 gtk_clist_set_background(GTK_CLIST(fontsel->font_style_clist),
1183 for (tmpstyle = style; tmpstyle < font->nstyles; tmpstyle++)
1185 if (styles[tmpstyle].flags & GTK_FONT_DISPLAYED
1186 || charset_index != styles[tmpstyle].properties[CHARSET])
1189 styles[tmpstyle].flags |= GTK_FONT_DISPLAYED;
1191 weight_index = styles[tmpstyle].properties[WEIGHT];
1192 slant_index = styles[tmpstyle].properties[SLANT];
1193 set_width_index = styles[tmpstyle].properties[SET_WIDTH];
1194 spacing_index = styles[tmpstyle].properties[SPACING];
1195 weight = fontsel_info->properties[WEIGHT] [weight_index];
1196 slant = fontsel_info->properties[SLANT] [slant_index];
1197 set_width = fontsel_info->properties[SET_WIDTH][set_width_index];
1198 spacing = fontsel_info->properties[SPACING] [spacing_index];
1200 /* Convert '(nil)' weights to 'regular', since it looks nicer. */
1201 if (!g_strcasecmp(weight, "(nil)")) weight = "regular";
1203 /* We don't show default values or (nil) in the other properties. */
1204 if (!g_strcasecmp(slant, "r")) slant = NULL;
1205 else if (!g_strcasecmp(slant, "(nil)")) slant = NULL;
1206 else if (!g_strcasecmp(slant, "i")) slant = "italic";
1207 else if (!g_strcasecmp(slant, "o")) slant = "oblique";
1208 else if (!g_strcasecmp(slant, "ri")) slant = "reverse italic";
1209 else if (!g_strcasecmp(slant, "ro")) slant = "reverse oblique";
1210 else if (!g_strcasecmp(slant, "ot")) slant = "other";
1212 if (!g_strcasecmp(set_width, "normal")) set_width = NULL;
1213 else if (!g_strcasecmp(set_width, "(nil)")) set_width = NULL;
1215 if (!g_strcasecmp(spacing, "p")) spacing = NULL;
1216 else if (!g_strcasecmp(spacing, "(nil)")) spacing = NULL;
1217 else if (!g_strcasecmp(spacing, "m")) spacing = "[M]";
1218 else if (!g_strcasecmp(spacing, "c")) spacing = "[C]";
1220 /* Add the strings together, making sure there is 1 space between
1222 strcpy(buffer, weight);
1225 strcat(buffer, " ");
1226 strcat(buffer, slant);
1230 strcat(buffer, " ");
1231 strcat(buffer, set_width);
1235 strcat(buffer, " ");
1236 strcat(buffer, spacing);
1240 row = gtk_clist_append(GTK_CLIST(fontsel->font_style_clist),
1243 gtk_clist_set_shift(GTK_CLIST(fontsel->font_style_clist), row, 0,
1245 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_style_clist), row,
1246 GINT_TO_POINTER (tmpstyle));
1250 gtk_clist_thaw (GTK_CLIST(fontsel->font_style_clist));
1254 /* This selects a style when the user selects a font. It just uses the first
1255 available style at present. I was thinking of trying to maintain the
1256 selected style, e.g. bold italic, when the user selects different fonts.
1257 However, the interface is so easy to use now I'm not sure it's worth it.
1258 Note: This will load a font. */
1260 gtk_font_selection_select_best_style(GtkFontSelection *fontsel,
1265 gint row, prop, style, matched;
1266 gint best_matched = -1, best_style = -1, best_row;
1268 #ifdef FONTSEL_DEBUG
1269 g_message("In select_best_style\n");
1271 font = &fontsel_info->font_info[fontsel->font_index];
1272 styles = &fontsel_info->font_styles[font->style_index];
1274 for (row = 0; row < GTK_CLIST(fontsel->font_style_clist)->rows; row++)
1276 style = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_style_clist), row));
1277 /* Skip charset rows. */
1281 /* If we just want the first style, we've got it. */
1290 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1292 if (fontsel->property_values[prop] == styles[style].properties[prop])
1295 if (matched > best_matched)
1297 best_matched = matched;
1302 g_return_if_fail (best_style != -1);
1304 fontsel->style = best_style;
1306 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1307 fontsel->property_values[prop] = styles[fontsel->style].properties[prop];
1309 gtk_clist_select_row(GTK_CLIST(fontsel->font_style_clist), best_row, 0);
1310 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_style_clist), best_row)
1311 != GTK_VISIBILITY_FULL)
1312 gtk_clist_moveto(GTK_CLIST(fontsel->font_style_clist), best_row, -1,
1314 gtk_font_selection_show_available_sizes (fontsel);
1315 gtk_font_selection_select_best_size (fontsel);
1319 /* This is called when a style is selected in the list. */
1321 gtk_font_selection_select_style (GtkWidget *w,
1324 GdkEventButton *bevent,
1327 GtkFontSelection *fontsel;
1328 FontInfo *font_info;
1334 #ifdef FONTSEL_DEBUG
1335 g_message("In select_style\n");
1337 fontsel = GTK_FONT_SELECTION(data);
1338 font_info = fontsel_info->font_info;
1339 font = &font_info[fontsel->font_index];
1340 styles = &fontsel_info->font_styles[font->style_index];
1342 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1343 gtk_widget_grab_focus (w);
1345 /* The style index is stored in the row data, so we just need to copy
1346 the style values into the fontsel and reload the font. */
1347 style = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(fontsel->font_style_clist), row));
1349 /* Don't allow selection of charset rows. */
1352 gtk_clist_unselect_row(GTK_CLIST(fontsel->font_style_clist), row, 0);
1356 gtk_clist_get_text(GTK_CLIST(fontsel->font_style_clist), row, 0, &text);
1357 gtk_entry_set_text(GTK_ENTRY(fontsel->font_style_entry), text);
1359 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1360 fontsel->property_values[prop] = styles[style].properties[prop];
1362 if (fontsel->style == style)
1365 fontsel->style = style;
1366 gtk_font_selection_show_available_sizes (fontsel);
1367 gtk_font_selection_select_best_size (fontsel);
1371 /* This shows all the available sizes in the size clist, according to the
1372 current metric and the current font & style. */
1374 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel)
1377 FontStyle *styles, *style;
1378 const guint16 *standard_sizes;
1379 guint16 *bitmapped_sizes, bitmap_size;
1380 gint nstandard_sizes, nbitmapped_sizes;
1381 gchar buffer[16], *size;
1382 gfloat bitmap_size_float;
1386 #ifdef FONTSEL_DEBUG
1387 g_message("In show_available_sizes\n");
1389 font = &fontsel_info->font_info[fontsel->font_index];
1390 styles = &fontsel_info->font_styles[font->style_index];
1391 style = &styles[fontsel->style];
1393 standard_sizes = font_sizes;
1394 nstandard_sizes = sizeof(font_sizes) / sizeof(font_sizes[0]);
1395 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1397 bitmapped_sizes = &fontsel_info->point_sizes[style->point_sizes_index];
1398 nbitmapped_sizes = style->npoint_sizes;
1402 bitmapped_sizes = &fontsel_info->pixel_sizes[style->pixel_sizes_index];
1403 nbitmapped_sizes = style->npixel_sizes;
1406 /* Only show the standard sizes if a scalable font is available. */
1407 type_filter = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
1408 & fontsel->filters[GTK_FONT_FILTER_USER].font_type;
1410 if (!((style->flags & GTK_FONT_SCALABLE_BITMAP
1411 && type_filter & GTK_FONT_SCALABLE_BITMAP)
1412 || (style->flags & GTK_FONT_SCALABLE
1413 && type_filter & GTK_FONT_SCALABLE)))
1414 nstandard_sizes = 0;
1416 gtk_clist_freeze (GTK_CLIST(fontsel->size_clist));
1417 gtk_clist_clear (GTK_CLIST(fontsel->size_clist));
1419 /* Interleave the standard sizes with the bitmapped sizes so we get a list
1420 of ascending sizes. If the metric is points, we have to convert the
1421 decipoints to points. */
1422 while (nstandard_sizes || nbitmapped_sizes)
1425 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1427 if (*bitmapped_sizes % 10 != 0)
1429 bitmap_size = *bitmapped_sizes / 10;
1430 bitmap_size_float = *bitmapped_sizes / 10;
1434 bitmap_size = *bitmapped_sizes;
1435 bitmap_size_float = *bitmapped_sizes;
1438 if (can_match && nstandard_sizes && nbitmapped_sizes
1439 && *standard_sizes == bitmap_size)
1441 sprintf(buffer, "%i *", *standard_sizes);
1447 else if (nstandard_sizes
1448 && (!nbitmapped_sizes
1449 || (gfloat)*standard_sizes < bitmap_size_float))
1451 sprintf(buffer, "%i", *standard_sizes);
1457 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1459 if (*bitmapped_sizes % 10 == 0)
1460 sprintf(buffer, "%i *", *bitmapped_sizes / 10);
1462 sprintf(buffer, "%i.%i *", *bitmapped_sizes / 10,
1463 *bitmapped_sizes % 10);
1467 sprintf(buffer, "%i *", *bitmapped_sizes);
1473 gtk_clist_append(GTK_CLIST(fontsel->size_clist), &size);
1475 gtk_clist_thaw (GTK_CLIST(fontsel->size_clist));
1479 /* If the user hits return in the font size entry, we change to the new font
1482 gtk_font_selection_size_key_press (GtkWidget *w,
1486 GtkFontSelection *fontsel;
1488 gfloat new_size_float;
1491 #ifdef FONTSEL_DEBUG
1492 g_message("In size_key_press\n");
1494 fontsel = GTK_FONT_SELECTION(data);
1496 if (event->keyval == GDK_Return)
1498 text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1499 if (fontsel->metric == GTK_FONT_METRIC_PIXELS)
1501 new_size = atoi (text);
1507 new_size_float = atof (text) * 10;
1508 new_size = (gint) new_size_float;
1513 /* Remember that this size was set explicitly. */
1514 fontsel->selected_size = new_size;
1516 /* Check if the font size has changed, and return if it hasn't. */
1517 if (fontsel->size == new_size)
1520 fontsel->size = new_size;
1521 gtk_font_selection_select_best_size (fontsel);
1529 /* This tries to select the closest size to the current size, though it
1530 may have to change the size if only unscaled bitmaps are available.
1531 Note: this will load a font. */
1533 gtk_font_selection_select_best_size(GtkFontSelection *fontsel)
1536 FontStyle *styles, *style;
1538 gint row, best_row = 0, size, size_fraction, best_size = 0, nmatched;
1539 gboolean found = FALSE;
1544 #ifdef FONTSEL_DEBUG
1545 g_message("In select_best_size\n");
1547 font = &fontsel_info->font_info[fontsel->font_index];
1548 styles = &fontsel_info->font_styles[font->style_index];
1549 style = &styles[fontsel->style];
1551 /* Find the closest size available in the size clist. If the exact size is
1552 in the list set found to TRUE. */
1553 for (row = 0; row < GTK_CLIST(fontsel->size_clist)->rows; row++)
1555 gtk_clist_get_text(GTK_CLIST(fontsel->size_clist), row, 0, &text);
1556 nmatched = sscanf(text, "%i.%i", &size, &size_fraction);
1557 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1561 size += size_fraction;
1564 if (size == fontsel->selected_size)
1571 else if (best_size == 0
1572 || abs(size - fontsel->selected_size)
1573 < (abs(best_size - fontsel->selected_size)))
1580 /* If we aren't scaling bitmapped fonts and this is a bitmapped font, we
1581 need to use the closest size found. */
1582 type_filter = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
1583 & fontsel->filters[GTK_FONT_FILTER_USER].font_type;
1585 if (!((style->flags & GTK_FONT_SCALABLE_BITMAP
1586 && type_filter & GTK_FONT_SCALABLE_BITMAP)
1587 || (style->flags & GTK_FONT_SCALABLE
1588 && type_filter & GTK_FONT_SCALABLE)))
1593 fontsel->size = best_size;
1594 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), best_row, -1, 0.5, 0);
1595 gtk_clist_select_row(GTK_CLIST(fontsel->size_clist), best_row, 0);
1599 fontsel->size = fontsel->selected_size;
1600 selection = GTK_CLIST(fontsel->size_clist)->selection;
1602 gtk_clist_unselect_row(GTK_CLIST(fontsel->size_clist),
1603 GPOINTER_TO_INT (selection->data), 0);
1604 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), best_row, -1, 0.5, 0);
1606 /* Show the size in the size entry. */
1607 if (fontsel->metric == GTK_FONT_METRIC_PIXELS)
1608 sprintf(buffer, "%i", fontsel->size);
1611 if (fontsel->size % 10 == 0)
1612 sprintf(buffer, "%i", fontsel->size / 10);
1614 sprintf(buffer, "%i.%i", fontsel->size / 10, fontsel->size % 10);
1616 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
1618 gtk_font_selection_load_font (fontsel);
1622 /* This is called when a size is selected in the list. */
1624 gtk_font_selection_select_size (GtkWidget *w,
1627 GdkEventButton *bevent,
1630 GtkFontSelection *fontsel;
1636 #ifdef FONTSEL_DEBUG
1637 g_message("In select_size\n");
1639 fontsel = GTK_FONT_SELECTION(data);
1641 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1642 gtk_widget_grab_focus (w);
1644 /* Copy the size from the clist to the size entry, but without the bitmapped
1646 gtk_clist_get_text(GTK_CLIST(fontsel->size_clist), row, 0, &text);
1648 while (i < 15 && (text[i] == '.' || (text[i] >= '0' && text[i] <= '9')))
1650 buffer[i] = text[i];
1654 gtk_entry_set_text(GTK_ENTRY(fontsel->size_entry), buffer);
1656 /* Check if the font size has changed, and return if it hasn't. */
1657 new_size = atoi(text);
1658 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1661 if (fontsel->size == new_size)
1664 /* If the size was selected by the user we set the selected_size. */
1665 fontsel->selected_size = new_size;
1667 fontsel->size = new_size;
1668 gtk_font_selection_load_font (fontsel);
1672 /* This is called when the pixels or points radio buttons are pressed. */
1674 gtk_font_selection_metric_callback (GtkWidget *w,
1677 GtkFontSelection *fontsel = GTK_FONT_SELECTION(data);
1679 #ifdef FONTSEL_DEBUG
1680 g_message("In metric_callback\n");
1682 if (GTK_TOGGLE_BUTTON(fontsel->pixels_button)->active)
1684 if (fontsel->metric == GTK_FONT_METRIC_PIXELS)
1686 fontsel->metric = GTK_FONT_METRIC_PIXELS;
1687 fontsel->size = (fontsel->size + 5) / 10;
1688 fontsel->selected_size = (fontsel->selected_size + 5) / 10;
1692 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1694 fontsel->metric = GTK_FONT_METRIC_POINTS;
1695 fontsel->size *= 10;
1696 fontsel->selected_size *= 10;
1698 if (fontsel->font_index != -1)
1700 gtk_font_selection_show_available_sizes (fontsel);
1701 gtk_font_selection_select_best_size (fontsel);
1706 /* This searches the given property table and returns the index of the given
1707 string, or 0, which is the wildcard '*' index, if it's not found. */
1709 gtk_font_selection_field_to_index (gchar **table,
1715 for (i = 0; i < ntable; i++)
1716 if (strcmp (field, table[i]) == 0)
1724 /* This attempts to load the current font, and returns TRUE if it succeeds. */
1726 gtk_font_selection_load_font (GtkFontSelection *fontsel)
1729 gchar *fontname, *label_text;
1732 gdk_font_unref (fontsel->font);
1733 fontsel->font = NULL;
1735 /* If no family has been selected yet, just return FALSE. */
1736 if (fontsel->font_index == -1)
1739 fontname = gtk_font_selection_get_font_name (fontsel);
1742 #ifdef FONTSEL_DEBUG
1743 g_message("Loading: %s\n", fontname);
1745 font = gdk_font_load (fontname);
1750 fontsel->font = font;
1751 /* Make sure the message label is empty, but don't change it unless
1752 it's necessary as it results in a resize of the whole window! */
1753 gtk_label_get(GTK_LABEL(fontsel->message_label), &label_text);
1754 if (strcmp(label_text, ""))
1755 gtk_label_set_text(GTK_LABEL(fontsel->message_label), "");
1756 gtk_font_selection_update_preview (fontsel);
1761 gtk_label_set_text(GTK_LABEL(fontsel->message_label),
1762 "The selected font is not available.");
1767 gtk_label_set_text(GTK_LABEL(fontsel->message_label),
1768 "The selected font is not a valid font.");
1775 /* This sets the font in the preview entry to the selected font, and tries to
1776 make sure that the preview entry is a reasonable size, i.e. so that the
1777 text can be seen with a bit of space to spare. But it tries to avoid
1778 resizing the entry every time the font changes.
1779 This also used to shrink the preview if the font size was decreased, but
1780 that made it awkward if the user wanted to resize the window themself. */
1782 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1784 GtkWidget *preview_entry;
1786 gint text_height, new_height;
1790 #ifdef FONTSEL_DEBUG
1791 g_message("In update_preview\n");
1793 style = gtk_style_new ();
1794 gdk_font_unref (style->font);
1795 style->font = fontsel->font;
1796 gdk_font_ref (style->font);
1798 preview_entry = fontsel->preview_entry;
1799 gtk_widget_set_style (preview_entry, style);
1800 gtk_style_unref(style);
1802 text_height = preview_entry->style->font->ascent
1803 + preview_entry->style->font->descent;
1804 /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1805 new_height = text_height + 20;
1806 if (new_height < INITIAL_PREVIEW_HEIGHT)
1807 new_height = INITIAL_PREVIEW_HEIGHT;
1808 if (new_height > MAX_PREVIEW_HEIGHT)
1809 new_height = MAX_PREVIEW_HEIGHT;
1811 if ((preview_entry->requisition.height < text_height + 10)
1812 || (preview_entry->requisition.height > text_height + 40))
1813 gtk_widget_set_usize(preview_entry, -1, new_height);
1815 /* This sets the preview text, if it hasn't been set already. */
1816 text = gtk_entry_get_text(GTK_ENTRY(fontsel->preview_entry));
1817 if (strlen(text) == 0)
1818 gtk_entry_set_text(GTK_ENTRY(fontsel->preview_entry), PREVIEW_TEXT);
1819 gtk_entry_set_position(GTK_ENTRY(fontsel->preview_entry), 0);
1821 /* If this is a 2-byte font display a message to say it may not be
1822 displayed properly. */
1823 xfs = GDK_FONT_XFONT(fontsel->font);
1824 if (xfs->min_byte1 != 0 || xfs->max_byte1 != 0)
1825 gtk_label_set_text(GTK_LABEL(fontsel->message_label),
1826 "This is a 2-byte font and may not be displayed correctly.");
1831 gtk_font_selection_switch_page (GtkWidget *w,
1832 GtkNotebookPage *page,
1836 GtkFontSelection *fontsel = GTK_FONT_SELECTION(data);
1838 /* This function strangely gets called when the window is destroyed,
1839 so we check here to see if the notebook is visible. */
1840 if (!GTK_WIDGET_VISIBLE(w))
1844 gtk_font_selection_update_filter(fontsel);
1845 else if (page_num == 1)
1846 gtk_font_selection_show_font_info(fontsel);
1851 gtk_font_selection_show_font_info (GtkFontSelection *fontsel)
1853 Atom font_atom, atom;
1857 gchar field_buffer[XLFD_MAX_FIELD_LEN];
1860 gboolean shown_actual_fields = FALSE;
1862 fontname = gtk_font_selection_get_font_name(fontsel);
1863 gtk_entry_set_text(GTK_ENTRY(fontsel->requested_font_name),
1864 fontname ? fontname : "");
1866 gtk_clist_freeze (GTK_CLIST(fontsel->info_clist));
1867 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1870 field = gtk_font_selection_get_xlfd_field (fontname, i, field_buffer);
1875 if (i == XLFD_SLANT)
1876 field = gtk_font_selection_expand_slant_code(field);
1877 else if (i == XLFD_SPACING)
1878 field = gtk_font_selection_expand_spacing_code(field);
1880 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 1,
1881 field ? field : "");
1886 font_atom = XInternAtom(GDK_DISPLAY(), "FONT", True);
1887 if (font_atom != None)
1889 status = XGetFontProperty(GDK_FONT_XFONT(fontsel->font), font_atom,
1893 name = XGetAtomName(GDK_DISPLAY(), atom);
1894 gtk_entry_set_text(GTK_ENTRY(fontsel->actual_font_name), name);
1896 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1898 field = gtk_font_selection_get_xlfd_field (name, i,
1900 if (i == XLFD_SLANT)
1901 field = gtk_font_selection_expand_slant_code(field);
1902 else if (i == XLFD_SPACING)
1903 field = gtk_font_selection_expand_spacing_code(field);
1904 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 2,
1905 field ? field : "");
1907 shown_actual_fields = TRUE;
1912 if (!shown_actual_fields)
1914 gtk_entry_set_text(GTK_ENTRY(fontsel->actual_font_name), "");
1915 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1917 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 2,
1918 fontname ? "(unknown)" : "");
1921 gtk_clist_thaw (GTK_CLIST(fontsel->info_clist));
1927 gtk_font_selection_expand_slant_code(gchar *slant)
1929 if (!g_strcasecmp(slant, "r")) return("roman");
1930 else if (!g_strcasecmp(slant, "i")) return("italic");
1931 else if (!g_strcasecmp(slant, "o")) return("oblique");
1932 else if (!g_strcasecmp(slant, "ri")) return("reverse italic");
1933 else if (!g_strcasecmp(slant, "ro")) return("reverse oblique");
1934 else if (!g_strcasecmp(slant, "ot")) return("other");
1939 gtk_font_selection_expand_spacing_code(gchar *spacing)
1941 if (!g_strcasecmp(spacing, "p")) return("proportional");
1942 else if (!g_strcasecmp(spacing, "m")) return("monospaced");
1943 else if (!g_strcasecmp(spacing, "c")) return("char cell");
1948 /*****************************************************************************
1949 * These functions all deal with the Filter page and filtering the fonts.
1950 *****************************************************************************/
1952 /* This is called when an item is selected in one of the filter clists.
1953 We make sure that the first row of the clist, i.e. the wildcard '*', is
1954 selected if and only if none of the other items are selected.
1955 Also doesn't allow selections of values filtered out by base filter.
1956 We may need to be careful about triggering other signals. */
1958 gtk_font_selection_select_filter (GtkWidget *w,
1961 GdkEventButton *bevent,
1962 GtkFontSelection *fontsel)
1964 gint i, prop, index;
1968 for (i = 1; i < GTK_CLIST(w)->rows; i++)
1969 gtk_clist_unselect_row(GTK_CLIST(w), i, 0);
1973 /* Find out which property this is. */
1974 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
1975 if (fontsel->filter_clists[prop] == w)
1977 index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(w), row));
1978 if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_BASE,
1979 prop, index) == NOT_FILTERED)
1980 gtk_clist_unselect_row(GTK_CLIST(w), row, 0);
1982 gtk_clist_unselect_row(GTK_CLIST(w), 0, 0);
1987 /* Here a filter item is being deselected. If there are now no items selected
1988 we select the first '*' item, unless that it is the item being deselected,
1989 in which case we select all of the other items. This makes it easy to
1990 select all items in the list except one or two. */
1992 gtk_font_selection_unselect_filter (GtkWidget *w,
1995 GdkEventButton *bevent,
1996 GtkFontSelection *fontsel)
1998 gint i, prop, index;
2000 if (!GTK_CLIST(w)->selection)
2004 /* Find out which property this is. */
2005 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2006 if (fontsel->filter_clists[prop] == w)
2009 for (i = 1; i < GTK_CLIST(w)->rows; i++)
2011 index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(w),
2013 if (gtk_font_selection_filter_state (fontsel,
2014 GTK_FONT_FILTER_BASE,
2017 gtk_clist_select_row(GTK_CLIST(w), i, 0);
2022 gtk_clist_select_row(GTK_CLIST(w), 0, 0);
2028 /* This is called when the main notebook page is selected. It checks if the
2029 filter has changed, an if so it creates the filter settings, and filters the
2030 fonts shown. If an empty filter (all '*'s) is applied, then filtering is
2033 gtk_font_selection_update_filter (GtkFontSelection *fontsel)
2037 gboolean default_filter = TRUE, filter_changed = FALSE;
2038 gint prop, nselected, i, row, index;
2039 GtkFontFilter *filter = &fontsel->filters[GTK_FONT_FILTER_USER];
2040 gint base_font_type, user_font_type, new_font_type;
2042 #ifdef FONTSEL_DEBUG
2043 g_message("In update_filter\n");
2046 /* Check if the user filter has changed, and also if it is the default
2047 filter, i.e. bitmap & scalable fonts and all '*'s selected.
2048 We only look at the bits which are not already filtered out by the base
2049 filter, since that overrides the user filter. */
2050 base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
2052 user_font_type = fontsel->filters[GTK_FONT_FILTER_USER].font_type
2054 new_font_type = GTK_TOGGLE_BUTTON(fontsel->type_bitmaps_button)->active
2055 ? GTK_FONT_BITMAP : 0;
2056 new_font_type |= (GTK_TOGGLE_BUTTON(fontsel->type_scalable_button)->active
2057 ? GTK_FONT_SCALABLE : 0);
2058 new_font_type |= (GTK_TOGGLE_BUTTON(fontsel->type_scaled_bitmaps_button)->active ? GTK_FONT_SCALABLE_BITMAP : 0);
2059 new_font_type &= base_font_type;
2060 new_font_type |= (~base_font_type & user_font_type);
2061 if (new_font_type != (GTK_FONT_BITMAP | GTK_FONT_SCALABLE))
2062 default_filter = FALSE;
2064 if (new_font_type != user_font_type)
2065 filter_changed = TRUE;
2066 fontsel->filters[GTK_FONT_FILTER_USER].font_type = new_font_type;
2068 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2070 clist = fontsel->filter_clists[prop];
2071 selection = GTK_CLIST(clist)->selection;
2072 nselected = g_list_length(selection);
2073 if (nselected != 1 || GPOINTER_TO_INT (selection->data) != 0)
2075 default_filter = FALSE;
2077 if (filter->property_nfilters[prop] != nselected)
2078 filter_changed = TRUE;
2081 for (i = 0; i < nselected; i++)
2083 row = GPOINTER_TO_INT (selection->data);
2084 index = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (clist), row));
2085 if (filter->property_filters[prop][i] != index)
2086 filter_changed = TRUE;
2087 selection = selection->next;
2093 if (filter->property_nfilters[prop] != 0)
2094 filter_changed = TRUE;
2098 /* If the filter hasn't changed we just return. */
2099 if (!filter_changed)
2102 #ifdef FONTSEL_DEBUG
2103 g_message(" update_fonts: filter has changed\n");
2106 /* Free the old filter data and create the new arrays. */
2107 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2109 g_free(filter->property_filters[prop]);
2111 clist = fontsel->filter_clists[prop];
2112 selection = GTK_CLIST(clist)->selection;
2113 nselected = g_list_length(selection);
2114 if (nselected == 1 && GPOINTER_TO_INT (selection->data) == 0)
2116 filter->property_filters[prop] = NULL;
2117 filter->property_nfilters[prop] = 0;
2121 filter->property_filters[prop] = g_new(guint16, nselected);
2122 filter->property_nfilters[prop] = nselected;
2123 for (i = 0; i < nselected; i++)
2125 row = GPOINTER_TO_INT (selection->data);
2126 index = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (clist), row));
2127 filter->property_filters[prop][i] = index;
2128 selection = selection->next;
2133 /* Set the 'Reset Filter' button sensitive if a filter is in effect, and
2134 also set the label above the font list to show this as well. */
2137 gtk_widget_set_sensitive(fontsel->filter_button, FALSE);
2138 gtk_label_set_text(GTK_LABEL(fontsel->font_label), "Font:");
2142 gtk_widget_set_sensitive(fontsel->filter_button, TRUE);
2143 gtk_label_set_text(GTK_LABEL(fontsel->font_label), "Font: (Filter Applied)");
2145 gtk_font_selection_show_available_fonts(fontsel);
2149 /* This shows all the available fonts in the font clist. */
2151 gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
2153 FontInfo *font_info, *font;
2154 GtkFontFilter *filter;
2155 gint nfonts, i, j, k, row, style, font_row = -1;
2156 gchar font_buffer[XLFD_MAX_FIELD_LEN * 2 + 4];
2158 gboolean matched, matched_style;
2160 #ifdef FONTSEL_DEBUG
2161 g_message("In show_available_fonts\n");
2163 font_info = fontsel_info->font_info;
2164 nfonts = fontsel_info->nfonts;
2166 /* Filter the list of fonts. */
2167 gtk_clist_freeze (GTK_CLIST(fontsel->font_clist));
2168 gtk_clist_clear (GTK_CLIST(fontsel->font_clist));
2169 for (i = 0; i < nfonts; i++)
2171 font = &font_info[i];
2173 /* Check if the foundry passes through all filters. */
2175 for (k = 0; k < GTK_NUM_FONT_FILTERS; k++)
2177 filter = &fontsel->filters[k];
2179 if (filter->property_nfilters[FOUNDRY] != 0)
2182 for (j = 0; j < filter->property_nfilters[FOUNDRY]; j++)
2184 if (font->foundry == filter->property_filters[FOUNDRY][j])
2199 /* Now check if the other properties are matched in at least one style.*/
2200 matched_style = FALSE;
2201 for (style = 0; style < font->nstyles; style++)
2203 if (gtk_font_selection_style_visible(fontsel, font, style))
2205 matched_style = TRUE;
2212 /* Insert the font in the clist. */
2213 if ((i > 0 && font->family == font_info[i-1].family)
2214 || (i < nfonts - 1 && font->family == font_info[i+1].family))
2216 sprintf(font_buffer, "%s (%s)", font->family,
2217 fontsel_info->properties[FOUNDRY][font->foundry]);
2218 font_item = font_buffer;
2219 row = gtk_clist_append(GTK_CLIST(fontsel->font_clist), &font_item);
2223 row = gtk_clist_append(GTK_CLIST(fontsel->font_clist),
2226 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_clist), row,
2227 GINT_TO_POINTER (i));
2228 if (fontsel->font_index == i)
2231 gtk_clist_thaw (GTK_CLIST(fontsel->font_clist));
2233 /* If the currently-selected font isn't in the new list, reset the
2237 fontsel->font_index = -1;
2239 gdk_font_unref(fontsel->font);
2240 fontsel->font = NULL;
2241 gtk_entry_set_text(GTK_ENTRY(fontsel->font_entry), "");
2242 gtk_clist_clear (GTK_CLIST(fontsel->font_style_clist));
2243 gtk_entry_set_text(GTK_ENTRY(fontsel->font_style_entry), "");
2247 gtk_clist_select_row(GTK_CLIST(fontsel->font_clist), font_row, 0);
2248 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_clist), font_row)
2249 != GTK_VISIBILITY_FULL)
2250 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), font_row, -1, 0.5, 0);
2252 gtk_font_selection_show_available_styles (fontsel);
2253 gtk_font_selection_select_best_style (fontsel, FALSE);
2257 /* Returns TRUE if the style is not currently filtered out. */
2259 gtk_font_selection_style_visible(GtkFontSelection *fontsel,
2263 FontStyle *styles, *style;
2264 GtkFontFilter *filter;
2270 styles = &fontsel_info->font_styles[font->style_index];
2271 style = &styles[style_index];
2273 /* Check if font_type of style is filtered. */
2274 type_filter = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
2275 & fontsel->filters[GTK_FONT_FILTER_USER].font_type;
2276 if (!(style->flags & type_filter))
2279 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2281 value = style->properties[prop];
2283 /* Check each filter. */
2284 for (i = 0; i < GTK_NUM_FONT_FILTERS; i++)
2286 filter = &fontsel->filters[i];
2288 if (filter->property_nfilters[prop] != 0)
2291 for (j = 0; j < filter->property_nfilters[prop]; j++)
2293 if (value == filter->property_filters[prop][j])
2308 /* This resets the font type to bitmap or scalable, and sets all the filter
2309 clists to the wildcard '*' options. */
2311 gtk_font_selection_reset_filter (GtkWidget *w,
2312 GtkFontSelection *fontsel)
2314 gint prop, base_font_type;
2316 fontsel->filters[GTK_FONT_FILTER_USER].font_type = GTK_FONT_BITMAP
2317 | GTK_FONT_SCALABLE;
2319 base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type;
2320 if (base_font_type & GTK_FONT_BITMAP)
2321 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), TRUE);
2322 if (base_font_type & GTK_FONT_SCALABLE)
2323 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), TRUE);
2324 if (base_font_type & GTK_FONT_SCALABLE_BITMAP)
2325 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), FALSE);
2327 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2328 gtk_clist_select_row(GTK_CLIST(fontsel->filter_clists[prop]), 0, 0);
2332 /* This clears the filter, showing all fonts and styles again. */
2334 gtk_font_selection_on_clear_filter (GtkWidget *w,
2335 GtkFontSelection *fontsel)
2337 gtk_font_selection_clear_filter(fontsel);
2341 /* This resets the user filter, showing all fonts and styles which pass the
2342 base filter again. Note that the font type is set to bitmaps and scalable
2343 fonts - scaled bitmaps are not shown. */
2345 gtk_font_selection_clear_filter (GtkFontSelection *fontsel)
2347 GtkFontFilter *filter;
2350 #ifdef FONTSEL_DEBUG
2351 g_message("In clear_filter\n");
2353 /* Clear the filter data. */
2354 filter = &fontsel->filters[GTK_FONT_FILTER_USER];
2355 filter->font_type = GTK_FONT_BITMAP | GTK_FONT_SCALABLE;
2356 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2358 g_free(filter->property_filters[prop]);
2359 filter->property_filters[prop] = NULL;
2360 filter->property_nfilters[prop] = 0;
2363 /* Select all the '*'s on the filter page. */
2364 gtk_font_selection_reset_filter(NULL, fontsel);
2366 /* Update the main notebook page. */
2367 gtk_widget_set_sensitive(fontsel->filter_button, FALSE);
2368 gtk_label_set_text(GTK_LABEL(fontsel->font_label), "Font:");
2370 gtk_font_selection_show_available_fonts(fontsel);
2375 gtk_font_selection_set_filter (GtkFontSelection *fontsel,
2376 GtkFontFilterType filter_type,
2377 GtkFontType font_type,
2385 GtkFontFilter *filter;
2386 gchar **filter_strings [GTK_NUM_FONT_PROPERTIES];
2387 gchar *filter_string;
2388 gchar *property, *property_alt;
2389 gint prop, nfilters, i, j, num_found;
2390 gint base_font_type, user_font_type;
2391 gboolean filter_set;
2393 /* Put them into an array so we can use a simple loop. */
2394 filter_strings[FOUNDRY] = foundries;
2395 filter_strings[WEIGHT] = weights;
2396 filter_strings[SLANT] = slants;
2397 filter_strings[SET_WIDTH] = setwidths;
2398 filter_strings[SPACING] = spacings;
2399 filter_strings[CHARSET] = charsets;
2401 filter = &fontsel->filters[filter_type];
2402 filter->font_type = font_type;
2404 /* Free the old filter data, and insert the new. */
2405 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2407 g_free(filter->property_filters[prop]);
2408 filter->property_filters[prop] = NULL;
2409 filter->property_nfilters[prop] = 0;
2411 if (filter_strings[prop])
2413 /* Count how many items in the new array. */
2415 while (filter_strings[prop][nfilters])
2418 filter->property_filters[prop] = g_new(guint16, nfilters);
2419 filter->property_nfilters[prop] = 0;
2421 /* Now convert the strings to property indices. */
2423 for (i = 0; i < nfilters; i++)
2425 filter_string = filter_strings[prop][i];
2426 for (j = 0; j < fontsel_info->nproperties[prop]; j++)
2428 property = fontsel_info->properties[prop][j];
2429 property_alt = NULL;
2431 property_alt = gtk_font_selection_expand_slant_code(property);
2432 else if (prop == SPACING)
2433 property_alt = gtk_font_selection_expand_spacing_code(property);
2434 if (!strcmp (filter_string, property)
2435 || (property_alt && !strcmp (filter_string, property_alt)))
2437 filter->property_filters[prop][num_found] = j;
2443 filter->property_nfilters[prop] = num_found;
2447 /* Now set the clists on the filter page according to the new filter. */
2448 gtk_font_selection_update_filter_lists (fontsel);
2450 if (filter_type == GTK_FONT_FILTER_BASE)
2452 user_font_type = fontsel->filters[GTK_FONT_FILTER_USER].font_type;
2453 if (font_type & GTK_FONT_BITMAP)
2455 gtk_widget_set_sensitive (fontsel->type_bitmaps_button, TRUE);
2456 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), user_font_type & GTK_FONT_BITMAP);
2460 gtk_widget_set_sensitive (fontsel->type_bitmaps_button, FALSE);
2461 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), FALSE);
2464 if (font_type & GTK_FONT_SCALABLE)
2466 gtk_widget_set_sensitive (fontsel->type_scalable_button, TRUE);
2467 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), user_font_type & GTK_FONT_SCALABLE);
2471 gtk_widget_set_sensitive (fontsel->type_scalable_button, FALSE);
2472 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), FALSE);
2475 if (font_type & GTK_FONT_SCALABLE_BITMAP)
2477 gtk_widget_set_sensitive (fontsel->type_scaled_bitmaps_button, TRUE);
2478 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), user_font_type & GTK_FONT_SCALABLE_BITMAP);
2482 gtk_widget_set_sensitive (fontsel->type_scaled_bitmaps_button, FALSE);
2483 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), FALSE);
2488 base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type;
2489 if (base_font_type & GTK_FONT_BITMAP)
2490 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), font_type & GTK_FONT_BITMAP);
2492 if (base_font_type & GTK_FONT_SCALABLE)
2493 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), font_type & GTK_FONT_SCALABLE);
2495 if (base_font_type & GTK_FONT_SCALABLE_BITMAP)
2496 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), font_type & GTK_FONT_SCALABLE_BITMAP);
2498 /* If the user filter is not the default, make the 'Reset Filter' button
2501 if (font_type != (GTK_FONT_BITMAP | GTK_FONT_SCALABLE))
2503 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2505 if (filter->property_nfilters[prop] != 0)
2509 gtk_widget_set_sensitive (fontsel->filter_button, TRUE);
2512 gtk_font_selection_show_available_fonts (fontsel);
2516 /* This sets the colour of each property in the filter clists according to
2517 the base filter. i.e. Filtered properties are shown as insensitive. */
2519 gtk_font_selection_update_filter_lists (GtkFontSelection *fontsel)
2522 GdkColor *inactive_fg, *inactive_bg, *fg, *bg;
2523 gint prop, row, index;
2525 /* We have to make sure the clist is realized to use the colours. */
2526 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2528 clist = fontsel->filter_clists[prop];
2529 gtk_widget_realize (clist);
2530 inactive_fg = &clist->style->fg[GTK_STATE_INSENSITIVE];
2531 inactive_bg = &clist->style->bg[GTK_STATE_INSENSITIVE];
2532 for (row = 1; row < GTK_CLIST(clist)->rows; row++)
2534 index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(clist),
2536 /* Set the colour according to the base filter. */
2537 if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_BASE,
2538 prop, index) == NOT_FILTERED)
2548 gtk_clist_set_foreground(GTK_CLIST(clist), row, fg);
2549 gtk_clist_set_background(GTK_CLIST(clist), row, bg);
2551 /* Set the selection state according to the user filter. */
2552 if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_USER,
2553 prop, index) == FILTERED
2555 gtk_clist_select_row (GTK_CLIST (clist), row, 0);
2557 gtk_clist_unselect_row (GTK_CLIST (clist), row, 0);
2563 /* Returns whether a property value is in the filter or not, or if the
2564 property has no filter set. */
2565 static GtkFontPropertyFilterState
2566 gtk_font_selection_filter_state (GtkFontSelection *fontsel,
2567 GtkFontFilterType filter_type,
2571 GtkFontFilter *filter;
2574 filter = &fontsel->filters[filter_type];
2575 if (filter->property_nfilters[property] == 0)
2578 for (i = 0; i < filter->property_nfilters[property]; i++)
2580 if (filter->property_filters[property][i] == index)
2583 return NOT_FILTERED;
2587 /*****************************************************************************
2588 * These functions all deal with creating the main class arrays containing
2589 * the data about all available fonts.
2590 *****************************************************************************/
2592 gtk_font_selection_get_fonts (void)
2599 gint i, prop, style, size;
2600 gint npixel_sizes = 0, npoint_sizes = 0;
2602 FontStyle *current_style, *prev_style, *tmp_style;
2603 gboolean matched_style, found_size;
2604 gint pixels, points, res_x, res_y;
2605 gchar field_buffer[XLFD_MAX_FIELD_LEN];
2608 guint16 *pixel_sizes, *point_sizes, *tmp_sizes;
2610 fontsel_info = g_new (GtkFontSelInfo, 1);
2612 /* Get a maximum of MAX_FONTS fontnames from the X server.
2613 Use "-*" as the pattern rather than "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" since
2614 the latter may result in fonts being returned which don't actually exist.
2615 xlsfonts also uses "*" so I think it's OK. "-*" gets rid of aliases. */
2616 xfontnames = XListFonts (GDK_DISPLAY(), "-*", MAX_FONTS, &num_fonts);
2617 /* Output a warning if we actually get MAX_FONTS fonts. */
2618 if (num_fonts == MAX_FONTS)
2619 g_warning("MAX_FONTS exceeded. Some fonts may be missing.");
2621 /* The maximum size of all these tables is the number of font names
2622 returned. We realloc them later when we know exactly how many
2623 unique entries there are. */
2624 fontsel_info->font_info = g_new (FontInfo, num_fonts);
2625 fontsel_info->font_styles = g_new (FontStyle, num_fonts);
2626 fontsel_info->pixel_sizes = g_new (guint16, num_fonts);
2627 fontsel_info->point_sizes = g_new (guint16, num_fonts);
2629 fontnames = g_new (GSList*, num_fonts);
2631 /* Create the initial arrays for the property value strings, though they
2632 may be realloc'ed later. Put the wildcard '*' in the first elements. */
2633 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2635 fontsel_info->properties[prop] = g_new(gchar*, PROPERTY_ARRAY_INCREMENT);
2636 fontsel_info->space_allocated[prop] = PROPERTY_ARRAY_INCREMENT;
2637 fontsel_info->nproperties[prop] = 1;
2638 fontsel_info->properties[prop][0] = "*";
2642 /* Insert the font families into the main table, sorted by family and
2643 foundry (fonts with different foundries are placed in seaparate FontInfos.
2644 All fontnames in each family + foundry are placed into the fontnames
2646 fontsel_info->nfonts = 0;
2647 for (i = 0; i < num_fonts; i++)
2649 #ifdef FONTSEL_DEBUG
2650 g_message("%s\n", xfontnames[i]);
2652 if (gtk_font_selection_is_xlfd_font_name (xfontnames[i]))
2653 gtk_font_selection_insert_font (fontnames, &fontsel_info->nfonts, xfontnames[i]);
2656 #ifdef FONTSEL_DEBUG
2657 g_warning("Skipping invalid font: %s", xfontnames[i]);
2663 /* Since many font names will be in the same FontInfo not all of the
2664 allocated FontInfo table will be used, so we will now reallocate it
2665 with the real size. */
2666 fontsel_info->font_info = g_realloc(fontsel_info->font_info,
2667 sizeof(FontInfo) * fontsel_info->nfonts);
2670 /* Now we work out which choices of weight/slant etc. are valid for each
2672 fontsel_info->nstyles = 0;
2673 current_style = fontsel_info->font_styles;
2674 for (i = 0; i < fontsel_info->nfonts; i++)
2676 font = &fontsel_info->font_info[i];
2678 /* Use the next free position in the styles array. */
2679 font->style_index = fontsel_info->nstyles;
2681 /* Now step through each of the fontnames with this family, and create
2682 a style for each fontname. Each style contains the index into the
2683 weights/slants etc. arrays, and a number of pixel/point sizes. */
2685 temp_list = fontnames[i];
2688 fontname = temp_list->data;
2689 temp_list = temp_list->next;
2691 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2693 current_style->properties[prop]
2694 = gtk_font_selection_insert_field (fontname, prop);
2696 current_style->pixel_sizes_index = npixel_sizes;
2697 current_style->npixel_sizes = 0;
2698 current_style->point_sizes_index = npoint_sizes;
2699 current_style->npoint_sizes = 0;
2700 current_style->flags = 0;
2703 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_PIXELS,
2705 pixels = atoi(field);
2707 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_POINTS,
2709 points = atoi(field);
2711 field = gtk_font_selection_get_xlfd_field (fontname,
2714 res_x = atoi(field);
2716 field = gtk_font_selection_get_xlfd_field (fontname,
2719 res_y = atoi(field);
2721 if (pixels == 0 && points == 0)
2723 if (res_x == 0 && res_y == 0)
2724 flags = GTK_FONT_SCALABLE;
2726 flags = GTK_FONT_SCALABLE_BITMAP;
2729 flags = GTK_FONT_BITMAP;
2731 /* Now we check to make sure that the style is unique. If it isn't
2733 prev_style = fontsel_info->font_styles + font->style_index;
2734 matched_style = FALSE;
2735 while (prev_style < current_style)
2737 matched_style = TRUE;
2738 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2740 if (prev_style->properties[prop]
2741 != current_style->properties[prop])
2743 matched_style = FALSE;
2752 /* If we matched an existing style, we need to add the pixels &
2753 point sizes to the style. If not, we insert the pixel & point
2754 sizes into our new style. Note that we don't add sizes for
2758 prev_style->flags |= flags;
2759 if (flags == GTK_FONT_BITMAP)
2761 pixel_sizes = fontsel_info->pixel_sizes
2762 + prev_style->pixel_sizes_index;
2764 for (size = 0; size < prev_style->npixel_sizes; size++)
2766 if (pixels == *pixel_sizes)
2771 else if (pixels < *pixel_sizes)
2775 /* We need to move all the following pixel sizes up, and also
2776 update the indexes of any following styles. */
2779 for (tmp_sizes = fontsel_info->pixel_sizes + npixel_sizes;
2780 tmp_sizes > pixel_sizes; tmp_sizes--)
2781 *tmp_sizes = *(tmp_sizes - 1);
2783 *pixel_sizes = pixels;
2785 prev_style->npixel_sizes++;
2787 tmp_style = prev_style + 1;
2788 while (tmp_style < current_style)
2790 tmp_style->pixel_sizes_index++;
2795 point_sizes = fontsel_info->point_sizes
2796 + prev_style->point_sizes_index;
2798 for (size = 0; size < prev_style->npoint_sizes; size++)
2800 if (points == *point_sizes)
2805 else if (points < *point_sizes)
2809 /* We need to move all the following point sizes up, and also
2810 update the indexes of any following styles. */
2813 for (tmp_sizes = fontsel_info->point_sizes + npoint_sizes;
2814 tmp_sizes > point_sizes; tmp_sizes--)
2815 *tmp_sizes = *(tmp_sizes - 1);
2817 *point_sizes = points;
2819 prev_style->npoint_sizes++;
2821 tmp_style = prev_style + 1;
2822 while (tmp_style < current_style)
2824 tmp_style->point_sizes_index++;
2832 current_style->flags = flags;
2833 if (flags == GTK_FONT_BITMAP)
2835 fontsel_info->pixel_sizes[npixel_sizes++] = pixels;
2836 current_style->npixel_sizes = 1;
2837 fontsel_info->point_sizes[npoint_sizes++] = points;
2838 current_style->npoint_sizes = 1;
2841 fontsel_info->nstyles++;
2845 g_slist_free(fontnames[i]);
2847 /* Set nstyles to the real value, minus duplicated fontnames.
2848 Note that we aren't using all the allocated memory if fontnames are
2850 font->nstyles = style;
2853 /* Since some repeated styles may be skipped we won't have used all the
2854 allocated space, so we will now reallocate it with the real size. */
2855 fontsel_info->font_styles = g_realloc(fontsel_info->font_styles,
2856 sizeof(FontStyle) * fontsel_info->nstyles);
2857 fontsel_info->pixel_sizes = g_realloc(fontsel_info->pixel_sizes,
2858 sizeof(guint16) * npixel_sizes);
2859 fontsel_info->point_sizes = g_realloc(fontsel_info->point_sizes,
2860 sizeof(guint16) * npoint_sizes);
2862 XFreeFontNames (xfontnames);
2865 /* Debugging Output */
2866 /* This outputs all FontInfos. */
2867 #ifdef FONTSEL_DEBUG
2868 g_message("\n\n Font Family Weight Slant Set Width Spacing Charset\n\n");
2869 for (i = 0; i < fontsel_info->nfonts; i++)
2871 FontInfo *font = &fontsel_info->font_info[i];
2872 FontStyle *styles = fontsel_info->font_styles + font->style_index;
2873 for (style = 0; style < font->nstyles; style++)
2875 g_message("%5i %-16.16s ", i, font->family);
2876 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2877 g_message("%-9.9s ",
2878 fontsel_info->properties[prop][styles->properties[prop]]);
2881 if (styles->flags & GTK_FONT_BITMAP)
2882 g_message("Bitmapped font ");
2883 if (styles->flags & GTK_FONT_SCALABLE)
2884 g_message("Scalable font ");
2885 if (styles->flags & GTK_FONT_SCALABLE_BITMAP)
2886 g_message("Scalable-Bitmapped font ");
2889 if (styles->npixel_sizes)
2891 g_message(" Pixel sizes: ");
2892 tmp_sizes = fontsel_info->pixel_sizes + styles->pixel_sizes_index;
2893 for (size = 0; size < styles->npixel_sizes; size++)
2894 g_message("%i ", *tmp_sizes++);
2898 if (styles->npoint_sizes)
2900 g_message(" Point sizes: ");
2901 tmp_sizes = fontsel_info->point_sizes + styles->point_sizes_index;
2902 for (size = 0; size < styles->npoint_sizes; size++)
2903 g_message("%i ", *tmp_sizes++);
2911 /* This outputs all available properties. */
2912 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2914 g_message("Property: %s\n", xlfd_field_names[xlfd_index[prop]]);
2915 for (i = 0; i < fontsel_info->nproperties[prop]; i++)
2916 g_message(" %s\n", fontsel_info->properties[prop][i]);
2921 /* This inserts the given fontname into the FontInfo table.
2922 If a FontInfo already exists with the same family and foundry, then the
2923 fontname is added to the FontInfos list of fontnames, else a new FontInfo
2924 is created and inserted in alphabetical order in the table. */
2926 gtk_font_selection_insert_font (GSList *fontnames[],
2932 GSList *temp_fontname;
2934 gboolean family_exists = FALSE;
2938 gchar family_buffer[XLFD_MAX_FIELD_LEN];
2940 table = fontsel_info->font_info;
2942 /* insert a fontname into a table */
2943 family = gtk_font_selection_get_xlfd_field (fontname, XLFD_FAMILY,
2948 foundry = gtk_font_selection_insert_field (fontname, FOUNDRY);
2953 /* Do a binary search to determine if we have already encountered
2954 * a font with this family & foundry. */
2956 while (lower < upper)
2958 middle = (lower + upper) >> 1;
2960 cmp = strcmp (family, table[middle].family);
2961 /* If the family matches we sort by the foundry. */
2964 family_exists = TRUE;
2965 family = table[middle].family;
2966 cmp = strcmp(fontsel_info->properties[FOUNDRY][foundry],
2967 fontsel_info->properties[FOUNDRY][table[middle].foundry]);
2972 fontnames[middle] = g_slist_prepend (fontnames[middle],
2983 /* Add another entry to the table for this new font family */
2984 temp_info.family = family_exists ? family : g_strdup(family);
2985 temp_info.foundry = foundry;
2986 temp_fontname = g_slist_prepend (NULL, fontname);
2990 /* Quickly insert the entry into the table in sorted order
2991 * using a modification of insertion sort and the knowledge
2992 * that the entries proper position in the table was determined
2993 * above in the binary search and is contained in the "lower"
2997 upper = *ntable - 1;
2998 while (lower != upper)
3000 table[upper] = table[upper-1];
3001 fontnames[upper] = fontnames[upper-1];
3005 table[lower] = temp_info;
3006 fontnames[lower] = temp_fontname;
3010 /* This checks that the specified field of the given fontname is in the
3011 appropriate properties array. If not it is added. Thus eventually we get
3012 arrays of all possible weights/slants etc. It returns the array index. */
3014 gtk_font_selection_insert_field (gchar *fontname,
3017 gchar field_buffer[XLFD_MAX_FIELD_LEN];
3021 field = gtk_font_selection_get_xlfd_field (fontname, xlfd_index[prop],
3026 /* If the field is already in the array just return its index. */
3027 for (index = 0; index < fontsel_info->nproperties[prop]; index++)
3028 if (!strcmp(field, fontsel_info->properties[prop][index]))
3031 /* Make sure we have enough space to add the field. */
3032 if (fontsel_info->nproperties[prop] == fontsel_info->space_allocated[prop])
3034 fontsel_info->space_allocated[prop] += PROPERTY_ARRAY_INCREMENT;
3035 fontsel_info->properties[prop] = g_realloc(fontsel_info->properties[prop],
3037 * fontsel_info->space_allocated[prop]);
3040 /* Add the new field. */
3041 index = fontsel_info->nproperties[prop];
3042 fontsel_info->properties[prop][index] = g_strdup(field);
3043 fontsel_info->nproperties[prop]++;
3048 /*****************************************************************************
3049 * These functions are the main public interface for getting/setting the font.
3050 *****************************************************************************/
3053 gtk_font_selection_get_font (GtkFontSelection *fontsel)
3055 g_return_val_if_fail (fontsel != NULL, NULL);
3056 return fontsel->font;
3061 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
3064 gchar *family_str, *foundry_str;
3065 gchar *property_str[GTK_NUM_STYLE_PROPERTIES];
3068 g_return_val_if_fail (fontsel != NULL, NULL);
3069 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
3071 /* If no family has been selected return NULL. */
3072 if (fontsel->font_index == -1)
3075 font = &fontsel_info->font_info[fontsel->font_index];
3076 family_str = font->family;
3077 foundry_str = fontsel_info->properties[FOUNDRY][font->foundry];
3079 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
3082 = fontsel_info->properties[prop][fontsel->property_values[prop]];
3083 if (strcmp (property_str[prop], "(nil)") == 0)
3084 property_str[prop] = "";
3087 return gtk_font_selection_create_xlfd (fontsel->size,
3091 property_str[WEIGHT],
3092 property_str[SLANT],
3093 property_str[SET_WIDTH],
3094 property_str[SPACING],
3095 property_str[CHARSET]);
3099 /* This sets the current font, selecting the appropriate clist rows.
3100 First we check the fontname is valid and try to find the font family
3101 - i.e. the name in the main list. If we can't find that, then just return.
3102 Next we try to set each of the properties according to the fontname.
3103 Finally we select the font family & style in the clists. */
3105 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
3106 const gchar *fontname)
3108 gchar *family, *field;
3109 gint index, prop, size;
3110 guint16 foundry, value;
3111 gchar family_buffer[XLFD_MAX_FIELD_LEN];
3112 gchar field_buffer[XLFD_MAX_FIELD_LEN];
3115 g_return_val_if_fail (fontsel != NULL, FALSE);
3116 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
3117 g_return_val_if_fail (fontname != NULL, FALSE);
3119 /* Check it is a valid fontname. */
3120 if (!gtk_font_selection_is_xlfd_font_name(fontname))
3123 family = gtk_font_selection_get_xlfd_field (fontname, XLFD_FAMILY,
3128 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_FOUNDRY,
3130 foundry = gtk_font_selection_field_to_index (fontsel_info->properties[FOUNDRY],
3131 fontsel_info->nproperties[FOUNDRY],
3134 index = gtk_font_selection_find_font(fontsel, family, foundry);
3138 /* Convert the property fields into indices and set them. */
3139 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
3141 field = gtk_font_selection_get_xlfd_field (fontname, xlfd_index[prop],
3143 value = gtk_font_selection_field_to_index (fontsel_info->properties[prop],
3144 fontsel_info->nproperties[prop],
3146 fontsel->property_values[prop] = value;
3149 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_POINTS,
3156 fontsel->size = fontsel->selected_size = size;
3157 fontsel->metric = GTK_FONT_METRIC_POINTS;
3158 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->points_button),
3161 sprintf (buffer, "%i", size / 10);
3163 sprintf (buffer, "%i.%i", size / 10, size % 10);
3167 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_PIXELS,
3172 fontsel->size = fontsel->selected_size = size;
3173 fontsel->metric = GTK_FONT_METRIC_PIXELS;
3174 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->pixels_button),
3176 sprintf (buffer, "%i", size);
3178 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
3180 /* Clear any current filter. */
3181 gtk_font_selection_clear_filter(fontsel);
3183 /* Now find the best style match. */
3184 fontsel->font_index = index;
3185 gtk_clist_select_row(GTK_CLIST(fontsel->font_clist), index, 0);
3186 if (GTK_WIDGET_MAPPED (fontsel->font_clist))
3187 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), index, -1, 0.5, 0);
3189 gtk_font_selection_show_available_styles (fontsel);
3190 /* This will load the font. */
3191 gtk_font_selection_select_best_style (fontsel, FALSE);
3197 /* Returns the index of the given family, or -1 if not found */
3199 gtk_font_selection_find_font (GtkFontSelection *fontsel,
3203 FontInfo *font_info;
3204 gint lower, upper, middle = -1, cmp, nfonts;
3205 gint found_family = -1;
3207 font_info = fontsel_info->font_info;
3208 nfonts = fontsel_info->nfonts;
3212 /* Do a binary search to find the font family. */
3215 while (lower < upper)
3217 middle = (lower + upper) >> 1;
3219 cmp = strcmp (family, font_info[middle].family);
3222 found_family = middle;
3223 cmp = strcmp(fontsel_info->properties[FOUNDRY][foundry],
3224 fontsel_info->properties[FOUNDRY][font_info[middle].foundry]);
3235 /* We couldn't find the family and foundry, but we may have just found the
3236 family, so we return that. */
3237 return found_family;
3241 /* This returns the text in the preview entry. You should copy the returned
3242 text if you need it. */
3244 gtk_font_selection_get_preview_text (GtkFontSelection *fontsel)
3246 return gtk_entry_get_text(GTK_ENTRY(fontsel->preview_entry));
3250 /* This sets the text in the preview entry. */
3252 gtk_font_selection_set_preview_text (GtkFontSelection *fontsel,
3255 gtk_entry_set_text(GTK_ENTRY(fontsel->preview_entry), text);
3259 /*****************************************************************************
3260 * These functions all deal with X Logical Font Description (XLFD) fontnames.
3261 * See the freely available documentation about this.
3262 *****************************************************************************/
3265 * Returns TRUE if the fontname is a valid XLFD.
3266 * (It just checks if the number of dashes is 14, and that each
3267 * field < XLFD_MAX_FIELD_LEN characters long - that's not in the XLFD but it
3268 * makes it easier for me).
3271 gtk_font_selection_is_xlfd_font_name (const gchar *fontname)
3278 if (*fontname++ == '-')
3280 if (field_len > XLFD_MAX_FIELD_LEN) return FALSE;
3288 return (i == 14) ? TRUE : FALSE;
3292 * This fills the buffer with the specified field from the X Logical Font
3293 * Description name, and returns it. If fontname is NULL or the field is
3294 * longer than XFLD_MAX_FIELD_LEN it returns NULL.
3295 * Note: For the charset field, we also return the encoding, e.g. 'iso8859-1'.
3298 gtk_font_selection_get_xlfd_field (const gchar *fontname,
3299 FontField field_num,
3302 const gchar *t1, *t2;
3303 gint countdown, len, num_dashes;
3308 /* we assume this is a valid fontname...that is, it has 14 fields */
3310 countdown = field_num;
3312 while (*t1 && (countdown >= 0))
3316 num_dashes = (field_num == XLFD_CHARSET) ? 2 : 1;
3317 for (t2 = t1; *t2; t2++)
3319 if (*t2 == '-' && --num_dashes == 0)
3325 /* Check we don't overflow the buffer */
3326 len = (long) t2 - (long) t1;
3327 if (len > XLFD_MAX_FIELD_LEN - 1)
3329 strncpy (buffer, t1, len);
3332 /* Convert to lower case. */
3336 strcpy(buffer, "(nil)");
3342 * This returns a X Logical Font Description font name, given all the pieces.
3343 * Note: this retval must be freed by the caller.
3346 gtk_font_selection_create_xlfd (gint size,
3347 GtkFontMetricType metric,
3357 gchar *pixel_size = "*", *point_size = "*", *fontname;
3363 sprintf (buffer, "%d", (int) size);
3364 if (metric == GTK_FONT_METRIC_PIXELS)
3365 pixel_size = buffer;
3367 point_size = buffer;
3369 /* Note: be careful here - don't overrun the allocated memory. */
3370 length = strlen(foundry) + strlen(family) + strlen(weight) + strlen(slant)
3371 + strlen(set_width) + strlen(pixel_size) + strlen(point_size)
3372 + strlen(spacing) + strlen(charset)
3373 + 1 + 1 + 1 + 1 + 1 + 3 + 1 + 5 + 3
3374 + 1 /* for the terminating '\0'. */;
3376 fontname = g_new(gchar, length);
3377 /* **NOTE**: If you change this string please change length above! */
3378 sprintf(fontname, "-%s-%s-%s-%s-%s-*-%s-%s-*-*-%s-*-%s",
3379 foundry, family, weight, slant, set_width, pixel_size,
3380 point_size, spacing, charset);
3386 /*****************************************************************************
3387 * GtkFontSelectionDialog
3388 *****************************************************************************/
3391 gtk_font_selection_dialog_get_type (void)
3393 static guint font_selection_dialog_type = 0;
3395 if (!font_selection_dialog_type)
3397 GtkTypeInfo fontsel_diag_info =
3399 "GtkFontSelectionDialog",
3400 sizeof (GtkFontSelectionDialog),
3401 sizeof (GtkFontSelectionDialogClass),
3402 (GtkClassInitFunc) gtk_font_selection_dialog_class_init,
3403 (GtkObjectInitFunc) gtk_font_selection_dialog_init,
3404 /* reserved_1 */ NULL,
3405 /* reserved_2 */ NULL,
3406 (GtkClassInitFunc) NULL,
3409 font_selection_dialog_type = gtk_type_unique (GTK_TYPE_WINDOW, &fontsel_diag_info);
3412 return font_selection_dialog_type;
3416 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
3418 GtkObjectClass *object_class;
3420 object_class = (GtkObjectClass*) klass;
3422 font_selection_dialog_parent_class = gtk_type_class (GTK_TYPE_WINDOW);
3426 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
3428 fontseldiag->dialog_width = -1;
3429 fontseldiag->auto_resize = TRUE;
3431 gtk_widget_set_events(GTK_WIDGET(fontseldiag), GDK_STRUCTURE_MASK);
3432 gtk_signal_connect (GTK_OBJECT (fontseldiag), "configure_event",
3433 (GtkSignalFunc) gtk_font_selection_dialog_on_configure,
3436 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag), 4);
3437 gtk_window_set_policy(GTK_WINDOW(fontseldiag), FALSE, TRUE, TRUE);
3439 fontseldiag->main_vbox = gtk_vbox_new (FALSE, 4);
3440 gtk_widget_show (fontseldiag->main_vbox);
3441 gtk_container_add (GTK_CONTAINER (fontseldiag), fontseldiag->main_vbox);
3443 fontseldiag->fontsel = gtk_font_selection_new();
3444 gtk_widget_show (fontseldiag->fontsel);
3445 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
3446 fontseldiag->fontsel, TRUE, TRUE, 0);
3448 /* Create the action area */
3449 fontseldiag->action_area = gtk_hbutton_box_new ();
3450 gtk_button_box_set_layout(GTK_BUTTON_BOX(fontseldiag->action_area),
3452 gtk_button_box_set_spacing(GTK_BUTTON_BOX(fontseldiag->action_area), 5);
3453 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
3454 fontseldiag->action_area, FALSE, FALSE, 0);
3455 gtk_widget_show (fontseldiag->action_area);
3457 fontseldiag->ok_button = gtk_button_new_with_label("OK");
3458 GTK_WIDGET_SET_FLAGS (fontseldiag->ok_button, GTK_CAN_DEFAULT);
3459 gtk_widget_show(fontseldiag->ok_button);
3460 gtk_box_pack_start (GTK_BOX (fontseldiag->action_area),
3461 fontseldiag->ok_button, TRUE, TRUE, 0);
3462 gtk_widget_grab_default (fontseldiag->ok_button);
3464 fontseldiag->apply_button = gtk_button_new_with_label("Apply");
3465 GTK_WIDGET_SET_FLAGS (fontseldiag->apply_button, GTK_CAN_DEFAULT);
3466 /*gtk_widget_show(fontseldiag->apply_button);*/
3467 gtk_box_pack_start (GTK_BOX(fontseldiag->action_area),
3468 fontseldiag->apply_button, TRUE, TRUE, 0);
3470 fontseldiag->cancel_button = gtk_button_new_with_label("Cancel");
3471 GTK_WIDGET_SET_FLAGS (fontseldiag->cancel_button, GTK_CAN_DEFAULT);
3472 gtk_widget_show(fontseldiag->cancel_button);
3473 gtk_box_pack_start (GTK_BOX(fontseldiag->action_area),
3474 fontseldiag->cancel_button, TRUE, TRUE, 0);
3480 gtk_font_selection_dialog_new (const gchar *title)
3482 GtkFontSelectionDialog *fontseldiag;
3484 fontseldiag = gtk_type_new (GTK_TYPE_FONT_SELECTION_DIALOG);
3485 gtk_window_set_title (GTK_WINDOW (fontseldiag),
3486 title ? title : "Font Selection");
3488 return GTK_WIDGET (fontseldiag);
3492 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
3494 return gtk_font_selection_get_font_name(GTK_FONT_SELECTION(fsd->fontsel));
3498 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
3500 return gtk_font_selection_get_font(GTK_FONT_SELECTION(fsd->fontsel));
3504 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
3505 const gchar *fontname)
3507 return gtk_font_selection_set_font_name(GTK_FONT_SELECTION(fsd->fontsel),
3512 gtk_font_selection_dialog_set_filter (GtkFontSelectionDialog *fsd,
3513 GtkFontFilterType filter_type,
3514 GtkFontType font_type,
3522 gtk_font_selection_set_filter (GTK_FONT_SELECTION (fsd->fontsel),
3523 filter_type, font_type,
3524 foundries, weights, slants, setwidths,
3525 spacings, charsets);
3529 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
3531 return gtk_font_selection_get_preview_text(GTK_FONT_SELECTION(fsd->fontsel));
3535 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
3538 gtk_font_selection_set_preview_text(GTK_FONT_SELECTION(fsd->fontsel), text);
3542 /* This turns auto-shrink off if the user resizes the width of the dialog.
3543 It also turns it back on again if the user resizes it back to its normal
3546 gtk_font_selection_dialog_on_configure (GtkWidget *widget,
3547 GdkEventConfigure *event,
3548 GtkFontSelectionDialog *fsd)
3550 /* This sets the initial width. */
3551 if (fsd->dialog_width == -1)
3552 fsd->dialog_width = event->width;
3553 else if (fsd->auto_resize && fsd->dialog_width != event->width)
3555 fsd->auto_resize = FALSE;
3556 gtk_window_set_policy(GTK_WINDOW(fsd), FALSE, TRUE, FALSE);
3558 else if (!fsd->auto_resize && fsd->dialog_width == event->width)
3560 fsd->auto_resize = TRUE;
3561 gtk_window_set_policy(GTK_WINDOW(fsd), FALSE, TRUE, TRUE);