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"
87 /* The maximum number of fontnames requested with XListFonts(). */
88 #define MAX_FONTS 32767
90 /* This is the largest field length we will accept. If a fontname has a field
91 larger than this we will skip it. */
92 #define XLFD_MAX_FIELD_LEN 64
94 /* These are what we use as the standard font sizes, for the size clist.
95 Note that when using points we still show these integer point values but
96 we work internally in decipoints (and decipoint values can be typed in). */
97 static const guint16 font_sizes[] = {
98 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28,
99 32, 36, 40, 48, 56, 64, 72
102 /* Initial font metric & size (Remember point sizes are in decipoints).
103 The font size should match one of those in the font_sizes array. */
104 #define INITIAL_METRIC GTK_FONT_METRIC_POINTS
105 #define INITIAL_FONT_SIZE 140
107 /* This is the default text shown in the preview entry, though the user
108 can set it. Remember that some fonts only have capital letters. */
109 #define PREVIEW_TEXT "abcdefghijk ABCDEFGHIJK"
111 /* This is the initial and maximum height of the preview entry (it expands
112 when large font sizes are selected). Initial height is also the minimum. */
113 #define INITIAL_PREVIEW_HEIGHT 44
114 #define MAX_PREVIEW_HEIGHT 300
116 /* These are the sizes of the font, style & size clists. */
117 #define FONT_LIST_HEIGHT 136
118 #define FONT_LIST_WIDTH 190
119 #define FONT_STYLE_LIST_WIDTH 170
120 #define FONT_SIZE_LIST_WIDTH 60
122 /* This is the number of fields in an X Logical Font Description font name.
123 Note that we count the registry & encoding as 1. */
124 #define GTK_XLFD_NUM_FIELDS 13
126 typedef struct _GtkFontSelInfo GtkFontSelInfo;
127 typedef struct _FontInfo FontInfo;
128 typedef struct _FontStyle FontStyle;
130 /* This struct represents one family of fonts (with one foundry), e.g. adobe
131 courier or sony fixed. It stores the family name, the index of the foundry
132 name, and the index of and number of available styles. */
141 /* This represents one style, as displayed in the Font Style clist. It can
142 have a number of available pixel sizes and point sizes. The indexes point
143 into the two big fontsel_info->pixel_sizes & fontsel_info->point_sizes
144 arrays. The displayed flag is used when displaying styles to remember which
145 styles have already been displayed. Note that it is combined with the
146 GtkFontType in the flags field. */
147 #define GTK_FONT_DISPLAYED (1 << 7)
150 guint16 properties[GTK_NUM_STYLE_PROPERTIES];
151 gint pixel_sizes_index;
152 guint16 npixel_sizes;
153 gint point_sizes_index;
154 guint16 npoint_sizes;
158 struct _GtkFontSelInfo {
160 /* This is a table with each FontInfo representing one font family+foundry */
164 /* This stores all the valid combinations of properties for every family.
165 Each FontInfo holds an index into its own space in this one big array. */
166 FontStyle *font_styles;
169 /* This stores all the font sizes available for every style.
170 Each style holds an index into these arrays. */
171 guint16 *pixel_sizes;
172 guint16 *point_sizes;
174 /* These are the arrays of strings of all possible weights, slants,
175 set widths, spacings, charsets & foundries, and the amount of space
176 allocated for each array. */
177 gchar **properties[GTK_NUM_FONT_PROPERTIES];
178 guint16 nproperties[GTK_NUM_FONT_PROPERTIES];
179 guint16 space_allocated[GTK_NUM_FONT_PROPERTIES];
182 /* These are the field numbers in the X Logical Font Description fontnames,
183 e.g. -adobe-courier-bold-o-normal--25-180-100-100-m-150-iso8859-1 */
194 XLFD_RESOLUTION_X = 8,
195 XLFD_RESOLUTION_Y = 9,
197 XLFD_AVERAGE_WIDTH = 11,
201 /* These are the names of the fields, used on the info & filter page. */
202 static const gchar* xlfd_field_names[GTK_XLFD_NUM_FIELDS] = {
214 N_("Average Width:"),
218 /* These are the array indices of the font properties used in several arrays,
219 and should match the xlfd_index array below. */
230 /* This is used to look up a field in a fontname given one of the above
232 static const FontField xlfd_index[GTK_NUM_FONT_PROPERTIES] = {
241 /* These are the positions of the properties in the filter table - x, y. */
242 static const gint filter_positions[GTK_NUM_FONT_PROPERTIES][2] = {
243 { 1, 0 }, { 0, 2 }, { 1, 2 }, { 2, 2 }, { 2, 0 }, { 0, 0 }
245 static const gint filter_heights[GTK_NUM_FONT_PROPERTIES] = {
246 100, 70, 70, 40, 100, 100
249 /* This is returned by gtk_font_selection_filter_state to describe if a
250 property value is filtered. e.g. if 'bold' has been selected on the filter
251 page, then that will return 'FILTERED' and 'black' will be 'NOT_FILTERED'.
252 If none of the weight values are selected, they all return 'NOT_SET'. */
258 } GtkFontPropertyFilterState;
260 static GtkFontSelInfo *fontsel_info = NULL;
262 /* The initial size and increment of each of the arrays of property values. */
263 #define PROPERTY_ARRAY_INCREMENT 16
265 static void gtk_font_selection_class_init (GtkFontSelectionClass *klass);
266 static void gtk_font_selection_init (GtkFontSelection *fontsel);
267 static void gtk_font_selection_destroy (GtkObject *object);
269 /* These are all used for class initialization - loading in the fonts etc. */
270 static void gtk_font_selection_get_fonts (void);
271 static void gtk_font_selection_insert_font (GSList *fontnames[],
274 static gint gtk_font_selection_insert_field (gchar *fontname,
277 /* These are the callbacks & related functions. */
278 static void gtk_font_selection_select_font (GtkWidget *w,
281 GdkEventButton *bevent,
283 static gint gtk_font_selection_on_clist_key_press (GtkWidget *clist,
285 GtkFontSelection *fs);
286 static gboolean gtk_font_selection_select_next (GtkFontSelection *fs,
289 static void gtk_font_selection_show_available_styles
290 (GtkFontSelection *fs);
291 static void gtk_font_selection_select_best_style (GtkFontSelection *fs,
294 static void gtk_font_selection_select_style (GtkWidget *w,
297 GdkEventButton *bevent,
299 static void gtk_font_selection_show_available_sizes
300 (GtkFontSelection *fs);
301 static gint gtk_font_selection_size_key_press (GtkWidget *w,
304 static void gtk_font_selection_select_best_size (GtkFontSelection *fs);
305 static void gtk_font_selection_select_size (GtkWidget *w,
308 GdkEventButton *bevent,
311 static void gtk_font_selection_metric_callback (GtkWidget *w,
313 static void gtk_font_selection_expose_list (GtkWidget *w,
314 GdkEventExpose *event,
316 static void gtk_font_selection_realize_list (GtkWidget *widget,
319 static void gtk_font_selection_switch_page (GtkWidget *w,
320 GtkNotebookPage *page,
323 static void gtk_font_selection_show_font_info (GtkFontSelection *fs);
325 static void gtk_font_selection_select_filter (GtkWidget *w,
328 GdkEventButton *bevent,
329 GtkFontSelection *fs);
330 static void gtk_font_selection_unselect_filter (GtkWidget *w,
333 GdkEventButton *bevent,
334 GtkFontSelection *fs);
335 static void gtk_font_selection_update_filter (GtkFontSelection *fs);
336 static gboolean gtk_font_selection_style_visible (GtkFontSelection *fs,
339 static void gtk_font_selection_reset_filter (GtkWidget *w,
340 GtkFontSelection *fs);
341 static void gtk_font_selection_on_clear_filter (GtkWidget *w,
342 GtkFontSelection *fs);
343 static void gtk_font_selection_show_available_fonts
344 (GtkFontSelection *fs);
345 static void gtk_font_selection_clear_filter (GtkFontSelection *fs);
346 static void gtk_font_selection_update_filter_lists(GtkFontSelection *fs);
347 static GtkFontPropertyFilterState gtk_font_selection_filter_state
348 (GtkFontSelection *fs,
349 GtkFontFilterType filter_type,
353 /* Misc. utility functions. */
354 static gboolean gtk_font_selection_load_font (GtkFontSelection *fs);
355 static void gtk_font_selection_update_preview (GtkFontSelection *fs);
357 static gint gtk_font_selection_find_font (GtkFontSelection *fs,
360 static guint16 gtk_font_selection_field_to_index (gchar **table,
364 static gchar* gtk_font_selection_expand_slant_code (gchar *slant);
365 static gchar* gtk_font_selection_expand_spacing_code(gchar *spacing);
367 /* Functions for handling X Logical Font Description fontnames. */
368 static gboolean gtk_font_selection_is_xlfd_font_name (const gchar *fontname);
369 static char* gtk_font_selection_get_xlfd_field (const gchar *fontname,
372 static gchar * gtk_font_selection_create_xlfd (gint size,
373 GtkFontMetricType metric,
383 /* FontSelectionDialog */
384 static void gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass);
385 static void gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag);
387 static gint gtk_font_selection_dialog_on_configure(GtkWidget *widget,
388 GdkEventConfigure *event,
389 GtkFontSelectionDialog *fsd);
391 static GtkWindowClass *font_selection_parent_class = NULL;
392 static GtkNotebookClass *font_selection_dialog_parent_class = NULL;
395 gtk_font_selection_get_type()
397 static GtkType font_selection_type = 0;
399 if(!font_selection_type)
401 static const GtkTypeInfo fontsel_type_info =
404 sizeof (GtkFontSelection),
405 sizeof (GtkFontSelectionClass),
406 (GtkClassInitFunc) gtk_font_selection_class_init,
407 (GtkObjectInitFunc) gtk_font_selection_init,
408 /* reserved_1 */ NULL,
409 /* reserved_2 */ NULL,
410 (GtkClassInitFunc) NULL,
413 font_selection_type = gtk_type_unique (GTK_TYPE_NOTEBOOK,
417 return font_selection_type;
421 gtk_font_selection_class_init(GtkFontSelectionClass *klass)
423 GtkObjectClass *object_class;
425 object_class = (GtkObjectClass *) klass;
427 font_selection_parent_class = gtk_type_class (GTK_TYPE_NOTEBOOK);
429 object_class->destroy = gtk_font_selection_destroy;
431 gtk_font_selection_get_fonts ();
435 gtk_font_selection_init(GtkFontSelection *fontsel)
437 GtkWidget *scrolled_win;
438 GtkWidget *text_frame;
439 GtkWidget *text_box, *frame;
440 GtkWidget *table, *label, *hbox, *hbox2, *clist, *button, *vbox, *alignment;
442 gchar *titles[] = { NULL, NULL, NULL };
447 gchar *property, *text;
450 /* Number of internationalized titles here must match number
451 of NULL initializers above */
452 titles[0] = _("Font Property");
453 titles[1] = _("Requested Value");
454 titles[2] = _("Actual Value");
456 /* Initialize the GtkFontSelection struct. We do this here in case any
457 callbacks are triggered while creating the interface. */
458 fontsel->font = NULL;
459 fontsel->font_index = -1;
461 fontsel->metric = INITIAL_METRIC;
462 fontsel->size = INITIAL_FONT_SIZE;
463 fontsel->selected_size = INITIAL_FONT_SIZE;
465 fontsel->filters[GTK_FONT_FILTER_BASE].font_type = GTK_FONT_ALL;
466 fontsel->filters[GTK_FONT_FILTER_USER].font_type = GTK_FONT_BITMAP
470 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
472 fontsel->filters[GTK_FONT_FILTER_BASE].property_filters[prop] = NULL;
473 fontsel->filters[GTK_FONT_FILTER_BASE].property_nfilters[prop] = 0;
474 fontsel->filters[GTK_FONT_FILTER_USER].property_filters[prop] = NULL;
475 fontsel->filters[GTK_FONT_FILTER_USER].property_nfilters[prop] = 0;
478 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
479 fontsel->property_values[prop] = 0;
481 /* Create the main notebook page. */
482 gtk_notebook_set_homogeneous_tabs (GTK_NOTEBOOK (fontsel), TRUE);
483 gtk_notebook_set_tab_hborder (GTK_NOTEBOOK (fontsel), 8);
484 fontsel->main_vbox = gtk_vbox_new (FALSE, 4);
485 gtk_widget_show (fontsel->main_vbox);
486 gtk_container_set_border_width (GTK_CONTAINER (fontsel->main_vbox), 6);
487 label = gtk_label_new(_("Font"));
488 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
489 fontsel->main_vbox, label);
491 /* Create the table of font, style & size. */
492 table = gtk_table_new (3, 3, FALSE);
493 gtk_widget_show (table);
494 gtk_table_set_col_spacings(GTK_TABLE(table), 8);
495 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), table, TRUE, TRUE, 0);
497 fontsel->font_label = gtk_label_new(_("Font:"));
498 gtk_misc_set_alignment (GTK_MISC (fontsel->font_label), 0.0, 0.5);
499 gtk_widget_show (fontsel->font_label);
500 gtk_table_attach (GTK_TABLE (table), fontsel->font_label, 0, 1, 0, 1,
502 label = gtk_label_new(_("Font Style:"));
503 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
504 gtk_widget_show (label);
505 gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1,
507 label = gtk_label_new(_("Size:"));
508 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
509 gtk_widget_show (label);
510 gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
513 fontsel->font_entry = gtk_entry_new();
514 gtk_entry_set_editable(GTK_ENTRY(fontsel->font_entry), FALSE);
515 gtk_widget_set_usize (fontsel->font_entry, 20, -1);
516 gtk_widget_show (fontsel->font_entry);
517 gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
519 fontsel->font_style_entry = gtk_entry_new();
520 gtk_entry_set_editable(GTK_ENTRY(fontsel->font_style_entry), FALSE);
521 gtk_widget_set_usize (fontsel->font_style_entry, 20, -1);
522 gtk_widget_show (fontsel->font_style_entry);
523 gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
525 fontsel->size_entry = gtk_entry_new();
526 gtk_widget_set_usize (fontsel->size_entry, 20, -1);
527 gtk_widget_show (fontsel->size_entry);
528 gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
530 gtk_signal_connect (GTK_OBJECT (fontsel->size_entry), "key_press_event",
531 (GtkSignalFunc) gtk_font_selection_size_key_press,
534 /* Create the clists */
535 fontsel->font_clist = gtk_clist_new(1);
536 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->font_clist));
537 gtk_clist_set_column_auto_resize (GTK_CLIST (fontsel->font_clist), 0, TRUE);
538 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
539 gtk_widget_set_usize (scrolled_win, FONT_LIST_WIDTH, FONT_LIST_HEIGHT);
540 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->font_clist);
541 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
542 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
543 gtk_widget_show(fontsel->font_clist);
544 gtk_widget_show(scrolled_win);
546 gtk_table_attach (GTK_TABLE (table), scrolled_win, 0, 1, 2, 3,
547 GTK_EXPAND | GTK_FILL,
548 GTK_EXPAND | GTK_FILL, 0, 0);
550 fontsel->font_style_clist = gtk_clist_new(1);
551 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->font_style_clist));
552 gtk_clist_set_column_auto_resize (GTK_CLIST (fontsel->font_style_clist),
554 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
555 gtk_widget_set_usize (scrolled_win, FONT_STYLE_LIST_WIDTH, -1);
556 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->font_style_clist);
557 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
558 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
559 gtk_widget_show(fontsel->font_style_clist);
560 gtk_widget_show(scrolled_win);
561 gtk_table_attach (GTK_TABLE (table), scrolled_win, 1, 2, 2, 3,
562 GTK_EXPAND | GTK_FILL,
563 GTK_EXPAND | GTK_FILL, 0, 0);
565 fontsel->size_clist = gtk_clist_new(1);
566 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->size_clist));
567 gtk_clist_set_column_width (GTK_CLIST(fontsel->size_clist), 0, 20);
568 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
569 gtk_widget_set_usize (scrolled_win, FONT_SIZE_LIST_WIDTH, -1);
570 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->size_clist);
571 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
572 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
573 gtk_widget_show(fontsel->size_clist);
574 gtk_widget_show(scrolled_win);
575 gtk_table_attach (GTK_TABLE (table), scrolled_win, 2, 3, 2, 3,
576 GTK_FILL, GTK_FILL, 0, 0);
579 /* Insert the fonts. If there exist fonts with the same family but
580 different foundries, then the foundry name is appended in brackets. */
581 gtk_font_selection_show_available_fonts(fontsel);
583 gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "select_row",
584 GTK_SIGNAL_FUNC(gtk_font_selection_select_font),
586 GTK_WIDGET_SET_FLAGS (fontsel->font_clist, GTK_CAN_FOCUS);
587 gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "key_press_event",
588 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
590 gtk_signal_connect_after (GTK_OBJECT (fontsel->font_clist), "expose_event",
591 GTK_SIGNAL_FUNC(gtk_font_selection_expose_list),
594 gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist), "select_row",
595 GTK_SIGNAL_FUNC(gtk_font_selection_select_style),
597 GTK_WIDGET_SET_FLAGS (fontsel->font_style_clist, GTK_CAN_FOCUS);
598 gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist),
600 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
602 gtk_signal_connect_after (GTK_OBJECT (fontsel->font_style_clist),
604 GTK_SIGNAL_FUNC(gtk_font_selection_realize_list),
607 /* Insert the standard font sizes */
608 gtk_clist_freeze (GTK_CLIST(fontsel->size_clist));
609 size_to_match = INITIAL_FONT_SIZE;
610 if (INITIAL_METRIC == GTK_FONT_METRIC_POINTS)
611 size_to_match = size_to_match / 10;
612 for (i = 0; i < sizeof(font_sizes) / sizeof(font_sizes[0]); i++)
614 sprintf(buffer, "%i", font_sizes[i]);
616 gtk_clist_append(GTK_CLIST(fontsel->size_clist), &size);
617 if (font_sizes[i] == size_to_match)
619 gtk_clist_select_row(GTK_CLIST(fontsel->size_clist), i, 0);
620 gtk_entry_set_text(GTK_ENTRY(fontsel->size_entry), buffer);
623 gtk_clist_thaw (GTK_CLIST(fontsel->size_clist));
625 gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "select_row",
626 GTK_SIGNAL_FUNC(gtk_font_selection_select_size),
628 GTK_WIDGET_SET_FLAGS (fontsel->size_clist, GTK_CAN_FOCUS);
629 gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "key_press_event",
630 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
634 /* create the Reset Filter & Metric buttons */
635 hbox = gtk_hbox_new(FALSE, 8);
636 gtk_widget_show (hbox);
637 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), hbox, FALSE, TRUE, 0);
639 fontsel->filter_button = gtk_button_new_with_label(_("Reset Filter"));
640 gtk_misc_set_padding (GTK_MISC (GTK_BIN (fontsel->filter_button)->child),
642 gtk_widget_show(fontsel->filter_button);
643 gtk_box_pack_start (GTK_BOX (hbox), fontsel->filter_button, FALSE, FALSE, 0);
644 gtk_widget_set_sensitive (fontsel->filter_button, FALSE);
645 gtk_signal_connect (GTK_OBJECT (fontsel->filter_button), "clicked",
646 GTK_SIGNAL_FUNC(gtk_font_selection_on_clear_filter),
649 hbox2 = gtk_hbox_new(FALSE, 0);
650 gtk_widget_show (hbox2);
651 gtk_box_pack_end (GTK_BOX (hbox), hbox2, FALSE, FALSE, 0);
653 label = gtk_label_new(_("Metric:"));
654 gtk_widget_show (label);
655 gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 8);
657 fontsel->points_button = gtk_radio_button_new_with_label(NULL, _("Points"));
658 gtk_widget_show (fontsel->points_button);
659 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->points_button, FALSE, TRUE, 0);
660 if (INITIAL_METRIC == GTK_FONT_METRIC_POINTS)
661 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fontsel->points_button),
664 fontsel->pixels_button = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(fontsel->points_button), _("Pixels"));
665 gtk_widget_show (fontsel->pixels_button);
666 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->pixels_button, FALSE, TRUE, 0);
667 if (INITIAL_METRIC == GTK_FONT_METRIC_PIXELS)
668 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fontsel->pixels_button),
671 gtk_signal_connect(GTK_OBJECT(fontsel->points_button), "toggled",
672 (GtkSignalFunc) gtk_font_selection_metric_callback,
674 gtk_signal_connect(GTK_OBJECT(fontsel->pixels_button), "toggled",
675 (GtkSignalFunc) gtk_font_selection_metric_callback,
679 /* create the text entry widget */
680 text_frame = gtk_frame_new (_("Preview:"));
681 gtk_widget_show (text_frame);
682 gtk_frame_set_shadow_type(GTK_FRAME(text_frame), GTK_SHADOW_ETCHED_IN);
683 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), text_frame,
686 /* This is just used to get a 4-pixel space around the preview entry. */
687 text_box = gtk_hbox_new (FALSE, 0);
688 gtk_widget_show (text_box);
689 gtk_container_add (GTK_CONTAINER (text_frame), text_box);
690 gtk_container_set_border_width (GTK_CONTAINER (text_box), 4);
692 fontsel->preview_entry = gtk_entry_new ();
693 gtk_widget_show (fontsel->preview_entry);
694 gtk_widget_set_usize (fontsel->preview_entry, -1, INITIAL_PREVIEW_HEIGHT);
695 gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
698 /* Create the message area */
699 fontsel->message_label = gtk_label_new("");
700 gtk_widget_show (fontsel->message_label);
701 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), fontsel->message_label,
705 /* Create the font info page */
706 fontsel->info_vbox = gtk_vbox_new (FALSE, 4);
707 gtk_widget_show (fontsel->info_vbox);
708 gtk_container_set_border_width (GTK_CONTAINER (fontsel->info_vbox), 2);
709 label = gtk_label_new(_("Font Information"));
710 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
711 fontsel->info_vbox, label);
713 fontsel->info_clist = gtk_clist_new_with_titles (3, titles);
714 gtk_widget_set_usize (fontsel->info_clist, 390, 150);
715 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 0, 130);
716 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 1, 130);
717 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 2, 130);
718 gtk_clist_column_titles_passive(GTK_CLIST(fontsel->info_clist));
719 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
720 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->info_clist);
721 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
722 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
723 gtk_widget_show(fontsel->info_clist);
724 gtk_widget_show(scrolled_win);
725 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), scrolled_win,
728 /* Insert the property names */
729 gtk_clist_freeze (GTK_CLIST(fontsel->info_clist));
732 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
734 row_text[0] = gettext(xlfd_field_names[i]);
735 gtk_clist_append(GTK_CLIST(fontsel->info_clist), row_text);
736 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 0, 0, 4);
737 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 1, 0, 4);
738 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 2, 0, 4);
740 gtk_clist_thaw (GTK_CLIST(fontsel->info_clist));
742 label = gtk_label_new(_("Requested Font Name:"));
743 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
744 gtk_widget_show (label);
745 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, TRUE, 0);
747 fontsel->requested_font_name = gtk_entry_new();
748 gtk_entry_set_editable(GTK_ENTRY(fontsel->requested_font_name), FALSE);
749 gtk_widget_show (fontsel->requested_font_name);
750 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox),
751 fontsel->requested_font_name, FALSE, TRUE, 0);
753 label = gtk_label_new(_("Actual Font Name:"));
754 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
755 gtk_widget_show (label);
756 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, TRUE, 0);
758 fontsel->actual_font_name = gtk_entry_new();
759 gtk_entry_set_editable(GTK_ENTRY(fontsel->actual_font_name), FALSE);
760 gtk_widget_show (fontsel->actual_font_name);
761 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox),
762 fontsel->actual_font_name, FALSE, TRUE, 0);
764 sprintf(buffer, _("%i fonts available with a total of %i styles."),
765 fontsel_info->nfonts, fontsel_info->nstyles);
766 label = gtk_label_new(buffer);
767 gtk_widget_show (label);
768 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, FALSE, 0);
770 gtk_signal_connect (GTK_OBJECT (fontsel), "switch_page",
771 GTK_SIGNAL_FUNC(gtk_font_selection_switch_page),
775 /* Create the Filter page. */
776 fontsel->filter_vbox = gtk_vbox_new (FALSE, 4);
777 gtk_widget_show (fontsel->filter_vbox);
778 gtk_container_set_border_width (GTK_CONTAINER (fontsel->filter_vbox), 2);
779 label = gtk_label_new(_("Filter"));
780 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
781 fontsel->filter_vbox, label);
783 /* Create the font type checkbuttons. */
784 frame = gtk_frame_new (NULL);
785 gtk_widget_show (frame);
786 gtk_box_pack_start (GTK_BOX (fontsel->filter_vbox), frame, FALSE, TRUE, 0);
788 hbox = gtk_hbox_new (FALSE, 20);
789 gtk_widget_show (hbox);
790 gtk_container_add (GTK_CONTAINER (frame), hbox);
792 label = gtk_label_new(_("Font Types:"));
793 gtk_widget_show (label);
794 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 10);
796 hbox2 = gtk_hbox_new (TRUE, 0);
797 gtk_widget_show (hbox2);
798 gtk_box_pack_start (GTK_BOX (hbox), hbox2, FALSE, TRUE, 0);
800 fontsel->type_bitmaps_button = gtk_check_button_new_with_label (_("Bitmap"));
801 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), TRUE);
802 gtk_widget_show (fontsel->type_bitmaps_button);
803 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_bitmaps_button,
806 fontsel->type_scalable_button = gtk_check_button_new_with_label (_("Scalable"));
807 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), TRUE);
808 gtk_widget_show (fontsel->type_scalable_button);
809 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_scalable_button,
812 fontsel->type_scaled_bitmaps_button = gtk_check_button_new_with_label (_("Scaled Bitmap"));
813 gtk_widget_show (fontsel->type_scaled_bitmaps_button);
814 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_scaled_bitmaps_button,
817 table = gtk_table_new (4, 3, FALSE);
818 gtk_table_set_col_spacings(GTK_TABLE(table), 2);
819 gtk_widget_show (table);
820 gtk_box_pack_start (GTK_BOX (fontsel->filter_vbox), table, TRUE, TRUE, 0);
822 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
824 gint left = filter_positions[prop][0];
825 gint top = filter_positions[prop][1];
827 label = gtk_label_new(gettext(xlfd_field_names[xlfd_index[prop]]));
828 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 1.0);
829 gtk_misc_set_padding (GTK_MISC (label), 0, 2);
830 gtk_widget_show(label);
831 gtk_table_attach (GTK_TABLE (table), label, left, left + 1,
832 top, top + 1, GTK_FILL, GTK_FILL, 0, 0);
834 clist = gtk_clist_new(1);
835 gtk_widget_set_usize (clist, 100, filter_heights[prop]);
836 gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_MULTIPLE);
837 gtk_clist_column_titles_hide(GTK_CLIST(clist));
838 gtk_clist_set_column_auto_resize (GTK_CLIST (clist), 0, TRUE);
839 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
840 gtk_container_add (GTK_CONTAINER (scrolled_win), clist);
841 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
842 GTK_POLICY_AUTOMATIC,
843 GTK_POLICY_AUTOMATIC);
844 gtk_widget_show(clist);
845 gtk_widget_show(scrolled_win);
847 /* For the bottom-right cell we add the 'Reset Filter' button. */
848 if (top == 2 && left == 2)
850 vbox = gtk_vbox_new(FALSE, 0);
851 gtk_widget_show(vbox);
852 gtk_table_attach (GTK_TABLE (table), vbox, left, left + 1,
853 top + 1, top + 2, GTK_FILL, GTK_FILL, 0, 0);
855 gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0);
857 alignment = gtk_alignment_new(0.5, 0.0, 0.8, 0.0);
858 gtk_widget_show(alignment);
859 gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, TRUE, 4);
861 button = gtk_button_new_with_label(_("Reset Filter"));
862 gtk_widget_show(button);
863 gtk_container_add(GTK_CONTAINER(alignment), button);
864 gtk_signal_connect (GTK_OBJECT (button), "clicked",
865 GTK_SIGNAL_FUNC(gtk_font_selection_reset_filter),
869 gtk_table_attach (GTK_TABLE (table), scrolled_win,
870 left, left + 1, top + 1, top + 2,
871 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
873 gtk_signal_connect (GTK_OBJECT (clist), "select_row",
874 GTK_SIGNAL_FUNC(gtk_font_selection_select_filter),
876 gtk_signal_connect (GTK_OBJECT (clist), "unselect_row",
877 GTK_SIGNAL_FUNC(gtk_font_selection_unselect_filter),
880 /* Insert the property names, expanded, and in sorted order.
881 But we make sure that the wildcard '*' is first. */
882 gtk_clist_freeze (GTK_CLIST(clist));
884 gtk_clist_append(GTK_CLIST(clist), &property);
886 for (i = 1; i < fontsel_info->nproperties[prop]; i++) {
887 property = fontsel_info->properties[prop][i];
889 property = gtk_font_selection_expand_slant_code(property);
890 else if (prop == SPACING)
891 property = gtk_font_selection_expand_spacing_code(property);
894 for (row = 1; row < GTK_CLIST(clist)->rows; row++)
896 gtk_clist_get_text(GTK_CLIST(clist), row, 0, &text);
897 if (strcmp(property, text) < 0)
900 gtk_clist_insert(GTK_CLIST(clist), row, &property);
905 row = gtk_clist_append(GTK_CLIST(clist), &property);
906 gtk_clist_set_row_data(GTK_CLIST(clist), row, GINT_TO_POINTER (i));
908 gtk_clist_select_row(GTK_CLIST(clist), 0, 0);
909 gtk_clist_thaw (GTK_CLIST(clist));
910 fontsel->filter_clists[prop] = clist;
915 gtk_font_selection_new()
917 GtkFontSelection *fontsel;
919 fontsel = gtk_type_new (GTK_TYPE_FONT_SELECTION);
921 return GTK_WIDGET (fontsel);
925 gtk_font_selection_destroy (GtkObject *object)
927 GtkFontSelection *fontsel;
929 g_return_if_fail (object != NULL);
930 g_return_if_fail (GTK_IS_FONT_SELECTION (object));
932 fontsel = GTK_FONT_SELECTION (object);
934 /* All we have to do is unref the font, if we have one. */
936 gdk_font_unref (fontsel->font);
938 if (GTK_OBJECT_CLASS (font_selection_parent_class)->destroy)
939 (* GTK_OBJECT_CLASS (font_selection_parent_class)->destroy) (object);
943 /* This is called when the clist is exposed. Here we scroll to the current
944 font if necessary. */
946 gtk_font_selection_expose_list (GtkWidget *widget,
947 GdkEventExpose *event,
950 GtkFontSelection *fontsel;
956 g_message("In expose_list\n");
958 fontsel = GTK_FONT_SELECTION(data);
960 font_info = fontsel_info->font_info;
962 /* Try to scroll the font family clist to the selected item */
963 selection = GTK_CLIST(fontsel->font_clist)->selection;
966 index = GPOINTER_TO_INT (selection->data);
967 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_clist), index)
968 != GTK_VISIBILITY_FULL)
969 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), index, -1, 0.5, 0);
972 /* Try to scroll the font style clist to the selected item */
973 selection = GTK_CLIST(fontsel->font_style_clist)->selection;
976 index = GPOINTER_TO_INT (selection->data);
977 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_style_clist), index)
978 != GTK_VISIBILITY_FULL)
979 gtk_clist_moveto(GTK_CLIST(fontsel->font_style_clist), index, -1,
983 /* Try to scroll the font size clist to the selected item */
984 selection = GTK_CLIST(fontsel->size_clist)->selection;
987 index = GPOINTER_TO_INT (selection->data);
988 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->size_clist), index)
989 != GTK_VISIBILITY_FULL)
990 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), index, -1, 0.5, 0);
995 /* This is called when the style clist is realized. We need to set any
996 charset rows to insensitive colours. */
998 gtk_font_selection_realize_list (GtkWidget *widget,
1001 GtkFontSelection *fontsel;
1003 GdkColor *inactive_fg, *inactive_bg;
1005 #ifdef FONTSEL_DEBUG
1006 g_message("In realize_list\n");
1008 fontsel = GTK_FONT_SELECTION (data);
1010 /* Set the colours for any charset rows to insensitive. */
1011 inactive_fg = &fontsel->font_style_clist->style->fg[GTK_STATE_INSENSITIVE];
1012 inactive_bg = &fontsel->font_style_clist->style->bg[GTK_STATE_INSENSITIVE];
1014 for (row = 0; row < GTK_CLIST (fontsel->font_style_clist)->rows; row++)
1016 if (GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_style_clist), row)) == -1)
1018 gtk_clist_set_foreground (GTK_CLIST (fontsel->font_style_clist),
1020 gtk_clist_set_background (GTK_CLIST (fontsel->font_style_clist),
1027 /* This is called when a family is selected in the list. */
1029 gtk_font_selection_select_font (GtkWidget *w,
1032 GdkEventButton *bevent,
1035 GtkFontSelection *fontsel;
1036 FontInfo *font_info;
1039 #ifdef FONTSEL_DEBUG
1040 g_message("In select_font\n");
1042 fontsel = GTK_FONT_SELECTION(data);
1043 font_info = fontsel_info->font_info;
1045 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1046 gtk_widget_grab_focus (w);
1048 row = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_clist), row));
1049 font = &font_info[row];
1050 gtk_entry_set_text(GTK_ENTRY(fontsel->font_entry), font->family);
1052 /* If it is already the current font, just return. */
1053 if (fontsel->font_index == row)
1056 fontsel->font_index = row;
1057 gtk_font_selection_show_available_styles (fontsel);
1058 gtk_font_selection_select_best_style (fontsel, TRUE);
1063 gtk_font_selection_on_clist_key_press (GtkWidget *clist,
1065 GtkFontSelection *fontsel)
1067 #ifdef FONTSEL_DEBUG
1068 g_message("In on_clist_key_press\n");
1070 if (event->keyval == GDK_Up)
1071 return gtk_font_selection_select_next (fontsel, clist, -1);
1072 else if (event->keyval == GDK_Down)
1073 return gtk_font_selection_select_next (fontsel, clist, 1);
1080 gtk_font_selection_select_next (GtkFontSelection *fontsel,
1085 gint current_row, row;
1087 selection = GTK_CLIST(clist)->selection;
1090 current_row = GPOINTER_TO_INT (selection->data);
1092 /* Stop the normal clist key handler from being run. */
1093 gtk_signal_emit_stop_by_name (GTK_OBJECT (clist), "key_press_event");
1095 for (row = current_row + step;
1096 row >= 0 && row < GTK_CLIST(clist)->rows;
1099 /* If this is the style clist, make sure that the item is not a charset
1101 if (clist == fontsel->font_style_clist)
1102 if (GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(clist), row)) == -1)
1105 /* Now we've found the row to select. */
1106 if (gtk_clist_row_is_visible(GTK_CLIST(clist), row)
1107 != GTK_VISIBILITY_FULL)
1108 gtk_clist_moveto(GTK_CLIST(clist), row, -1, (step < 0) ? 0 : 1, 0);
1109 gtk_clist_select_row(GTK_CLIST(clist), row, 0);
1116 /* This fills the font style clist with all the possible style combinations
1117 for the current font family. */
1119 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
1123 gint style, tmpstyle, row;
1124 gint weight_index, slant_index, set_width_index, spacing_index;
1126 gchar *weight, *slant, *set_width, *spacing;
1127 gchar *charset = NULL;
1129 gchar buffer[XLFD_MAX_FIELD_LEN * 6 + 2];
1130 GdkColor *inactive_fg, *inactive_bg;
1131 gboolean show_charset;
1133 #ifdef FONTSEL_DEBUG
1134 g_message("In show_available_styles\n");
1136 font = &fontsel_info->font_info[fontsel->font_index];
1137 styles = &fontsel_info->font_styles[font->style_index];
1139 gtk_clist_freeze (GTK_CLIST(fontsel->font_style_clist));
1140 gtk_clist_clear (GTK_CLIST(fontsel->font_style_clist));
1142 /* First we mark all visible styles as not having been displayed yet,
1143 and check if every style has the same charset. If not then we will
1144 display the charset in the list before the styles. */
1145 show_charset = FALSE;
1147 for (style = 0; style < font->nstyles; style++)
1149 if (gtk_font_selection_style_visible(fontsel, font, style))
1151 styles[style].flags &= ~GTK_FONT_DISPLAYED;
1153 if (charset_index == -1)
1154 charset_index = styles[style].properties[CHARSET];
1155 else if (charset_index != styles[style].properties[CHARSET])
1156 show_charset = TRUE;
1159 styles[style].flags |= GTK_FONT_DISPLAYED;
1162 /* Step through the undisplayed styles, finding the next charset which
1163 hasn't been displayed yet. Then display the charset on one line, if
1164 necessary, and the visible styles indented beneath it. */
1165 inactive_fg = &fontsel->font_style_clist->style->fg[GTK_STATE_INSENSITIVE];
1166 inactive_bg = &fontsel->font_style_clist->style->bg[GTK_STATE_INSENSITIVE];
1168 for (style = 0; style < font->nstyles; style++)
1170 if (styles[style].flags & GTK_FONT_DISPLAYED)
1175 charset_index = styles[style].properties[CHARSET];
1176 charset = fontsel_info->properties[CHARSET] [charset_index];
1177 row = gtk_clist_append(GTK_CLIST(fontsel->font_style_clist),
1179 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_style_clist), row,
1181 if (GTK_WIDGET_REALIZED (fontsel->font_style_clist))
1183 gtk_clist_set_foreground(GTK_CLIST(fontsel->font_style_clist),
1185 gtk_clist_set_background(GTK_CLIST(fontsel->font_style_clist),
1190 for (tmpstyle = style; tmpstyle < font->nstyles; tmpstyle++)
1192 if (styles[tmpstyle].flags & GTK_FONT_DISPLAYED
1193 || charset_index != styles[tmpstyle].properties[CHARSET])
1196 styles[tmpstyle].flags |= GTK_FONT_DISPLAYED;
1198 weight_index = styles[tmpstyle].properties[WEIGHT];
1199 slant_index = styles[tmpstyle].properties[SLANT];
1200 set_width_index = styles[tmpstyle].properties[SET_WIDTH];
1201 spacing_index = styles[tmpstyle].properties[SPACING];
1202 weight = fontsel_info->properties[WEIGHT] [weight_index];
1203 slant = fontsel_info->properties[SLANT] [slant_index];
1204 set_width = fontsel_info->properties[SET_WIDTH][set_width_index];
1205 spacing = fontsel_info->properties[SPACING] [spacing_index];
1207 /* Convert '(nil)' weights to 'regular', since it looks nicer. */
1208 if (!g_strcasecmp(weight, "(nil)")) weight = _("regular");
1210 /* We don't show default values or (nil) in the other properties. */
1211 if (!g_strcasecmp(slant, "r")) slant = NULL;
1212 else if (!g_strcasecmp(slant, "(nil)")) slant = NULL;
1213 else if (!g_strcasecmp(slant, "i")) slant = _("italic");
1214 else if (!g_strcasecmp(slant, "o")) slant = _("oblique");
1215 else if (!g_strcasecmp(slant, "ri")) slant = _("reverse italic");
1216 else if (!g_strcasecmp(slant, "ro")) slant = _("reverse oblique");
1217 else if (!g_strcasecmp(slant, "ot")) slant = _("other");
1219 if (!g_strcasecmp(set_width, "normal")) set_width = NULL;
1220 else if (!g_strcasecmp(set_width, "(nil)")) set_width = NULL;
1222 if (!g_strcasecmp(spacing, "p")) spacing = NULL;
1223 else if (!g_strcasecmp(spacing, "(nil)")) spacing = NULL;
1224 else if (!g_strcasecmp(spacing, "m")) spacing = _("[M]");
1225 else if (!g_strcasecmp(spacing, "c")) spacing = _("[C]");
1227 /* Add the strings together, making sure there is 1 space between
1229 strcpy(buffer, weight);
1232 strcat(buffer, " ");
1233 strcat(buffer, slant);
1237 strcat(buffer, " ");
1238 strcat(buffer, set_width);
1242 strcat(buffer, " ");
1243 strcat(buffer, spacing);
1247 row = gtk_clist_append(GTK_CLIST(fontsel->font_style_clist),
1250 gtk_clist_set_shift(GTK_CLIST(fontsel->font_style_clist), row, 0,
1252 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_style_clist), row,
1253 GINT_TO_POINTER (tmpstyle));
1257 gtk_clist_thaw (GTK_CLIST(fontsel->font_style_clist));
1261 /* This selects a style when the user selects a font. It just uses the first
1262 available style at present. I was thinking of trying to maintain the
1263 selected style, e.g. bold italic, when the user selects different fonts.
1264 However, the interface is so easy to use now I'm not sure it's worth it.
1265 Note: This will load a font. */
1267 gtk_font_selection_select_best_style(GtkFontSelection *fontsel,
1272 gint row, prop, style, matched;
1273 gint best_matched = -1, best_style = -1, best_row = -1;
1275 #ifdef FONTSEL_DEBUG
1276 g_message("In select_best_style\n");
1278 font = &fontsel_info->font_info[fontsel->font_index];
1279 styles = &fontsel_info->font_styles[font->style_index];
1281 for (row = 0; row < GTK_CLIST(fontsel->font_style_clist)->rows; row++)
1283 style = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_style_clist), row));
1284 /* Skip charset rows. */
1288 /* If we just want the first style, we've got it. */
1297 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1299 if (fontsel->property_values[prop] == styles[style].properties[prop])
1302 if (matched > best_matched)
1304 best_matched = matched;
1309 g_return_if_fail (best_style != -1);
1310 g_return_if_fail (best_row != -1);
1312 fontsel->style = best_style;
1314 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1315 fontsel->property_values[prop] = styles[fontsel->style].properties[prop];
1317 gtk_clist_select_row(GTK_CLIST(fontsel->font_style_clist), best_row, 0);
1318 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_style_clist), best_row)
1319 != GTK_VISIBILITY_FULL)
1320 gtk_clist_moveto(GTK_CLIST(fontsel->font_style_clist), best_row, -1,
1322 gtk_font_selection_show_available_sizes (fontsel);
1323 gtk_font_selection_select_best_size (fontsel);
1327 /* This is called when a style is selected in the list. */
1329 gtk_font_selection_select_style (GtkWidget *w,
1332 GdkEventButton *bevent,
1335 GtkFontSelection *fontsel;
1336 FontInfo *font_info;
1342 #ifdef FONTSEL_DEBUG
1343 g_message("In select_style\n");
1345 fontsel = GTK_FONT_SELECTION(data);
1346 font_info = fontsel_info->font_info;
1347 font = &font_info[fontsel->font_index];
1348 styles = &fontsel_info->font_styles[font->style_index];
1350 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1351 gtk_widget_grab_focus (w);
1353 /* The style index is stored in the row data, so we just need to copy
1354 the style values into the fontsel and reload the font. */
1355 style = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(fontsel->font_style_clist), row));
1357 /* Don't allow selection of charset rows. */
1360 gtk_clist_unselect_row(GTK_CLIST(fontsel->font_style_clist), row, 0);
1364 gtk_clist_get_text(GTK_CLIST(fontsel->font_style_clist), row, 0, &text);
1365 gtk_entry_set_text(GTK_ENTRY(fontsel->font_style_entry), text);
1367 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1368 fontsel->property_values[prop] = styles[style].properties[prop];
1370 if (fontsel->style == style)
1373 fontsel->style = style;
1374 gtk_font_selection_show_available_sizes (fontsel);
1375 gtk_font_selection_select_best_size (fontsel);
1379 /* This shows all the available sizes in the size clist, according to the
1380 current metric and the current font & style. */
1382 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel)
1385 FontStyle *styles, *style;
1386 const guint16 *standard_sizes;
1387 guint16 *bitmapped_sizes, bitmap_size;
1388 gint nstandard_sizes, nbitmapped_sizes;
1389 gchar buffer[16], *size;
1390 gfloat bitmap_size_float;
1394 #ifdef FONTSEL_DEBUG
1395 g_message("In show_available_sizes\n");
1397 font = &fontsel_info->font_info[fontsel->font_index];
1398 styles = &fontsel_info->font_styles[font->style_index];
1399 style = &styles[fontsel->style];
1401 standard_sizes = font_sizes;
1402 nstandard_sizes = sizeof(font_sizes) / sizeof(font_sizes[0]);
1403 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1405 bitmapped_sizes = &fontsel_info->point_sizes[style->point_sizes_index];
1406 nbitmapped_sizes = style->npoint_sizes;
1410 bitmapped_sizes = &fontsel_info->pixel_sizes[style->pixel_sizes_index];
1411 nbitmapped_sizes = style->npixel_sizes;
1414 /* Only show the standard sizes if a scalable font is available. */
1415 type_filter = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
1416 & fontsel->filters[GTK_FONT_FILTER_USER].font_type;
1418 if (!((style->flags & GTK_FONT_SCALABLE_BITMAP
1419 && type_filter & GTK_FONT_SCALABLE_BITMAP)
1420 || (style->flags & GTK_FONT_SCALABLE
1421 && type_filter & GTK_FONT_SCALABLE)))
1422 nstandard_sizes = 0;
1424 gtk_clist_freeze (GTK_CLIST(fontsel->size_clist));
1425 gtk_clist_clear (GTK_CLIST(fontsel->size_clist));
1427 /* Interleave the standard sizes with the bitmapped sizes so we get a list
1428 of ascending sizes. If the metric is points, we have to convert the
1429 decipoints to points. */
1430 while (nstandard_sizes || nbitmapped_sizes)
1433 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1435 if (*bitmapped_sizes % 10 != 0)
1437 bitmap_size = *bitmapped_sizes / 10;
1438 bitmap_size_float = *bitmapped_sizes / 10;
1442 bitmap_size = *bitmapped_sizes;
1443 bitmap_size_float = *bitmapped_sizes;
1446 if (can_match && nstandard_sizes && nbitmapped_sizes
1447 && *standard_sizes == bitmap_size)
1449 sprintf(buffer, "%i *", *standard_sizes);
1455 else if (nstandard_sizes
1456 && (!nbitmapped_sizes
1457 || (gfloat)*standard_sizes < bitmap_size_float))
1459 sprintf(buffer, "%i", *standard_sizes);
1465 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1467 if (*bitmapped_sizes % 10 == 0)
1468 sprintf(buffer, "%i *", *bitmapped_sizes / 10);
1470 sprintf(buffer, "%i.%i *", *bitmapped_sizes / 10,
1471 *bitmapped_sizes % 10);
1475 sprintf(buffer, "%i *", *bitmapped_sizes);
1481 gtk_clist_append(GTK_CLIST(fontsel->size_clist), &size);
1483 gtk_clist_thaw (GTK_CLIST(fontsel->size_clist));
1487 /* If the user hits return in the font size entry, we change to the new font
1490 gtk_font_selection_size_key_press (GtkWidget *w,
1494 GtkFontSelection *fontsel;
1496 gfloat new_size_float;
1499 #ifdef FONTSEL_DEBUG
1500 g_message("In size_key_press\n");
1502 fontsel = GTK_FONT_SELECTION(data);
1504 if (event->keyval == GDK_Return)
1506 text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1507 if (fontsel->metric == GTK_FONT_METRIC_PIXELS)
1509 new_size = atoi (text);
1515 new_size_float = atof (text) * 10;
1516 new_size = (gint) new_size_float;
1521 /* Remember that this size was set explicitly. */
1522 fontsel->selected_size = new_size;
1524 /* Check if the font size has changed, and return if it hasn't. */
1525 if (fontsel->size == new_size)
1528 fontsel->size = new_size;
1529 gtk_font_selection_select_best_size (fontsel);
1537 /* This tries to select the closest size to the current size, though it
1538 may have to change the size if only unscaled bitmaps are available.
1539 Note: this will load a font. */
1541 gtk_font_selection_select_best_size(GtkFontSelection *fontsel)
1544 FontStyle *styles, *style;
1546 gint row, best_row = 0, size, size_fraction, best_size = 0, nmatched;
1547 gboolean found = FALSE;
1552 #ifdef FONTSEL_DEBUG
1553 g_message("In select_best_size\n");
1555 font = &fontsel_info->font_info[fontsel->font_index];
1556 styles = &fontsel_info->font_styles[font->style_index];
1557 style = &styles[fontsel->style];
1559 /* Find the closest size available in the size clist. If the exact size is
1560 in the list set found to TRUE. */
1561 for (row = 0; row < GTK_CLIST(fontsel->size_clist)->rows; row++)
1563 gtk_clist_get_text(GTK_CLIST(fontsel->size_clist), row, 0, &text);
1564 nmatched = sscanf(text, "%i.%i", &size, &size_fraction);
1565 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1569 size += size_fraction;
1572 if (size == fontsel->selected_size)
1579 else if (best_size == 0
1580 || abs(size - fontsel->selected_size)
1581 < (abs(best_size - fontsel->selected_size)))
1588 /* If we aren't scaling bitmapped fonts and this is a bitmapped font, we
1589 need to use the closest size found. */
1590 type_filter = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
1591 & fontsel->filters[GTK_FONT_FILTER_USER].font_type;
1593 if (!((style->flags & GTK_FONT_SCALABLE_BITMAP
1594 && type_filter & GTK_FONT_SCALABLE_BITMAP)
1595 || (style->flags & GTK_FONT_SCALABLE
1596 && type_filter & GTK_FONT_SCALABLE)))
1601 fontsel->size = best_size;
1602 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), best_row, -1, 0.5, 0);
1603 gtk_clist_select_row(GTK_CLIST(fontsel->size_clist), best_row, 0);
1607 fontsel->size = fontsel->selected_size;
1608 selection = GTK_CLIST(fontsel->size_clist)->selection;
1610 gtk_clist_unselect_row(GTK_CLIST(fontsel->size_clist),
1611 GPOINTER_TO_INT (selection->data), 0);
1612 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), best_row, -1, 0.5, 0);
1614 /* Show the size in the size entry. */
1615 if (fontsel->metric == GTK_FONT_METRIC_PIXELS)
1616 sprintf(buffer, "%i", fontsel->size);
1619 if (fontsel->size % 10 == 0)
1620 sprintf(buffer, "%i", fontsel->size / 10);
1622 sprintf(buffer, "%i.%i", fontsel->size / 10, fontsel->size % 10);
1624 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
1626 gtk_font_selection_load_font (fontsel);
1630 /* This is called when a size is selected in the list. */
1632 gtk_font_selection_select_size (GtkWidget *w,
1635 GdkEventButton *bevent,
1638 GtkFontSelection *fontsel;
1644 #ifdef FONTSEL_DEBUG
1645 g_message("In select_size\n");
1647 fontsel = GTK_FONT_SELECTION(data);
1649 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1650 gtk_widget_grab_focus (w);
1652 /* Copy the size from the clist to the size entry, but without the bitmapped
1654 gtk_clist_get_text(GTK_CLIST(fontsel->size_clist), row, 0, &text);
1656 while (i < 15 && (text[i] == '.' || (text[i] >= '0' && text[i] <= '9')))
1658 buffer[i] = text[i];
1662 gtk_entry_set_text(GTK_ENTRY(fontsel->size_entry), buffer);
1664 /* Check if the font size has changed, and return if it hasn't. */
1665 new_size = atoi(text);
1666 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1669 if (fontsel->size == new_size)
1672 /* If the size was selected by the user we set the selected_size. */
1673 fontsel->selected_size = new_size;
1675 fontsel->size = new_size;
1676 gtk_font_selection_load_font (fontsel);
1680 /* This is called when the pixels or points radio buttons are pressed. */
1682 gtk_font_selection_metric_callback (GtkWidget *w,
1685 GtkFontSelection *fontsel = GTK_FONT_SELECTION(data);
1687 #ifdef FONTSEL_DEBUG
1688 g_message("In metric_callback\n");
1690 if (GTK_TOGGLE_BUTTON(fontsel->pixels_button)->active)
1692 if (fontsel->metric == GTK_FONT_METRIC_PIXELS)
1694 fontsel->metric = GTK_FONT_METRIC_PIXELS;
1695 fontsel->size = (fontsel->size + 5) / 10;
1696 fontsel->selected_size = (fontsel->selected_size + 5) / 10;
1700 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1702 fontsel->metric = GTK_FONT_METRIC_POINTS;
1703 fontsel->size *= 10;
1704 fontsel->selected_size *= 10;
1706 if (fontsel->font_index != -1)
1708 gtk_font_selection_show_available_sizes (fontsel);
1709 gtk_font_selection_select_best_size (fontsel);
1714 /* This searches the given property table and returns the index of the given
1715 string, or 0, which is the wildcard '*' index, if it's not found. */
1717 gtk_font_selection_field_to_index (gchar **table,
1723 for (i = 0; i < ntable; i++)
1724 if (strcmp (field, table[i]) == 0)
1732 /* This attempts to load the current font, and returns TRUE if it succeeds. */
1734 gtk_font_selection_load_font (GtkFontSelection *fontsel)
1737 gchar *fontname, *label_text;
1740 gdk_font_unref (fontsel->font);
1741 fontsel->font = NULL;
1743 /* If no family has been selected yet, just return FALSE. */
1744 if (fontsel->font_index == -1)
1747 fontname = gtk_font_selection_get_font_name (fontsel);
1750 #ifdef FONTSEL_DEBUG
1751 g_message("Loading: %s\n", fontname);
1753 font = gdk_font_load (fontname);
1758 fontsel->font = font;
1759 /* Make sure the message label is empty, but don't change it unless
1760 it's necessary as it results in a resize of the whole window! */
1761 gtk_label_get(GTK_LABEL(fontsel->message_label), &label_text);
1762 if (strcmp(label_text, ""))
1763 gtk_label_set_text(GTK_LABEL(fontsel->message_label), "");
1764 gtk_font_selection_update_preview (fontsel);
1769 gtk_label_set_text(GTK_LABEL(fontsel->message_label),
1770 _("The selected font is not available."));
1775 gtk_label_set_text(GTK_LABEL(fontsel->message_label),
1776 _("The selected font is not a valid font."));
1783 /* This sets the font in the preview entry to the selected font, and tries to
1784 make sure that the preview entry is a reasonable size, i.e. so that the
1785 text can be seen with a bit of space to spare. But it tries to avoid
1786 resizing the entry every time the font changes.
1787 This also used to shrink the preview if the font size was decreased, but
1788 that made it awkward if the user wanted to resize the window themself. */
1790 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1792 GtkWidget *preview_entry;
1794 gint text_height, new_height;
1798 #ifdef FONTSEL_DEBUG
1799 g_message("In update_preview\n");
1801 style = gtk_style_new ();
1802 gdk_font_unref (style->font);
1803 style->font = fontsel->font;
1804 gdk_font_ref (style->font);
1806 preview_entry = fontsel->preview_entry;
1807 gtk_widget_set_style (preview_entry, style);
1808 gtk_style_unref(style);
1810 text_height = preview_entry->style->font->ascent
1811 + preview_entry->style->font->descent;
1812 /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1813 new_height = text_height + 20;
1814 if (new_height < INITIAL_PREVIEW_HEIGHT)
1815 new_height = INITIAL_PREVIEW_HEIGHT;
1816 if (new_height > MAX_PREVIEW_HEIGHT)
1817 new_height = MAX_PREVIEW_HEIGHT;
1819 if ((preview_entry->requisition.height < text_height + 10)
1820 || (preview_entry->requisition.height > text_height + 40))
1821 gtk_widget_set_usize(preview_entry, -1, new_height);
1823 /* This sets the preview text, if it hasn't been set already. */
1824 text = gtk_entry_get_text(GTK_ENTRY(fontsel->preview_entry));
1825 if (strlen(text) == 0)
1826 gtk_entry_set_text(GTK_ENTRY(fontsel->preview_entry), PREVIEW_TEXT);
1827 gtk_entry_set_position(GTK_ENTRY(fontsel->preview_entry), 0);
1829 /* If this is a 2-byte font display a message to say it may not be
1830 displayed properly. */
1831 xfs = GDK_FONT_XFONT(fontsel->font);
1832 if (xfs->min_byte1 != 0 || xfs->max_byte1 != 0)
1833 gtk_label_set_text(GTK_LABEL(fontsel->message_label),
1834 _("This is a 2-byte font and may not be displayed correctly."));
1839 gtk_font_selection_switch_page (GtkWidget *w,
1840 GtkNotebookPage *page,
1844 GtkFontSelection *fontsel = GTK_FONT_SELECTION(data);
1846 /* This function strangely gets called when the window is destroyed,
1847 so we check here to see if the notebook is visible. */
1848 if (!GTK_WIDGET_VISIBLE(w))
1852 gtk_font_selection_update_filter(fontsel);
1853 else if (page_num == 1)
1854 gtk_font_selection_show_font_info(fontsel);
1859 gtk_font_selection_show_font_info (GtkFontSelection *fontsel)
1861 Atom font_atom, atom;
1865 gchar field_buffer[XLFD_MAX_FIELD_LEN];
1868 gboolean shown_actual_fields = FALSE;
1870 fontname = gtk_font_selection_get_font_name(fontsel);
1871 gtk_entry_set_text(GTK_ENTRY(fontsel->requested_font_name),
1872 fontname ? fontname : "");
1874 gtk_clist_freeze (GTK_CLIST(fontsel->info_clist));
1875 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1878 field = gtk_font_selection_get_xlfd_field (fontname, i, field_buffer);
1883 if (i == XLFD_SLANT)
1884 field = gtk_font_selection_expand_slant_code(field);
1885 else if (i == XLFD_SPACING)
1886 field = gtk_font_selection_expand_spacing_code(field);
1888 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 1,
1889 field ? field : "");
1894 font_atom = XInternAtom(GDK_DISPLAY(), "FONT", True);
1895 if (font_atom != None)
1897 status = XGetFontProperty(GDK_FONT_XFONT(fontsel->font), font_atom,
1901 name = XGetAtomName(GDK_DISPLAY(), atom);
1902 gtk_entry_set_text(GTK_ENTRY(fontsel->actual_font_name), name);
1904 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1906 field = gtk_font_selection_get_xlfd_field (name, i,
1908 if (i == XLFD_SLANT)
1909 field = gtk_font_selection_expand_slant_code(field);
1910 else if (i == XLFD_SPACING)
1911 field = gtk_font_selection_expand_spacing_code(field);
1912 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 2,
1913 field ? field : "");
1915 shown_actual_fields = TRUE;
1920 if (!shown_actual_fields)
1922 gtk_entry_set_text(GTK_ENTRY(fontsel->actual_font_name), "");
1923 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1925 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 2,
1926 fontname ? _("(unknown)") : "");
1929 gtk_clist_thaw (GTK_CLIST(fontsel->info_clist));
1935 gtk_font_selection_expand_slant_code(gchar *slant)
1937 if (!g_strcasecmp(slant, "r")) return(_("roman"));
1938 else if (!g_strcasecmp(slant, "i")) return(_("italic"));
1939 else if (!g_strcasecmp(slant, "o")) return(_("oblique"));
1940 else if (!g_strcasecmp(slant, "ri")) return(_("reverse italic"));
1941 else if (!g_strcasecmp(slant, "ro")) return(_("reverse oblique"));
1942 else if (!g_strcasecmp(slant, "ot")) return(_("other"));
1947 gtk_font_selection_expand_spacing_code(gchar *spacing)
1949 if (!g_strcasecmp(spacing, "p")) return(_("proportional"));
1950 else if (!g_strcasecmp(spacing, "m")) return(_("monospaced"));
1951 else if (!g_strcasecmp(spacing, "c")) return(_("char cell"));
1956 /*****************************************************************************
1957 * These functions all deal with the Filter page and filtering the fonts.
1958 *****************************************************************************/
1960 /* This is called when an item is selected in one of the filter clists.
1961 We make sure that the first row of the clist, i.e. the wildcard '*', is
1962 selected if and only if none of the other items are selected.
1963 Also doesn't allow selections of values filtered out by base filter.
1964 We may need to be careful about triggering other signals. */
1966 gtk_font_selection_select_filter (GtkWidget *w,
1969 GdkEventButton *bevent,
1970 GtkFontSelection *fontsel)
1972 gint i, prop, index;
1976 for (i = 1; i < GTK_CLIST(w)->rows; i++)
1977 gtk_clist_unselect_row(GTK_CLIST(w), i, 0);
1981 /* Find out which property this is. */
1982 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
1983 if (fontsel->filter_clists[prop] == w)
1985 index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(w), row));
1986 if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_BASE,
1987 prop, index) == NOT_FILTERED)
1988 gtk_clist_unselect_row(GTK_CLIST(w), row, 0);
1990 gtk_clist_unselect_row(GTK_CLIST(w), 0, 0);
1995 /* Here a filter item is being deselected. If there are now no items selected
1996 we select the first '*' item, unless that it is the item being deselected,
1997 in which case we select all of the other items. This makes it easy to
1998 select all items in the list except one or two. */
2000 gtk_font_selection_unselect_filter (GtkWidget *w,
2003 GdkEventButton *bevent,
2004 GtkFontSelection *fontsel)
2006 gint i, prop, index;
2008 if (!GTK_CLIST(w)->selection)
2012 /* Find out which property this is. */
2013 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2014 if (fontsel->filter_clists[prop] == w)
2017 for (i = 1; i < GTK_CLIST(w)->rows; i++)
2019 index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(w),
2021 if (gtk_font_selection_filter_state (fontsel,
2022 GTK_FONT_FILTER_BASE,
2025 gtk_clist_select_row(GTK_CLIST(w), i, 0);
2030 gtk_clist_select_row(GTK_CLIST(w), 0, 0);
2036 /* This is called when the main notebook page is selected. It checks if the
2037 filter has changed, an if so it creates the filter settings, and filters the
2038 fonts shown. If an empty filter (all '*'s) is applied, then filtering is
2041 gtk_font_selection_update_filter (GtkFontSelection *fontsel)
2045 gboolean default_filter = TRUE, filter_changed = FALSE;
2046 gint prop, nselected, i, row, index;
2047 GtkFontFilter *filter = &fontsel->filters[GTK_FONT_FILTER_USER];
2048 gint base_font_type, user_font_type, new_font_type;
2050 #ifdef FONTSEL_DEBUG
2051 g_message("In update_filter\n");
2054 /* Check if the user filter has changed, and also if it is the default
2055 filter, i.e. bitmap & scalable fonts and all '*'s selected.
2056 We only look at the bits which are not already filtered out by the base
2057 filter, since that overrides the user filter. */
2058 base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
2060 user_font_type = fontsel->filters[GTK_FONT_FILTER_USER].font_type
2062 new_font_type = GTK_TOGGLE_BUTTON(fontsel->type_bitmaps_button)->active
2063 ? GTK_FONT_BITMAP : 0;
2064 new_font_type |= (GTK_TOGGLE_BUTTON(fontsel->type_scalable_button)->active
2065 ? GTK_FONT_SCALABLE : 0);
2066 new_font_type |= (GTK_TOGGLE_BUTTON(fontsel->type_scaled_bitmaps_button)->active ? GTK_FONT_SCALABLE_BITMAP : 0);
2067 new_font_type &= base_font_type;
2068 new_font_type |= (~base_font_type & user_font_type);
2069 if (new_font_type != (GTK_FONT_BITMAP | GTK_FONT_SCALABLE))
2070 default_filter = FALSE;
2072 if (new_font_type != user_font_type)
2073 filter_changed = TRUE;
2074 fontsel->filters[GTK_FONT_FILTER_USER].font_type = new_font_type;
2076 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2078 clist = fontsel->filter_clists[prop];
2079 selection = GTK_CLIST(clist)->selection;
2080 nselected = g_list_length(selection);
2081 if (nselected != 1 || GPOINTER_TO_INT (selection->data) != 0)
2083 default_filter = FALSE;
2085 if (filter->property_nfilters[prop] != nselected)
2086 filter_changed = TRUE;
2089 for (i = 0; i < nselected; i++)
2091 row = GPOINTER_TO_INT (selection->data);
2092 index = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (clist), row));
2093 if (filter->property_filters[prop][i] != index)
2094 filter_changed = TRUE;
2095 selection = selection->next;
2101 if (filter->property_nfilters[prop] != 0)
2102 filter_changed = TRUE;
2106 /* If the filter hasn't changed we just return. */
2107 if (!filter_changed)
2110 #ifdef FONTSEL_DEBUG
2111 g_message(" update_fonts: filter has changed\n");
2114 /* Free the old filter data and create the new arrays. */
2115 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2117 g_free(filter->property_filters[prop]);
2119 clist = fontsel->filter_clists[prop];
2120 selection = GTK_CLIST(clist)->selection;
2121 nselected = g_list_length(selection);
2122 if (nselected == 1 && GPOINTER_TO_INT (selection->data) == 0)
2124 filter->property_filters[prop] = NULL;
2125 filter->property_nfilters[prop] = 0;
2129 filter->property_filters[prop] = g_new(guint16, nselected);
2130 filter->property_nfilters[prop] = nselected;
2131 for (i = 0; i < nselected; i++)
2133 row = GPOINTER_TO_INT (selection->data);
2134 index = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (clist), row));
2135 filter->property_filters[prop][i] = index;
2136 selection = selection->next;
2141 /* Set the 'Reset Filter' button sensitive if a filter is in effect, and
2142 also set the label above the font list to show this as well. */
2145 gtk_widget_set_sensitive(fontsel->filter_button, FALSE);
2146 gtk_label_set_text(GTK_LABEL(fontsel->font_label), _("Font:"));
2150 gtk_widget_set_sensitive(fontsel->filter_button, TRUE);
2151 gtk_label_set_text(GTK_LABEL(fontsel->font_label), _("Font: (Filter Applied)"));
2153 gtk_font_selection_show_available_fonts(fontsel);
2157 /* This shows all the available fonts in the font clist. */
2159 gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
2161 FontInfo *font_info, *font;
2162 GtkFontFilter *filter;
2163 gint nfonts, i, j, k, row, style, font_row = -1;
2164 gchar font_buffer[XLFD_MAX_FIELD_LEN * 2 + 4];
2166 gboolean matched, matched_style;
2168 #ifdef FONTSEL_DEBUG
2169 g_message("In show_available_fonts\n");
2171 font_info = fontsel_info->font_info;
2172 nfonts = fontsel_info->nfonts;
2174 /* Filter the list of fonts. */
2175 gtk_clist_freeze (GTK_CLIST(fontsel->font_clist));
2176 gtk_clist_clear (GTK_CLIST(fontsel->font_clist));
2177 for (i = 0; i < nfonts; i++)
2179 font = &font_info[i];
2181 /* Check if the foundry passes through all filters. */
2183 for (k = 0; k < GTK_NUM_FONT_FILTERS; k++)
2185 filter = &fontsel->filters[k];
2187 if (filter->property_nfilters[FOUNDRY] != 0)
2190 for (j = 0; j < filter->property_nfilters[FOUNDRY]; j++)
2192 if (font->foundry == filter->property_filters[FOUNDRY][j])
2207 /* Now check if the other properties are matched in at least one style.*/
2208 matched_style = FALSE;
2209 for (style = 0; style < font->nstyles; style++)
2211 if (gtk_font_selection_style_visible(fontsel, font, style))
2213 matched_style = TRUE;
2220 /* Insert the font in the clist. */
2221 if ((i > 0 && font->family == font_info[i-1].family)
2222 || (i < nfonts - 1 && font->family == font_info[i+1].family))
2224 sprintf(font_buffer, "%s (%s)", font->family,
2225 fontsel_info->properties[FOUNDRY][font->foundry]);
2226 font_item = font_buffer;
2227 row = gtk_clist_append(GTK_CLIST(fontsel->font_clist), &font_item);
2231 row = gtk_clist_append(GTK_CLIST(fontsel->font_clist),
2234 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_clist), row,
2235 GINT_TO_POINTER (i));
2236 if (fontsel->font_index == i)
2239 gtk_clist_thaw (GTK_CLIST(fontsel->font_clist));
2241 /* If the currently-selected font isn't in the new list, reset the
2245 fontsel->font_index = -1;
2247 gdk_font_unref(fontsel->font);
2248 fontsel->font = NULL;
2249 gtk_entry_set_text(GTK_ENTRY(fontsel->font_entry), "");
2250 gtk_clist_clear (GTK_CLIST(fontsel->font_style_clist));
2251 gtk_entry_set_text(GTK_ENTRY(fontsel->font_style_entry), "");
2255 gtk_clist_select_row(GTK_CLIST(fontsel->font_clist), font_row, 0);
2256 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_clist), font_row)
2257 != GTK_VISIBILITY_FULL)
2258 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), font_row, -1, 0.5, 0);
2260 gtk_font_selection_show_available_styles (fontsel);
2261 gtk_font_selection_select_best_style (fontsel, FALSE);
2265 /* Returns TRUE if the style is not currently filtered out. */
2267 gtk_font_selection_style_visible(GtkFontSelection *fontsel,
2271 FontStyle *styles, *style;
2272 GtkFontFilter *filter;
2278 styles = &fontsel_info->font_styles[font->style_index];
2279 style = &styles[style_index];
2281 /* Check if font_type of style is filtered. */
2282 type_filter = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
2283 & fontsel->filters[GTK_FONT_FILTER_USER].font_type;
2284 if (!(style->flags & type_filter))
2287 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2289 value = style->properties[prop];
2291 /* Check each filter. */
2292 for (i = 0; i < GTK_NUM_FONT_FILTERS; i++)
2294 filter = &fontsel->filters[i];
2296 if (filter->property_nfilters[prop] != 0)
2299 for (j = 0; j < filter->property_nfilters[prop]; j++)
2301 if (value == filter->property_filters[prop][j])
2316 /* This resets the font type to bitmap or scalable, and sets all the filter
2317 clists to the wildcard '*' options. */
2319 gtk_font_selection_reset_filter (GtkWidget *w,
2320 GtkFontSelection *fontsel)
2322 gint prop, base_font_type;
2324 fontsel->filters[GTK_FONT_FILTER_USER].font_type = GTK_FONT_BITMAP
2325 | GTK_FONT_SCALABLE;
2327 base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type;
2328 if (base_font_type & GTK_FONT_BITMAP)
2329 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), TRUE);
2330 if (base_font_type & GTK_FONT_SCALABLE)
2331 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), TRUE);
2332 if (base_font_type & GTK_FONT_SCALABLE_BITMAP)
2333 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), FALSE);
2335 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2336 gtk_clist_select_row(GTK_CLIST(fontsel->filter_clists[prop]), 0, 0);
2340 /* This clears the filter, showing all fonts and styles again. */
2342 gtk_font_selection_on_clear_filter (GtkWidget *w,
2343 GtkFontSelection *fontsel)
2345 gtk_font_selection_clear_filter(fontsel);
2349 /* This resets the user filter, showing all fonts and styles which pass the
2350 base filter again. Note that the font type is set to bitmaps and scalable
2351 fonts - scaled bitmaps are not shown. */
2353 gtk_font_selection_clear_filter (GtkFontSelection *fontsel)
2355 GtkFontFilter *filter;
2358 #ifdef FONTSEL_DEBUG
2359 g_message("In clear_filter\n");
2361 /* Clear the filter data. */
2362 filter = &fontsel->filters[GTK_FONT_FILTER_USER];
2363 filter->font_type = GTK_FONT_BITMAP | GTK_FONT_SCALABLE;
2364 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2366 g_free(filter->property_filters[prop]);
2367 filter->property_filters[prop] = NULL;
2368 filter->property_nfilters[prop] = 0;
2371 /* Select all the '*'s on the filter page. */
2372 gtk_font_selection_reset_filter(NULL, fontsel);
2374 /* Update the main notebook page. */
2375 gtk_widget_set_sensitive(fontsel->filter_button, FALSE);
2376 gtk_label_set_text(GTK_LABEL(fontsel->font_label), _("Font:"));
2378 gtk_font_selection_show_available_fonts(fontsel);
2383 gtk_font_selection_set_filter (GtkFontSelection *fontsel,
2384 GtkFontFilterType filter_type,
2385 GtkFontType font_type,
2393 GtkFontFilter *filter;
2394 gchar **filter_strings [GTK_NUM_FONT_PROPERTIES];
2395 gchar *filter_string;
2396 gchar *property, *property_alt;
2397 gint prop, nfilters, i, j, num_found;
2398 gint base_font_type, user_font_type;
2399 gboolean filter_set;
2401 /* Put them into an array so we can use a simple loop. */
2402 filter_strings[FOUNDRY] = foundries;
2403 filter_strings[WEIGHT] = weights;
2404 filter_strings[SLANT] = slants;
2405 filter_strings[SET_WIDTH] = setwidths;
2406 filter_strings[SPACING] = spacings;
2407 filter_strings[CHARSET] = charsets;
2409 filter = &fontsel->filters[filter_type];
2410 filter->font_type = font_type;
2412 /* Free the old filter data, and insert the new. */
2413 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2415 g_free(filter->property_filters[prop]);
2416 filter->property_filters[prop] = NULL;
2417 filter->property_nfilters[prop] = 0;
2419 if (filter_strings[prop])
2421 /* Count how many items in the new array. */
2423 while (filter_strings[prop][nfilters])
2426 filter->property_filters[prop] = g_new(guint16, nfilters);
2427 filter->property_nfilters[prop] = 0;
2429 /* Now convert the strings to property indices. */
2431 for (i = 0; i < nfilters; i++)
2433 filter_string = filter_strings[prop][i];
2434 for (j = 0; j < fontsel_info->nproperties[prop]; j++)
2436 property = fontsel_info->properties[prop][j];
2437 property_alt = NULL;
2439 property_alt = gtk_font_selection_expand_slant_code(property);
2440 else if (prop == SPACING)
2441 property_alt = gtk_font_selection_expand_spacing_code(property);
2442 if (!strcmp (filter_string, property)
2443 || (property_alt && !strcmp (filter_string, property_alt)))
2445 filter->property_filters[prop][num_found] = j;
2451 filter->property_nfilters[prop] = num_found;
2455 /* Now set the clists on the filter page according to the new filter. */
2456 gtk_font_selection_update_filter_lists (fontsel);
2458 if (filter_type == GTK_FONT_FILTER_BASE)
2460 user_font_type = fontsel->filters[GTK_FONT_FILTER_USER].font_type;
2461 if (font_type & GTK_FONT_BITMAP)
2463 gtk_widget_set_sensitive (fontsel->type_bitmaps_button, TRUE);
2464 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), user_font_type & GTK_FONT_BITMAP);
2468 gtk_widget_set_sensitive (fontsel->type_bitmaps_button, FALSE);
2469 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), FALSE);
2472 if (font_type & GTK_FONT_SCALABLE)
2474 gtk_widget_set_sensitive (fontsel->type_scalable_button, TRUE);
2475 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), user_font_type & GTK_FONT_SCALABLE);
2479 gtk_widget_set_sensitive (fontsel->type_scalable_button, FALSE);
2480 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), FALSE);
2483 if (font_type & GTK_FONT_SCALABLE_BITMAP)
2485 gtk_widget_set_sensitive (fontsel->type_scaled_bitmaps_button, TRUE);
2486 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), user_font_type & GTK_FONT_SCALABLE_BITMAP);
2490 gtk_widget_set_sensitive (fontsel->type_scaled_bitmaps_button, FALSE);
2491 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), FALSE);
2496 base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type;
2497 if (base_font_type & GTK_FONT_BITMAP)
2498 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), font_type & GTK_FONT_BITMAP);
2500 if (base_font_type & GTK_FONT_SCALABLE)
2501 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), font_type & GTK_FONT_SCALABLE);
2503 if (base_font_type & GTK_FONT_SCALABLE_BITMAP)
2504 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), font_type & GTK_FONT_SCALABLE_BITMAP);
2506 /* If the user filter is not the default, make the 'Reset Filter' button
2509 if (font_type != (GTK_FONT_BITMAP | GTK_FONT_SCALABLE))
2511 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2513 if (filter->property_nfilters[prop] != 0)
2517 gtk_widget_set_sensitive (fontsel->filter_button, TRUE);
2520 gtk_font_selection_show_available_fonts (fontsel);
2524 /* This sets the colour of each property in the filter clists according to
2525 the base filter. i.e. Filtered properties are shown as insensitive. */
2527 gtk_font_selection_update_filter_lists (GtkFontSelection *fontsel)
2530 GdkColor *inactive_fg, *inactive_bg, *fg, *bg;
2531 gint prop, row, index;
2533 /* We have to make sure the clist is realized to use the colours. */
2534 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2536 clist = fontsel->filter_clists[prop];
2537 gtk_widget_realize (clist);
2538 inactive_fg = &clist->style->fg[GTK_STATE_INSENSITIVE];
2539 inactive_bg = &clist->style->bg[GTK_STATE_INSENSITIVE];
2540 for (row = 1; row < GTK_CLIST(clist)->rows; row++)
2542 index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(clist),
2544 /* Set the colour according to the base filter. */
2545 if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_BASE,
2546 prop, index) == NOT_FILTERED)
2556 gtk_clist_set_foreground(GTK_CLIST(clist), row, fg);
2557 gtk_clist_set_background(GTK_CLIST(clist), row, bg);
2559 /* Set the selection state according to the user filter. */
2560 if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_USER,
2561 prop, index) == FILTERED
2563 gtk_clist_select_row (GTK_CLIST (clist), row, 0);
2565 gtk_clist_unselect_row (GTK_CLIST (clist), row, 0);
2571 /* Returns whether a property value is in the filter or not, or if the
2572 property has no filter set. */
2573 static GtkFontPropertyFilterState
2574 gtk_font_selection_filter_state (GtkFontSelection *fontsel,
2575 GtkFontFilterType filter_type,
2579 GtkFontFilter *filter;
2582 filter = &fontsel->filters[filter_type];
2583 if (filter->property_nfilters[property] == 0)
2586 for (i = 0; i < filter->property_nfilters[property]; i++)
2588 if (filter->property_filters[property][i] == index)
2591 return NOT_FILTERED;
2595 /*****************************************************************************
2596 * These functions all deal with creating the main class arrays containing
2597 * the data about all available fonts.
2598 *****************************************************************************/
2600 gtk_font_selection_get_fonts (void)
2607 gint i, prop, style, size;
2608 gint npixel_sizes = 0, npoint_sizes = 0;
2610 FontStyle *current_style, *prev_style, *tmp_style;
2611 gboolean matched_style, found_size;
2612 gint pixels, points, res_x, res_y;
2613 gchar field_buffer[XLFD_MAX_FIELD_LEN];
2616 guint16 *pixel_sizes, *point_sizes, *tmp_sizes;
2618 fontsel_info = g_new (GtkFontSelInfo, 1);
2620 /* Get a maximum of MAX_FONTS fontnames from the X server.
2621 Use "-*" as the pattern rather than "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" since
2622 the latter may result in fonts being returned which don't actually exist.
2623 xlsfonts also uses "*" so I think it's OK. "-*" gets rid of aliases. */
2624 xfontnames = XListFonts (GDK_DISPLAY(), "-*", MAX_FONTS, &num_fonts);
2625 /* Output a warning if we actually get MAX_FONTS fonts. */
2626 if (num_fonts == MAX_FONTS)
2627 g_warning(_("MAX_FONTS exceeded. Some fonts may be missing."));
2629 /* The maximum size of all these tables is the number of font names
2630 returned. We realloc them later when we know exactly how many
2631 unique entries there are. */
2632 fontsel_info->font_info = g_new (FontInfo, num_fonts);
2633 fontsel_info->font_styles = g_new (FontStyle, num_fonts);
2634 fontsel_info->pixel_sizes = g_new (guint16, num_fonts);
2635 fontsel_info->point_sizes = g_new (guint16, num_fonts);
2637 fontnames = g_new (GSList*, num_fonts);
2639 /* Create the initial arrays for the property value strings, though they
2640 may be realloc'ed later. Put the wildcard '*' in the first elements. */
2641 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2643 fontsel_info->properties[prop] = g_new(gchar*, PROPERTY_ARRAY_INCREMENT);
2644 fontsel_info->space_allocated[prop] = PROPERTY_ARRAY_INCREMENT;
2645 fontsel_info->nproperties[prop] = 1;
2646 fontsel_info->properties[prop][0] = "*";
2650 /* Insert the font families into the main table, sorted by family and
2651 foundry (fonts with different foundries are placed in seaparate FontInfos.
2652 All fontnames in each family + foundry are placed into the fontnames
2654 fontsel_info->nfonts = 0;
2655 for (i = 0; i < num_fonts; i++)
2657 #ifdef FONTSEL_DEBUG
2658 g_message("%s\n", xfontnames[i]);
2660 if (gtk_font_selection_is_xlfd_font_name (xfontnames[i]))
2661 gtk_font_selection_insert_font (fontnames, &fontsel_info->nfonts, xfontnames[i]);
2664 #ifdef FONTSEL_DEBUG
2665 g_warning("Skipping invalid font: %s", xfontnames[i]);
2671 /* Since many font names will be in the same FontInfo not all of the
2672 allocated FontInfo table will be used, so we will now reallocate it
2673 with the real size. */
2674 fontsel_info->font_info = g_realloc(fontsel_info->font_info,
2675 sizeof(FontInfo) * fontsel_info->nfonts);
2678 /* Now we work out which choices of weight/slant etc. are valid for each
2680 fontsel_info->nstyles = 0;
2681 current_style = fontsel_info->font_styles;
2682 for (i = 0; i < fontsel_info->nfonts; i++)
2684 font = &fontsel_info->font_info[i];
2686 /* Use the next free position in the styles array. */
2687 font->style_index = fontsel_info->nstyles;
2689 /* Now step through each of the fontnames with this family, and create
2690 a style for each fontname. Each style contains the index into the
2691 weights/slants etc. arrays, and a number of pixel/point sizes. */
2693 temp_list = fontnames[i];
2696 fontname = temp_list->data;
2697 temp_list = temp_list->next;
2699 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2701 current_style->properties[prop]
2702 = gtk_font_selection_insert_field (fontname, prop);
2704 current_style->pixel_sizes_index = npixel_sizes;
2705 current_style->npixel_sizes = 0;
2706 current_style->point_sizes_index = npoint_sizes;
2707 current_style->npoint_sizes = 0;
2708 current_style->flags = 0;
2711 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_PIXELS,
2713 pixels = atoi(field);
2715 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_POINTS,
2717 points = atoi(field);
2719 field = gtk_font_selection_get_xlfd_field (fontname,
2722 res_x = atoi(field);
2724 field = gtk_font_selection_get_xlfd_field (fontname,
2727 res_y = atoi(field);
2729 if (pixels == 0 && points == 0)
2731 if (res_x == 0 && res_y == 0)
2732 flags = GTK_FONT_SCALABLE;
2734 flags = GTK_FONT_SCALABLE_BITMAP;
2737 flags = GTK_FONT_BITMAP;
2739 /* Now we check to make sure that the style is unique. If it isn't
2741 prev_style = fontsel_info->font_styles + font->style_index;
2742 matched_style = FALSE;
2743 while (prev_style < current_style)
2745 matched_style = TRUE;
2746 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2748 if (prev_style->properties[prop]
2749 != current_style->properties[prop])
2751 matched_style = FALSE;
2760 /* If we matched an existing style, we need to add the pixels &
2761 point sizes to the style. If not, we insert the pixel & point
2762 sizes into our new style. Note that we don't add sizes for
2766 prev_style->flags |= flags;
2767 if (flags == GTK_FONT_BITMAP)
2769 pixel_sizes = fontsel_info->pixel_sizes
2770 + prev_style->pixel_sizes_index;
2772 for (size = 0; size < prev_style->npixel_sizes; size++)
2774 if (pixels == *pixel_sizes)
2779 else if (pixels < *pixel_sizes)
2783 /* We need to move all the following pixel sizes up, and also
2784 update the indexes of any following styles. */
2787 for (tmp_sizes = fontsel_info->pixel_sizes + npixel_sizes;
2788 tmp_sizes > pixel_sizes; tmp_sizes--)
2789 *tmp_sizes = *(tmp_sizes - 1);
2791 *pixel_sizes = pixels;
2793 prev_style->npixel_sizes++;
2795 tmp_style = prev_style + 1;
2796 while (tmp_style < current_style)
2798 tmp_style->pixel_sizes_index++;
2803 point_sizes = fontsel_info->point_sizes
2804 + prev_style->point_sizes_index;
2806 for (size = 0; size < prev_style->npoint_sizes; size++)
2808 if (points == *point_sizes)
2813 else if (points < *point_sizes)
2817 /* We need to move all the following point sizes up, and also
2818 update the indexes of any following styles. */
2821 for (tmp_sizes = fontsel_info->point_sizes + npoint_sizes;
2822 tmp_sizes > point_sizes; tmp_sizes--)
2823 *tmp_sizes = *(tmp_sizes - 1);
2825 *point_sizes = points;
2827 prev_style->npoint_sizes++;
2829 tmp_style = prev_style + 1;
2830 while (tmp_style < current_style)
2832 tmp_style->point_sizes_index++;
2840 current_style->flags = flags;
2841 if (flags == GTK_FONT_BITMAP)
2843 fontsel_info->pixel_sizes[npixel_sizes++] = pixels;
2844 current_style->npixel_sizes = 1;
2845 fontsel_info->point_sizes[npoint_sizes++] = points;
2846 current_style->npoint_sizes = 1;
2849 fontsel_info->nstyles++;
2853 g_slist_free(fontnames[i]);
2855 /* Set nstyles to the real value, minus duplicated fontnames.
2856 Note that we aren't using all the allocated memory if fontnames are
2858 font->nstyles = style;
2861 /* Since some repeated styles may be skipped we won't have used all the
2862 allocated space, so we will now reallocate it with the real size. */
2863 fontsel_info->font_styles = g_realloc(fontsel_info->font_styles,
2864 sizeof(FontStyle) * fontsel_info->nstyles);
2865 fontsel_info->pixel_sizes = g_realloc(fontsel_info->pixel_sizes,
2866 sizeof(guint16) * npixel_sizes);
2867 fontsel_info->point_sizes = g_realloc(fontsel_info->point_sizes,
2868 sizeof(guint16) * npoint_sizes);
2870 XFreeFontNames (xfontnames);
2873 /* Debugging Output */
2874 /* This outputs all FontInfos. */
2875 #ifdef FONTSEL_DEBUG
2876 g_message("\n\n Font Family Weight Slant Set Width Spacing Charset\n\n");
2877 for (i = 0; i < fontsel_info->nfonts; i++)
2879 FontInfo *font = &fontsel_info->font_info[i];
2880 FontStyle *styles = fontsel_info->font_styles + font->style_index;
2881 for (style = 0; style < font->nstyles; style++)
2883 g_message("%5i %-16.16s ", i, font->family);
2884 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2885 g_message("%-9.9s ",
2886 fontsel_info->properties[prop][styles->properties[prop]]);
2889 if (styles->flags & GTK_FONT_BITMAP)
2890 g_message("Bitmapped font ");
2891 if (styles->flags & GTK_FONT_SCALABLE)
2892 g_message("Scalable font ");
2893 if (styles->flags & GTK_FONT_SCALABLE_BITMAP)
2894 g_message("Scalable-Bitmapped font ");
2897 if (styles->npixel_sizes)
2899 g_message(" Pixel sizes: ");
2900 tmp_sizes = fontsel_info->pixel_sizes + styles->pixel_sizes_index;
2901 for (size = 0; size < styles->npixel_sizes; size++)
2902 g_message("%i ", *tmp_sizes++);
2906 if (styles->npoint_sizes)
2908 g_message(" Point sizes: ");
2909 tmp_sizes = fontsel_info->point_sizes + styles->point_sizes_index;
2910 for (size = 0; size < styles->npoint_sizes; size++)
2911 g_message("%i ", *tmp_sizes++);
2919 /* This outputs all available properties. */
2920 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2922 g_message("Property: %s\n", xlfd_field_names[xlfd_index[prop]]);
2923 for (i = 0; i < fontsel_info->nproperties[prop]; i++)
2924 g_message(" %s\n", fontsel_info->properties[prop][i]);
2929 /* This inserts the given fontname into the FontInfo table.
2930 If a FontInfo already exists with the same family and foundry, then the
2931 fontname is added to the FontInfos list of fontnames, else a new FontInfo
2932 is created and inserted in alphabetical order in the table. */
2934 gtk_font_selection_insert_font (GSList *fontnames[],
2940 GSList *temp_fontname;
2942 gboolean family_exists = FALSE;
2946 gchar family_buffer[XLFD_MAX_FIELD_LEN];
2948 table = fontsel_info->font_info;
2950 /* insert a fontname into a table */
2951 family = gtk_font_selection_get_xlfd_field (fontname, XLFD_FAMILY,
2956 foundry = gtk_font_selection_insert_field (fontname, FOUNDRY);
2961 /* Do a binary search to determine if we have already encountered
2962 * a font with this family & foundry. */
2964 while (lower < upper)
2966 middle = (lower + upper) >> 1;
2968 cmp = strcmp (family, table[middle].family);
2969 /* If the family matches we sort by the foundry. */
2972 family_exists = TRUE;
2973 family = table[middle].family;
2974 cmp = strcmp(fontsel_info->properties[FOUNDRY][foundry],
2975 fontsel_info->properties[FOUNDRY][table[middle].foundry]);
2980 fontnames[middle] = g_slist_prepend (fontnames[middle],
2991 /* Add another entry to the table for this new font family */
2992 temp_info.family = family_exists ? family : g_strdup(family);
2993 temp_info.foundry = foundry;
2994 temp_fontname = g_slist_prepend (NULL, fontname);
2998 /* Quickly insert the entry into the table in sorted order
2999 * using a modification of insertion sort and the knowledge
3000 * that the entries proper position in the table was determined
3001 * above in the binary search and is contained in the "lower"
3005 upper = *ntable - 1;
3006 while (lower != upper)
3008 table[upper] = table[upper-1];
3009 fontnames[upper] = fontnames[upper-1];
3013 table[lower] = temp_info;
3014 fontnames[lower] = temp_fontname;
3018 /* This checks that the specified field of the given fontname is in the
3019 appropriate properties array. If not it is added. Thus eventually we get
3020 arrays of all possible weights/slants etc. It returns the array index. */
3022 gtk_font_selection_insert_field (gchar *fontname,
3025 gchar field_buffer[XLFD_MAX_FIELD_LEN];
3029 field = gtk_font_selection_get_xlfd_field (fontname, xlfd_index[prop],
3034 /* If the field is already in the array just return its index. */
3035 for (index = 0; index < fontsel_info->nproperties[prop]; index++)
3036 if (!strcmp(field, fontsel_info->properties[prop][index]))
3039 /* Make sure we have enough space to add the field. */
3040 if (fontsel_info->nproperties[prop] == fontsel_info->space_allocated[prop])
3042 fontsel_info->space_allocated[prop] += PROPERTY_ARRAY_INCREMENT;
3043 fontsel_info->properties[prop] = g_realloc(fontsel_info->properties[prop],
3045 * fontsel_info->space_allocated[prop]);
3048 /* Add the new field. */
3049 index = fontsel_info->nproperties[prop];
3050 fontsel_info->properties[prop][index] = g_strdup(field);
3051 fontsel_info->nproperties[prop]++;
3056 /*****************************************************************************
3057 * These functions are the main public interface for getting/setting the font.
3058 *****************************************************************************/
3061 gtk_font_selection_get_font (GtkFontSelection *fontsel)
3063 g_return_val_if_fail (fontsel != NULL, NULL);
3064 return fontsel->font;
3069 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
3072 gchar *family_str, *foundry_str;
3073 gchar *property_str[GTK_NUM_STYLE_PROPERTIES];
3076 g_return_val_if_fail (fontsel != NULL, NULL);
3077 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
3079 /* If no family has been selected return NULL. */
3080 if (fontsel->font_index == -1)
3083 font = &fontsel_info->font_info[fontsel->font_index];
3084 family_str = font->family;
3085 foundry_str = fontsel_info->properties[FOUNDRY][font->foundry];
3087 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
3090 = fontsel_info->properties[prop][fontsel->property_values[prop]];
3091 if (strcmp (property_str[prop], "(nil)") == 0)
3092 property_str[prop] = "";
3095 return gtk_font_selection_create_xlfd (fontsel->size,
3099 property_str[WEIGHT],
3100 property_str[SLANT],
3101 property_str[SET_WIDTH],
3102 property_str[SPACING],
3103 property_str[CHARSET]);
3107 /* This sets the current font, selecting the appropriate clist rows.
3108 First we check the fontname is valid and try to find the font family
3109 - i.e. the name in the main list. If we can't find that, then just return.
3110 Next we try to set each of the properties according to the fontname.
3111 Finally we select the font family & style in the clists. */
3113 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
3114 const gchar *fontname)
3116 gchar *family, *field;
3117 gint index, prop, size;
3118 guint16 foundry, value;
3119 gchar family_buffer[XLFD_MAX_FIELD_LEN];
3120 gchar field_buffer[XLFD_MAX_FIELD_LEN];
3123 g_return_val_if_fail (fontsel != NULL, FALSE);
3124 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
3125 g_return_val_if_fail (fontname != NULL, FALSE);
3127 /* Check it is a valid fontname. */
3128 if (!gtk_font_selection_is_xlfd_font_name(fontname))
3131 family = gtk_font_selection_get_xlfd_field (fontname, XLFD_FAMILY,
3136 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_FOUNDRY,
3138 foundry = gtk_font_selection_field_to_index (fontsel_info->properties[FOUNDRY],
3139 fontsel_info->nproperties[FOUNDRY],
3142 index = gtk_font_selection_find_font(fontsel, family, foundry);
3146 /* Convert the property fields into indices and set them. */
3147 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
3149 field = gtk_font_selection_get_xlfd_field (fontname, xlfd_index[prop],
3151 value = gtk_font_selection_field_to_index (fontsel_info->properties[prop],
3152 fontsel_info->nproperties[prop],
3154 fontsel->property_values[prop] = value;
3157 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_POINTS,
3164 fontsel->size = fontsel->selected_size = size;
3165 fontsel->metric = GTK_FONT_METRIC_POINTS;
3166 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fontsel->points_button),
3169 sprintf (buffer, "%i", size / 10);
3171 sprintf (buffer, "%i.%i", size / 10, size % 10);
3175 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_PIXELS,
3180 fontsel->size = fontsel->selected_size = size;
3181 fontsel->metric = GTK_FONT_METRIC_PIXELS;
3182 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fontsel->pixels_button),
3184 sprintf (buffer, "%i", size);
3186 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
3188 /* Clear any current filter. */
3189 gtk_font_selection_clear_filter(fontsel);
3191 /* Now find the best style match. */
3192 fontsel->font_index = index;
3193 gtk_clist_select_row(GTK_CLIST(fontsel->font_clist), index, 0);
3194 if (GTK_WIDGET_MAPPED (fontsel->font_clist))
3195 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), index, -1, 0.5, 0);
3197 gtk_font_selection_show_available_styles (fontsel);
3198 /* This will load the font. */
3199 gtk_font_selection_select_best_style (fontsel, FALSE);
3205 /* Returns the index of the given family, or -1 if not found */
3207 gtk_font_selection_find_font (GtkFontSelection *fontsel,
3211 FontInfo *font_info;
3212 gint lower, upper, middle = -1, cmp, nfonts;
3213 gint found_family = -1;
3215 font_info = fontsel_info->font_info;
3216 nfonts = fontsel_info->nfonts;
3220 /* Do a binary search to find the font family. */
3223 while (lower < upper)
3225 middle = (lower + upper) >> 1;
3227 cmp = strcmp (family, font_info[middle].family);
3230 found_family = middle;
3231 cmp = strcmp(fontsel_info->properties[FOUNDRY][foundry],
3232 fontsel_info->properties[FOUNDRY][font_info[middle].foundry]);
3243 /* We couldn't find the family and foundry, but we may have just found the
3244 family, so we return that. */
3245 return found_family;
3249 /* This returns the text in the preview entry. You should copy the returned
3250 text if you need it. */
3252 gtk_font_selection_get_preview_text (GtkFontSelection *fontsel)
3254 return gtk_entry_get_text(GTK_ENTRY(fontsel->preview_entry));
3258 /* This sets the text in the preview entry. */
3260 gtk_font_selection_set_preview_text (GtkFontSelection *fontsel,
3263 gtk_entry_set_text(GTK_ENTRY(fontsel->preview_entry), text);
3267 /*****************************************************************************
3268 * These functions all deal with X Logical Font Description (XLFD) fontnames.
3269 * See the freely available documentation about this.
3270 *****************************************************************************/
3273 * Returns TRUE if the fontname is a valid XLFD.
3274 * (It just checks if the number of dashes is 14, and that each
3275 * field < XLFD_MAX_FIELD_LEN characters long - that's not in the XLFD but it
3276 * makes it easier for me).
3279 gtk_font_selection_is_xlfd_font_name (const gchar *fontname)
3286 if (*fontname++ == '-')
3288 if (field_len > XLFD_MAX_FIELD_LEN) return FALSE;
3296 return (i == 14) ? TRUE : FALSE;
3300 * This fills the buffer with the specified field from the X Logical Font
3301 * Description name, and returns it. If fontname is NULL or the field is
3302 * longer than XFLD_MAX_FIELD_LEN it returns NULL.
3303 * Note: For the charset field, we also return the encoding, e.g. 'iso8859-1'.
3306 gtk_font_selection_get_xlfd_field (const gchar *fontname,
3307 FontField field_num,
3310 const gchar *t1, *t2;
3311 gint countdown, len, num_dashes;
3316 /* we assume this is a valid fontname...that is, it has 14 fields */
3318 countdown = field_num;
3320 while (*t1 && (countdown >= 0))
3324 num_dashes = (field_num == XLFD_CHARSET) ? 2 : 1;
3325 for (t2 = t1; *t2; t2++)
3327 if (*t2 == '-' && --num_dashes == 0)
3333 /* Check we don't overflow the buffer */
3334 len = (long) t2 - (long) t1;
3335 if (len > XLFD_MAX_FIELD_LEN - 1)
3337 strncpy (buffer, t1, len);
3340 /* Convert to lower case. */
3344 strcpy(buffer, "(nil)");
3350 * This returns a X Logical Font Description font name, given all the pieces.
3351 * Note: this retval must be freed by the caller.
3354 gtk_font_selection_create_xlfd (gint size,
3355 GtkFontMetricType metric,
3365 gchar *pixel_size = "*", *point_size = "*", *fontname;
3371 sprintf (buffer, "%d", (int) size);
3372 if (metric == GTK_FONT_METRIC_PIXELS)
3373 pixel_size = buffer;
3375 point_size = buffer;
3377 /* Note: be careful here - don't overrun the allocated memory. */
3378 length = strlen(foundry) + strlen(family) + strlen(weight) + strlen(slant)
3379 + strlen(set_width) + strlen(pixel_size) + strlen(point_size)
3380 + strlen(spacing) + strlen(charset)
3381 + 1 + 1 + 1 + 1 + 1 + 3 + 1 + 5 + 3
3382 + 1 /* for the terminating '\0'. */;
3384 fontname = g_new(gchar, length);
3385 /* **NOTE**: If you change this string please change length above! */
3386 sprintf(fontname, "-%s-%s-%s-%s-%s-*-%s-%s-*-*-%s-*-%s",
3387 foundry, family, weight, slant, set_width, pixel_size,
3388 point_size, spacing, charset);
3394 /*****************************************************************************
3395 * GtkFontSelectionDialog
3396 *****************************************************************************/
3399 gtk_font_selection_dialog_get_type (void)
3401 static guint font_selection_dialog_type = 0;
3403 if (!font_selection_dialog_type)
3405 GtkTypeInfo fontsel_diag_info =
3407 "GtkFontSelectionDialog",
3408 sizeof (GtkFontSelectionDialog),
3409 sizeof (GtkFontSelectionDialogClass),
3410 (GtkClassInitFunc) gtk_font_selection_dialog_class_init,
3411 (GtkObjectInitFunc) gtk_font_selection_dialog_init,
3412 /* reserved_1 */ NULL,
3413 /* reserved_2 */ NULL,
3414 (GtkClassInitFunc) NULL,
3417 font_selection_dialog_type = gtk_type_unique (GTK_TYPE_WINDOW, &fontsel_diag_info);
3420 return font_selection_dialog_type;
3424 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
3426 GtkObjectClass *object_class;
3428 object_class = (GtkObjectClass*) klass;
3430 font_selection_dialog_parent_class = gtk_type_class (GTK_TYPE_WINDOW);
3434 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
3436 fontseldiag->dialog_width = -1;
3437 fontseldiag->auto_resize = TRUE;
3439 gtk_widget_set_events(GTK_WIDGET(fontseldiag), GDK_STRUCTURE_MASK);
3440 gtk_signal_connect (GTK_OBJECT (fontseldiag), "configure_event",
3441 (GtkSignalFunc) gtk_font_selection_dialog_on_configure,
3444 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag), 4);
3445 gtk_window_set_policy(GTK_WINDOW(fontseldiag), FALSE, TRUE, TRUE);
3447 fontseldiag->main_vbox = gtk_vbox_new (FALSE, 4);
3448 gtk_widget_show (fontseldiag->main_vbox);
3449 gtk_container_add (GTK_CONTAINER (fontseldiag), fontseldiag->main_vbox);
3451 fontseldiag->fontsel = gtk_font_selection_new();
3452 gtk_widget_show (fontseldiag->fontsel);
3453 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
3454 fontseldiag->fontsel, TRUE, TRUE, 0);
3456 /* Create the action area */
3457 fontseldiag->action_area = gtk_hbutton_box_new ();
3458 gtk_button_box_set_layout(GTK_BUTTON_BOX(fontseldiag->action_area),
3460 gtk_button_box_set_spacing(GTK_BUTTON_BOX(fontseldiag->action_area), 5);
3461 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
3462 fontseldiag->action_area, FALSE, FALSE, 0);
3463 gtk_widget_show (fontseldiag->action_area);
3465 fontseldiag->ok_button = gtk_button_new_with_label(_("OK"));
3466 GTK_WIDGET_SET_FLAGS (fontseldiag->ok_button, GTK_CAN_DEFAULT);
3467 gtk_widget_show(fontseldiag->ok_button);
3468 gtk_box_pack_start (GTK_BOX (fontseldiag->action_area),
3469 fontseldiag->ok_button, TRUE, TRUE, 0);
3470 gtk_widget_grab_default (fontseldiag->ok_button);
3472 fontseldiag->apply_button = gtk_button_new_with_label(_("Apply"));
3473 GTK_WIDGET_SET_FLAGS (fontseldiag->apply_button, GTK_CAN_DEFAULT);
3474 /*gtk_widget_show(fontseldiag->apply_button);*/
3475 gtk_box_pack_start (GTK_BOX(fontseldiag->action_area),
3476 fontseldiag->apply_button, TRUE, TRUE, 0);
3478 fontseldiag->cancel_button = gtk_button_new_with_label(_("Cancel"));
3479 GTK_WIDGET_SET_FLAGS (fontseldiag->cancel_button, GTK_CAN_DEFAULT);
3480 gtk_widget_show(fontseldiag->cancel_button);
3481 gtk_box_pack_start (GTK_BOX(fontseldiag->action_area),
3482 fontseldiag->cancel_button, TRUE, TRUE, 0);
3488 gtk_font_selection_dialog_new (const gchar *title)
3490 GtkFontSelectionDialog *fontseldiag;
3492 fontseldiag = gtk_type_new (GTK_TYPE_FONT_SELECTION_DIALOG);
3493 gtk_window_set_title (GTK_WINDOW (fontseldiag),
3494 title ? title : _("Font Selection"));
3496 return GTK_WIDGET (fontseldiag);
3500 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
3502 return gtk_font_selection_get_font_name(GTK_FONT_SELECTION(fsd->fontsel));
3506 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
3508 return gtk_font_selection_get_font(GTK_FONT_SELECTION(fsd->fontsel));
3512 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
3513 const gchar *fontname)
3515 return gtk_font_selection_set_font_name(GTK_FONT_SELECTION(fsd->fontsel),
3520 gtk_font_selection_dialog_set_filter (GtkFontSelectionDialog *fsd,
3521 GtkFontFilterType filter_type,
3522 GtkFontType font_type,
3530 gtk_font_selection_set_filter (GTK_FONT_SELECTION (fsd->fontsel),
3531 filter_type, font_type,
3532 foundries, weights, slants, setwidths,
3533 spacings, charsets);
3537 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
3539 return gtk_font_selection_get_preview_text(GTK_FONT_SELECTION(fsd->fontsel));
3543 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
3546 gtk_font_selection_set_preview_text(GTK_FONT_SELECTION(fsd->fontsel), text);
3550 /* This turns auto-shrink off if the user resizes the width of the dialog.
3551 It also turns it back on again if the user resizes it back to its normal
3554 gtk_font_selection_dialog_on_configure (GtkWidget *widget,
3555 GdkEventConfigure *event,
3556 GtkFontSelectionDialog *fsd)
3558 /* This sets the initial width. */
3559 if (fsd->dialog_width == -1)
3560 fsd->dialog_width = event->width;
3561 else if (fsd->auto_resize && fsd->dialog_width != event->width)
3563 fsd->auto_resize = FALSE;
3564 gtk_window_set_policy(GTK_WINDOW(fsd), FALSE, TRUE, FALSE);
3566 else if (!fsd->auto_resize && fsd->dialog_width == event->width)
3568 fsd->auto_resize = TRUE;
3569 gtk_window_set_policy(GTK_WINDOW(fsd), FALSE, TRUE, TRUE);