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[] = { _("Font Property"), _("Requested Value"), _("Actual Value") };
447 gchar *property, *text;
450 /* Initialize the GtkFontSelection struct. We do this here in case any
451 callbacks are triggered while creating the interface. */
452 fontsel->font = NULL;
453 fontsel->font_index = -1;
455 fontsel->metric = INITIAL_METRIC;
456 fontsel->size = INITIAL_FONT_SIZE;
457 fontsel->selected_size = INITIAL_FONT_SIZE;
459 fontsel->filters[GTK_FONT_FILTER_BASE].font_type = GTK_FONT_ALL;
460 fontsel->filters[GTK_FONT_FILTER_USER].font_type = GTK_FONT_BITMAP
464 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
466 fontsel->filters[GTK_FONT_FILTER_BASE].property_filters[prop] = NULL;
467 fontsel->filters[GTK_FONT_FILTER_BASE].property_nfilters[prop] = 0;
468 fontsel->filters[GTK_FONT_FILTER_USER].property_filters[prop] = NULL;
469 fontsel->filters[GTK_FONT_FILTER_USER].property_nfilters[prop] = 0;
472 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
473 fontsel->property_values[prop] = 0;
475 /* Create the main notebook page. */
476 gtk_notebook_set_homogeneous_tabs (GTK_NOTEBOOK (fontsel), TRUE);
477 gtk_notebook_set_tab_hborder (GTK_NOTEBOOK (fontsel), 8);
478 fontsel->main_vbox = gtk_vbox_new (FALSE, 4);
479 gtk_widget_show (fontsel->main_vbox);
480 gtk_container_set_border_width (GTK_CONTAINER (fontsel->main_vbox), 6);
481 label = gtk_label_new(_("Font"));
482 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
483 fontsel->main_vbox, label);
485 /* Create the table of font, style & size. */
486 table = gtk_table_new (3, 3, FALSE);
487 gtk_widget_show (table);
488 gtk_table_set_col_spacings(GTK_TABLE(table), 8);
489 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), table, TRUE, TRUE, 0);
491 fontsel->font_label = gtk_label_new(_("Font:"));
492 gtk_misc_set_alignment (GTK_MISC (fontsel->font_label), 0.0, 0.5);
493 gtk_widget_show (fontsel->font_label);
494 gtk_table_attach (GTK_TABLE (table), fontsel->font_label, 0, 1, 0, 1,
496 label = gtk_label_new(_("Font Style:"));
497 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
498 gtk_widget_show (label);
499 gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1,
501 label = gtk_label_new(_("Size:"));
502 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
503 gtk_widget_show (label);
504 gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
507 fontsel->font_entry = gtk_entry_new();
508 gtk_entry_set_editable(GTK_ENTRY(fontsel->font_entry), FALSE);
509 gtk_widget_set_usize (fontsel->font_entry, 20, -1);
510 gtk_widget_show (fontsel->font_entry);
511 gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
513 fontsel->font_style_entry = gtk_entry_new();
514 gtk_entry_set_editable(GTK_ENTRY(fontsel->font_style_entry), FALSE);
515 gtk_widget_set_usize (fontsel->font_style_entry, 20, -1);
516 gtk_widget_show (fontsel->font_style_entry);
517 gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
519 fontsel->size_entry = gtk_entry_new();
520 gtk_widget_set_usize (fontsel->size_entry, 20, -1);
521 gtk_widget_show (fontsel->size_entry);
522 gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
524 gtk_signal_connect (GTK_OBJECT (fontsel->size_entry), "key_press_event",
525 (GtkSignalFunc) gtk_font_selection_size_key_press,
528 /* Create the clists */
529 fontsel->font_clist = gtk_clist_new(1);
530 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->font_clist));
531 gtk_clist_set_column_auto_resize (GTK_CLIST (fontsel->font_clist), 0, TRUE);
532 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
533 gtk_widget_set_usize (scrolled_win, FONT_LIST_WIDTH, FONT_LIST_HEIGHT);
534 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->font_clist);
535 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
536 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
537 gtk_widget_show(fontsel->font_clist);
538 gtk_widget_show(scrolled_win);
540 gtk_table_attach (GTK_TABLE (table), scrolled_win, 0, 1, 2, 3,
541 GTK_EXPAND | GTK_FILL,
542 GTK_EXPAND | GTK_FILL, 0, 0);
544 fontsel->font_style_clist = gtk_clist_new(1);
545 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->font_style_clist));
546 gtk_clist_set_column_auto_resize (GTK_CLIST (fontsel->font_style_clist),
548 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
549 gtk_widget_set_usize (scrolled_win, FONT_STYLE_LIST_WIDTH, -1);
550 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->font_style_clist);
551 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
552 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
553 gtk_widget_show(fontsel->font_style_clist);
554 gtk_widget_show(scrolled_win);
555 gtk_table_attach (GTK_TABLE (table), scrolled_win, 1, 2, 2, 3,
556 GTK_EXPAND | GTK_FILL,
557 GTK_EXPAND | GTK_FILL, 0, 0);
559 fontsel->size_clist = gtk_clist_new(1);
560 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->size_clist));
561 gtk_clist_set_column_width (GTK_CLIST(fontsel->size_clist), 0, 20);
562 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
563 gtk_widget_set_usize (scrolled_win, FONT_SIZE_LIST_WIDTH, -1);
564 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->size_clist);
565 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
566 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
567 gtk_widget_show(fontsel->size_clist);
568 gtk_widget_show(scrolled_win);
569 gtk_table_attach (GTK_TABLE (table), scrolled_win, 2, 3, 2, 3,
570 GTK_FILL, GTK_FILL, 0, 0);
573 /* Insert the fonts. If there exist fonts with the same family but
574 different foundries, then the foundry name is appended in brackets. */
575 gtk_font_selection_show_available_fonts(fontsel);
577 gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "select_row",
578 GTK_SIGNAL_FUNC(gtk_font_selection_select_font),
580 GTK_WIDGET_SET_FLAGS (fontsel->font_clist, GTK_CAN_FOCUS);
581 gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "key_press_event",
582 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
584 gtk_signal_connect_after (GTK_OBJECT (fontsel->font_clist), "expose_event",
585 GTK_SIGNAL_FUNC(gtk_font_selection_expose_list),
588 gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist), "select_row",
589 GTK_SIGNAL_FUNC(gtk_font_selection_select_style),
591 GTK_WIDGET_SET_FLAGS (fontsel->font_style_clist, GTK_CAN_FOCUS);
592 gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist),
594 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
596 gtk_signal_connect_after (GTK_OBJECT (fontsel->font_style_clist),
598 GTK_SIGNAL_FUNC(gtk_font_selection_realize_list),
601 /* Insert the standard font sizes */
602 gtk_clist_freeze (GTK_CLIST(fontsel->size_clist));
603 size_to_match = INITIAL_FONT_SIZE;
604 if (INITIAL_METRIC == GTK_FONT_METRIC_POINTS)
605 size_to_match = size_to_match / 10;
606 for (i = 0; i < sizeof(font_sizes) / sizeof(font_sizes[0]); i++)
608 sprintf(buffer, "%i", font_sizes[i]);
610 gtk_clist_append(GTK_CLIST(fontsel->size_clist), &size);
611 if (font_sizes[i] == size_to_match)
613 gtk_clist_select_row(GTK_CLIST(fontsel->size_clist), i, 0);
614 gtk_entry_set_text(GTK_ENTRY(fontsel->size_entry), buffer);
617 gtk_clist_thaw (GTK_CLIST(fontsel->size_clist));
619 gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "select_row",
620 GTK_SIGNAL_FUNC(gtk_font_selection_select_size),
622 GTK_WIDGET_SET_FLAGS (fontsel->size_clist, GTK_CAN_FOCUS);
623 gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "key_press_event",
624 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
628 /* create the Reset Filter & Metric buttons */
629 hbox = gtk_hbox_new(FALSE, 8);
630 gtk_widget_show (hbox);
631 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), hbox, FALSE, TRUE, 0);
633 fontsel->filter_button = gtk_button_new_with_label(_("Reset Filter"));
634 gtk_misc_set_padding (GTK_MISC (GTK_BIN (fontsel->filter_button)->child),
636 gtk_widget_show(fontsel->filter_button);
637 gtk_box_pack_start (GTK_BOX (hbox), fontsel->filter_button, FALSE, FALSE, 0);
638 gtk_widget_set_sensitive (fontsel->filter_button, FALSE);
639 gtk_signal_connect (GTK_OBJECT (fontsel->filter_button), "clicked",
640 GTK_SIGNAL_FUNC(gtk_font_selection_on_clear_filter),
643 hbox2 = gtk_hbox_new(FALSE, 0);
644 gtk_widget_show (hbox2);
645 gtk_box_pack_end (GTK_BOX (hbox), hbox2, FALSE, FALSE, 0);
647 label = gtk_label_new(_("Metric:"));
648 gtk_widget_show (label);
649 gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 8);
651 fontsel->points_button = gtk_radio_button_new_with_label(NULL, _("Points"));
652 gtk_widget_show (fontsel->points_button);
653 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->points_button, FALSE, TRUE, 0);
654 if (INITIAL_METRIC == GTK_FONT_METRIC_POINTS)
655 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->points_button),
658 fontsel->pixels_button = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(fontsel->points_button), _("Pixels"));
659 gtk_widget_show (fontsel->pixels_button);
660 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->pixels_button, FALSE, TRUE, 0);
661 if (INITIAL_METRIC == GTK_FONT_METRIC_PIXELS)
662 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->pixels_button),
665 gtk_signal_connect(GTK_OBJECT(fontsel->points_button), "toggled",
666 (GtkSignalFunc) gtk_font_selection_metric_callback,
668 gtk_signal_connect(GTK_OBJECT(fontsel->pixels_button), "toggled",
669 (GtkSignalFunc) gtk_font_selection_metric_callback,
673 /* create the text entry widget */
674 text_frame = gtk_frame_new (_("Preview:"));
675 gtk_widget_show (text_frame);
676 gtk_frame_set_shadow_type(GTK_FRAME(text_frame), GTK_SHADOW_ETCHED_IN);
677 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), text_frame,
680 /* This is just used to get a 4-pixel space around the preview entry. */
681 text_box = gtk_hbox_new (FALSE, 0);
682 gtk_widget_show (text_box);
683 gtk_container_add (GTK_CONTAINER (text_frame), text_box);
684 gtk_container_set_border_width (GTK_CONTAINER (text_box), 4);
686 fontsel->preview_entry = gtk_entry_new ();
687 gtk_widget_show (fontsel->preview_entry);
688 gtk_widget_set_usize (fontsel->preview_entry, -1, INITIAL_PREVIEW_HEIGHT);
689 gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
692 /* Create the message area */
693 fontsel->message_label = gtk_label_new("");
694 gtk_widget_show (fontsel->message_label);
695 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), fontsel->message_label,
699 /* Create the font info page */
700 fontsel->info_vbox = gtk_vbox_new (FALSE, 4);
701 gtk_widget_show (fontsel->info_vbox);
702 gtk_container_set_border_width (GTK_CONTAINER (fontsel->info_vbox), 2);
703 label = gtk_label_new(_("Font Information"));
704 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
705 fontsel->info_vbox, label);
707 fontsel->info_clist = gtk_clist_new_with_titles (3, titles);
708 gtk_widget_set_usize (fontsel->info_clist, 390, 150);
709 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 0, 130);
710 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 1, 130);
711 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 2, 130);
712 gtk_clist_column_titles_passive(GTK_CLIST(fontsel->info_clist));
713 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
714 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->info_clist);
715 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
716 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
717 gtk_widget_show(fontsel->info_clist);
718 gtk_widget_show(scrolled_win);
719 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), scrolled_win,
722 /* Insert the property names */
723 gtk_clist_freeze (GTK_CLIST(fontsel->info_clist));
726 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
728 row_text[0] = gettext(xlfd_field_names[i]);
729 gtk_clist_append(GTK_CLIST(fontsel->info_clist), row_text);
730 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 0, 0, 4);
731 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 1, 0, 4);
732 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 2, 0, 4);
734 gtk_clist_thaw (GTK_CLIST(fontsel->info_clist));
736 label = gtk_label_new(_("Requested Font Name:"));
737 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
738 gtk_widget_show (label);
739 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, TRUE, 0);
741 fontsel->requested_font_name = gtk_entry_new();
742 gtk_entry_set_editable(GTK_ENTRY(fontsel->requested_font_name), FALSE);
743 gtk_widget_show (fontsel->requested_font_name);
744 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox),
745 fontsel->requested_font_name, FALSE, TRUE, 0);
747 label = gtk_label_new(_("Actual Font Name:"));
748 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
749 gtk_widget_show (label);
750 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, TRUE, 0);
752 fontsel->actual_font_name = gtk_entry_new();
753 gtk_entry_set_editable(GTK_ENTRY(fontsel->actual_font_name), FALSE);
754 gtk_widget_show (fontsel->actual_font_name);
755 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox),
756 fontsel->actual_font_name, FALSE, TRUE, 0);
758 sprintf(buffer, _("%i fonts available with a total of %i styles."),
759 fontsel_info->nfonts, fontsel_info->nstyles);
760 label = gtk_label_new(buffer);
761 gtk_widget_show (label);
762 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, FALSE, 0);
764 gtk_signal_connect (GTK_OBJECT (fontsel), "switch_page",
765 GTK_SIGNAL_FUNC(gtk_font_selection_switch_page),
769 /* Create the Filter page. */
770 fontsel->filter_vbox = gtk_vbox_new (FALSE, 4);
771 gtk_widget_show (fontsel->filter_vbox);
772 gtk_container_set_border_width (GTK_CONTAINER (fontsel->filter_vbox), 2);
773 label = gtk_label_new(_("Filter"));
774 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
775 fontsel->filter_vbox, label);
777 /* Create the font type checkbuttons. */
778 frame = gtk_frame_new (NULL);
779 gtk_widget_show (frame);
780 gtk_box_pack_start (GTK_BOX (fontsel->filter_vbox), frame, FALSE, TRUE, 0);
782 hbox = gtk_hbox_new (FALSE, 20);
783 gtk_widget_show (hbox);
784 gtk_container_add (GTK_CONTAINER (frame), hbox);
786 label = gtk_label_new(_("Font Types:"));
787 gtk_widget_show (label);
788 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 10);
790 hbox2 = gtk_hbox_new (TRUE, 0);
791 gtk_widget_show (hbox2);
792 gtk_box_pack_start (GTK_BOX (hbox), hbox2, FALSE, TRUE, 0);
794 fontsel->type_bitmaps_button = gtk_check_button_new_with_label (_("Bitmap"));
795 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), TRUE);
796 gtk_widget_show (fontsel->type_bitmaps_button);
797 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_bitmaps_button,
800 fontsel->type_scalable_button = gtk_check_button_new_with_label (_("Scalable"));
801 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), TRUE);
802 gtk_widget_show (fontsel->type_scalable_button);
803 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_scalable_button,
806 fontsel->type_scaled_bitmaps_button = gtk_check_button_new_with_label (_("Scaled Bitmap"));
807 gtk_widget_show (fontsel->type_scaled_bitmaps_button);
808 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_scaled_bitmaps_button,
811 table = gtk_table_new (4, 3, FALSE);
812 gtk_table_set_col_spacings(GTK_TABLE(table), 2);
813 gtk_widget_show (table);
814 gtk_box_pack_start (GTK_BOX (fontsel->filter_vbox), table, TRUE, TRUE, 0);
816 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
818 gint left = filter_positions[prop][0];
819 gint top = filter_positions[prop][1];
821 label = gtk_label_new(gettext(xlfd_field_names[xlfd_index[prop]]));
822 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 1.0);
823 gtk_misc_set_padding (GTK_MISC (label), 0, 2);
824 gtk_widget_show(label);
825 gtk_table_attach (GTK_TABLE (table), label, left, left + 1,
826 top, top + 1, GTK_FILL, GTK_FILL, 0, 0);
828 clist = gtk_clist_new(1);
829 gtk_widget_set_usize (clist, 100, filter_heights[prop]);
830 gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_MULTIPLE);
831 gtk_clist_column_titles_hide(GTK_CLIST(clist));
832 gtk_clist_set_column_auto_resize (GTK_CLIST (clist), 0, TRUE);
833 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
834 gtk_container_add (GTK_CONTAINER (scrolled_win), clist);
835 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
836 GTK_POLICY_AUTOMATIC,
837 GTK_POLICY_AUTOMATIC);
838 gtk_widget_show(clist);
839 gtk_widget_show(scrolled_win);
841 /* For the bottom-right cell we add the 'Reset Filter' button. */
842 if (top == 2 && left == 2)
844 vbox = gtk_vbox_new(FALSE, 0);
845 gtk_widget_show(vbox);
846 gtk_table_attach (GTK_TABLE (table), vbox, left, left + 1,
847 top + 1, top + 2, GTK_FILL, GTK_FILL, 0, 0);
849 gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0);
851 alignment = gtk_alignment_new(0.5, 0.0, 0.8, 0.0);
852 gtk_widget_show(alignment);
853 gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, TRUE, 4);
855 button = gtk_button_new_with_label(_("Reset Filter"));
856 gtk_widget_show(button);
857 gtk_container_add(GTK_CONTAINER(alignment), button);
858 gtk_signal_connect (GTK_OBJECT (button), "clicked",
859 GTK_SIGNAL_FUNC(gtk_font_selection_reset_filter),
863 gtk_table_attach (GTK_TABLE (table), scrolled_win,
864 left, left + 1, top + 1, top + 2,
865 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
867 gtk_signal_connect (GTK_OBJECT (clist), "select_row",
868 GTK_SIGNAL_FUNC(gtk_font_selection_select_filter),
870 gtk_signal_connect (GTK_OBJECT (clist), "unselect_row",
871 GTK_SIGNAL_FUNC(gtk_font_selection_unselect_filter),
874 /* Insert the property names, expanded, and in sorted order.
875 But we make sure that the wildcard '*' is first. */
876 gtk_clist_freeze (GTK_CLIST(clist));
878 gtk_clist_append(GTK_CLIST(clist), &property);
880 for (i = 1; i < fontsel_info->nproperties[prop]; i++) {
881 property = fontsel_info->properties[prop][i];
883 property = gtk_font_selection_expand_slant_code(property);
884 else if (prop == SPACING)
885 property = gtk_font_selection_expand_spacing_code(property);
888 for (row = 1; row < GTK_CLIST(clist)->rows; row++)
890 gtk_clist_get_text(GTK_CLIST(clist), row, 0, &text);
891 if (strcmp(property, text) < 0)
894 gtk_clist_insert(GTK_CLIST(clist), row, &property);
899 row = gtk_clist_append(GTK_CLIST(clist), &property);
900 gtk_clist_set_row_data(GTK_CLIST(clist), row, GINT_TO_POINTER (i));
902 gtk_clist_select_row(GTK_CLIST(clist), 0, 0);
903 gtk_clist_thaw (GTK_CLIST(clist));
904 fontsel->filter_clists[prop] = clist;
909 gtk_font_selection_new()
911 GtkFontSelection *fontsel;
913 fontsel = gtk_type_new (GTK_TYPE_FONT_SELECTION);
915 return GTK_WIDGET (fontsel);
919 gtk_font_selection_destroy (GtkObject *object)
921 GtkFontSelection *fontsel;
923 g_return_if_fail (object != NULL);
924 g_return_if_fail (GTK_IS_FONT_SELECTION (object));
926 fontsel = GTK_FONT_SELECTION (object);
928 /* All we have to do is unref the font, if we have one. */
930 gdk_font_unref (fontsel->font);
932 if (GTK_OBJECT_CLASS (font_selection_parent_class)->destroy)
933 (* GTK_OBJECT_CLASS (font_selection_parent_class)->destroy) (object);
937 /* This is called when the clist is exposed. Here we scroll to the current
938 font if necessary. */
940 gtk_font_selection_expose_list (GtkWidget *widget,
941 GdkEventExpose *event,
944 GtkFontSelection *fontsel;
950 g_message("In expose_list\n");
952 fontsel = GTK_FONT_SELECTION(data);
954 font_info = fontsel_info->font_info;
956 /* Try to scroll the font family clist to the selected item */
957 selection = GTK_CLIST(fontsel->font_clist)->selection;
960 index = GPOINTER_TO_INT (selection->data);
961 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_clist), index)
962 != GTK_VISIBILITY_FULL)
963 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), index, -1, 0.5, 0);
966 /* Try to scroll the font style clist to the selected item */
967 selection = GTK_CLIST(fontsel->font_style_clist)->selection;
970 index = GPOINTER_TO_INT (selection->data);
971 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_style_clist), index)
972 != GTK_VISIBILITY_FULL)
973 gtk_clist_moveto(GTK_CLIST(fontsel->font_style_clist), index, -1,
977 /* Try to scroll the font size clist to the selected item */
978 selection = GTK_CLIST(fontsel->size_clist)->selection;
981 index = GPOINTER_TO_INT (selection->data);
982 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->size_clist), index)
983 != GTK_VISIBILITY_FULL)
984 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), index, -1, 0.5, 0);
989 /* This is called when the style clist is realized. We need to set any
990 charset rows to insensitive colours. */
992 gtk_font_selection_realize_list (GtkWidget *widget,
995 GtkFontSelection *fontsel;
997 GdkColor *inactive_fg, *inactive_bg;
1000 g_message("In realize_list\n");
1002 fontsel = GTK_FONT_SELECTION (data);
1004 /* Set the colours for any charset rows to insensitive. */
1005 inactive_fg = &fontsel->font_style_clist->style->fg[GTK_STATE_INSENSITIVE];
1006 inactive_bg = &fontsel->font_style_clist->style->bg[GTK_STATE_INSENSITIVE];
1008 for (row = 0; row < GTK_CLIST (fontsel->font_style_clist)->rows; row++)
1010 if (GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_style_clist), row)) == -1)
1012 gtk_clist_set_foreground (GTK_CLIST (fontsel->font_style_clist),
1014 gtk_clist_set_background (GTK_CLIST (fontsel->font_style_clist),
1021 /* This is called when a family is selected in the list. */
1023 gtk_font_selection_select_font (GtkWidget *w,
1026 GdkEventButton *bevent,
1029 GtkFontSelection *fontsel;
1030 FontInfo *font_info;
1033 #ifdef FONTSEL_DEBUG
1034 g_message("In select_font\n");
1036 fontsel = GTK_FONT_SELECTION(data);
1037 font_info = fontsel_info->font_info;
1039 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1040 gtk_widget_grab_focus (w);
1042 row = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_clist), row));
1043 font = &font_info[row];
1044 gtk_entry_set_text(GTK_ENTRY(fontsel->font_entry), font->family);
1046 /* If it is already the current font, just return. */
1047 if (fontsel->font_index == row)
1050 fontsel->font_index = row;
1051 gtk_font_selection_show_available_styles (fontsel);
1052 gtk_font_selection_select_best_style (fontsel, TRUE);
1057 gtk_font_selection_on_clist_key_press (GtkWidget *clist,
1059 GtkFontSelection *fontsel)
1061 #ifdef FONTSEL_DEBUG
1062 g_message("In on_clist_key_press\n");
1064 if (event->keyval == GDK_Up)
1065 return gtk_font_selection_select_next (fontsel, clist, -1);
1066 else if (event->keyval == GDK_Down)
1067 return gtk_font_selection_select_next (fontsel, clist, 1);
1074 gtk_font_selection_select_next (GtkFontSelection *fontsel,
1079 gint current_row, row;
1081 selection = GTK_CLIST(clist)->selection;
1084 current_row = GPOINTER_TO_INT (selection->data);
1086 /* Stop the normal clist key handler from being run. */
1087 gtk_signal_emit_stop_by_name (GTK_OBJECT (clist), "key_press_event");
1089 for (row = current_row + step;
1090 row >= 0 && row < GTK_CLIST(clist)->rows;
1093 /* If this is the style clist, make sure that the item is not a charset
1095 if (clist == fontsel->font_style_clist)
1096 if (GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(clist), row)) == -1)
1099 /* Now we've found the row to select. */
1100 if (gtk_clist_row_is_visible(GTK_CLIST(clist), row)
1101 != GTK_VISIBILITY_FULL)
1102 gtk_clist_moveto(GTK_CLIST(clist), row, -1, (step < 0) ? 0 : 1, 0);
1103 gtk_clist_select_row(GTK_CLIST(clist), row, 0);
1110 /* This fills the font style clist with all the possible style combinations
1111 for the current font family. */
1113 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
1117 gint style, tmpstyle, row;
1118 gint weight_index, slant_index, set_width_index, spacing_index;
1120 gchar *weight, *slant, *set_width, *spacing;
1121 gchar *charset = NULL;
1123 gchar buffer[XLFD_MAX_FIELD_LEN * 6 + 2];
1124 GdkColor *inactive_fg, *inactive_bg;
1125 gboolean show_charset;
1127 #ifdef FONTSEL_DEBUG
1128 g_message("In show_available_styles\n");
1130 font = &fontsel_info->font_info[fontsel->font_index];
1131 styles = &fontsel_info->font_styles[font->style_index];
1133 gtk_clist_freeze (GTK_CLIST(fontsel->font_style_clist));
1134 gtk_clist_clear (GTK_CLIST(fontsel->font_style_clist));
1136 /* First we mark all visible styles as not having been displayed yet,
1137 and check if every style has the same charset. If not then we will
1138 display the charset in the list before the styles. */
1139 show_charset = FALSE;
1141 for (style = 0; style < font->nstyles; style++)
1143 if (gtk_font_selection_style_visible(fontsel, font, style))
1145 styles[style].flags &= ~GTK_FONT_DISPLAYED;
1147 if (charset_index == -1)
1148 charset_index = styles[style].properties[CHARSET];
1149 else if (charset_index != styles[style].properties[CHARSET])
1150 show_charset = TRUE;
1153 styles[style].flags |= GTK_FONT_DISPLAYED;
1156 /* Step through the undisplayed styles, finding the next charset which
1157 hasn't been displayed yet. Then display the charset on one line, if
1158 necessary, and the visible styles indented beneath it. */
1159 inactive_fg = &fontsel->font_style_clist->style->fg[GTK_STATE_INSENSITIVE];
1160 inactive_bg = &fontsel->font_style_clist->style->bg[GTK_STATE_INSENSITIVE];
1162 for (style = 0; style < font->nstyles; style++)
1164 if (styles[style].flags & GTK_FONT_DISPLAYED)
1169 charset_index = styles[style].properties[CHARSET];
1170 charset = fontsel_info->properties[CHARSET] [charset_index];
1171 row = gtk_clist_append(GTK_CLIST(fontsel->font_style_clist),
1173 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_style_clist), row,
1175 if (GTK_WIDGET_REALIZED (fontsel->font_style_clist))
1177 gtk_clist_set_foreground(GTK_CLIST(fontsel->font_style_clist),
1179 gtk_clist_set_background(GTK_CLIST(fontsel->font_style_clist),
1184 for (tmpstyle = style; tmpstyle < font->nstyles; tmpstyle++)
1186 if (styles[tmpstyle].flags & GTK_FONT_DISPLAYED
1187 || charset_index != styles[tmpstyle].properties[CHARSET])
1190 styles[tmpstyle].flags |= GTK_FONT_DISPLAYED;
1192 weight_index = styles[tmpstyle].properties[WEIGHT];
1193 slant_index = styles[tmpstyle].properties[SLANT];
1194 set_width_index = styles[tmpstyle].properties[SET_WIDTH];
1195 spacing_index = styles[tmpstyle].properties[SPACING];
1196 weight = fontsel_info->properties[WEIGHT] [weight_index];
1197 slant = fontsel_info->properties[SLANT] [slant_index];
1198 set_width = fontsel_info->properties[SET_WIDTH][set_width_index];
1199 spacing = fontsel_info->properties[SPACING] [spacing_index];
1201 /* Convert '(nil)' weights to 'regular', since it looks nicer. */
1202 if (!g_strcasecmp(weight, "(nil)")) weight = _("regular");
1204 /* We don't show default values or (nil) in the other properties. */
1205 if (!g_strcasecmp(slant, "r")) slant = NULL;
1206 else if (!g_strcasecmp(slant, "(nil)")) slant = NULL;
1207 else if (!g_strcasecmp(slant, "i")) slant = _("italic");
1208 else if (!g_strcasecmp(slant, "o")) slant = _("oblique");
1209 else if (!g_strcasecmp(slant, "ri")) slant = _("reverse italic");
1210 else if (!g_strcasecmp(slant, "ro")) slant = _("reverse oblique");
1211 else if (!g_strcasecmp(slant, "ot")) slant = _("other");
1213 if (!g_strcasecmp(set_width, "normal")) set_width = NULL;
1214 else if (!g_strcasecmp(set_width, "(nil)")) set_width = NULL;
1216 if (!g_strcasecmp(spacing, "p")) spacing = NULL;
1217 else if (!g_strcasecmp(spacing, "(nil)")) spacing = NULL;
1218 else if (!g_strcasecmp(spacing, "m")) spacing = _("[M]");
1219 else if (!g_strcasecmp(spacing, "c")) spacing = _("[C]");
1221 /* Add the strings together, making sure there is 1 space between
1223 strcpy(buffer, weight);
1226 strcat(buffer, " ");
1227 strcat(buffer, slant);
1231 strcat(buffer, " ");
1232 strcat(buffer, set_width);
1236 strcat(buffer, " ");
1237 strcat(buffer, spacing);
1241 row = gtk_clist_append(GTK_CLIST(fontsel->font_style_clist),
1244 gtk_clist_set_shift(GTK_CLIST(fontsel->font_style_clist), row, 0,
1246 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_style_clist), row,
1247 GINT_TO_POINTER (tmpstyle));
1251 gtk_clist_thaw (GTK_CLIST(fontsel->font_style_clist));
1255 /* This selects a style when the user selects a font. It just uses the first
1256 available style at present. I was thinking of trying to maintain the
1257 selected style, e.g. bold italic, when the user selects different fonts.
1258 However, the interface is so easy to use now I'm not sure it's worth it.
1259 Note: This will load a font. */
1261 gtk_font_selection_select_best_style(GtkFontSelection *fontsel,
1266 gint row, prop, style, matched;
1267 gint best_matched = -1, best_style = -1, best_row;
1269 #ifdef FONTSEL_DEBUG
1270 g_message("In select_best_style\n");
1272 font = &fontsel_info->font_info[fontsel->font_index];
1273 styles = &fontsel_info->font_styles[font->style_index];
1275 for (row = 0; row < GTK_CLIST(fontsel->font_style_clist)->rows; row++)
1277 style = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_style_clist), row));
1278 /* Skip charset rows. */
1282 /* If we just want the first style, we've got it. */
1291 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1293 if (fontsel->property_values[prop] == styles[style].properties[prop])
1296 if (matched > best_matched)
1298 best_matched = matched;
1303 g_return_if_fail (best_style != -1);
1305 fontsel->style = best_style;
1307 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1308 fontsel->property_values[prop] = styles[fontsel->style].properties[prop];
1310 gtk_clist_select_row(GTK_CLIST(fontsel->font_style_clist), best_row, 0);
1311 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_style_clist), best_row)
1312 != GTK_VISIBILITY_FULL)
1313 gtk_clist_moveto(GTK_CLIST(fontsel->font_style_clist), best_row, -1,
1315 gtk_font_selection_show_available_sizes (fontsel);
1316 gtk_font_selection_select_best_size (fontsel);
1320 /* This is called when a style is selected in the list. */
1322 gtk_font_selection_select_style (GtkWidget *w,
1325 GdkEventButton *bevent,
1328 GtkFontSelection *fontsel;
1329 FontInfo *font_info;
1335 #ifdef FONTSEL_DEBUG
1336 g_message("In select_style\n");
1338 fontsel = GTK_FONT_SELECTION(data);
1339 font_info = fontsel_info->font_info;
1340 font = &font_info[fontsel->font_index];
1341 styles = &fontsel_info->font_styles[font->style_index];
1343 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1344 gtk_widget_grab_focus (w);
1346 /* The style index is stored in the row data, so we just need to copy
1347 the style values into the fontsel and reload the font. */
1348 style = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(fontsel->font_style_clist), row));
1350 /* Don't allow selection of charset rows. */
1353 gtk_clist_unselect_row(GTK_CLIST(fontsel->font_style_clist), row, 0);
1357 gtk_clist_get_text(GTK_CLIST(fontsel->font_style_clist), row, 0, &text);
1358 gtk_entry_set_text(GTK_ENTRY(fontsel->font_style_entry), text);
1360 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1361 fontsel->property_values[prop] = styles[style].properties[prop];
1363 if (fontsel->style == style)
1366 fontsel->style = style;
1367 gtk_font_selection_show_available_sizes (fontsel);
1368 gtk_font_selection_select_best_size (fontsel);
1372 /* This shows all the available sizes in the size clist, according to the
1373 current metric and the current font & style. */
1375 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel)
1378 FontStyle *styles, *style;
1379 const guint16 *standard_sizes;
1380 guint16 *bitmapped_sizes, bitmap_size;
1381 gint nstandard_sizes, nbitmapped_sizes;
1382 gchar buffer[16], *size;
1383 gfloat bitmap_size_float;
1387 #ifdef FONTSEL_DEBUG
1388 g_message("In show_available_sizes\n");
1390 font = &fontsel_info->font_info[fontsel->font_index];
1391 styles = &fontsel_info->font_styles[font->style_index];
1392 style = &styles[fontsel->style];
1394 standard_sizes = font_sizes;
1395 nstandard_sizes = sizeof(font_sizes) / sizeof(font_sizes[0]);
1396 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1398 bitmapped_sizes = &fontsel_info->point_sizes[style->point_sizes_index];
1399 nbitmapped_sizes = style->npoint_sizes;
1403 bitmapped_sizes = &fontsel_info->pixel_sizes[style->pixel_sizes_index];
1404 nbitmapped_sizes = style->npixel_sizes;
1407 /* Only show the standard sizes if a scalable font is available. */
1408 type_filter = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
1409 & fontsel->filters[GTK_FONT_FILTER_USER].font_type;
1411 if (!((style->flags & GTK_FONT_SCALABLE_BITMAP
1412 && type_filter & GTK_FONT_SCALABLE_BITMAP)
1413 || (style->flags & GTK_FONT_SCALABLE
1414 && type_filter & GTK_FONT_SCALABLE)))
1415 nstandard_sizes = 0;
1417 gtk_clist_freeze (GTK_CLIST(fontsel->size_clist));
1418 gtk_clist_clear (GTK_CLIST(fontsel->size_clist));
1420 /* Interleave the standard sizes with the bitmapped sizes so we get a list
1421 of ascending sizes. If the metric is points, we have to convert the
1422 decipoints to points. */
1423 while (nstandard_sizes || nbitmapped_sizes)
1426 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1428 if (*bitmapped_sizes % 10 != 0)
1430 bitmap_size = *bitmapped_sizes / 10;
1431 bitmap_size_float = *bitmapped_sizes / 10;
1435 bitmap_size = *bitmapped_sizes;
1436 bitmap_size_float = *bitmapped_sizes;
1439 if (can_match && nstandard_sizes && nbitmapped_sizes
1440 && *standard_sizes == bitmap_size)
1442 sprintf(buffer, "%i *", *standard_sizes);
1448 else if (nstandard_sizes
1449 && (!nbitmapped_sizes
1450 || (gfloat)*standard_sizes < bitmap_size_float))
1452 sprintf(buffer, "%i", *standard_sizes);
1458 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1460 if (*bitmapped_sizes % 10 == 0)
1461 sprintf(buffer, "%i *", *bitmapped_sizes / 10);
1463 sprintf(buffer, "%i.%i *", *bitmapped_sizes / 10,
1464 *bitmapped_sizes % 10);
1468 sprintf(buffer, "%i *", *bitmapped_sizes);
1474 gtk_clist_append(GTK_CLIST(fontsel->size_clist), &size);
1476 gtk_clist_thaw (GTK_CLIST(fontsel->size_clist));
1480 /* If the user hits return in the font size entry, we change to the new font
1483 gtk_font_selection_size_key_press (GtkWidget *w,
1487 GtkFontSelection *fontsel;
1489 gfloat new_size_float;
1492 #ifdef FONTSEL_DEBUG
1493 g_message("In size_key_press\n");
1495 fontsel = GTK_FONT_SELECTION(data);
1497 if (event->keyval == GDK_Return)
1499 text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1500 if (fontsel->metric == GTK_FONT_METRIC_PIXELS)
1502 new_size = atoi (text);
1508 new_size_float = atof (text) * 10;
1509 new_size = (gint) new_size_float;
1514 /* Remember that this size was set explicitly. */
1515 fontsel->selected_size = new_size;
1517 /* Check if the font size has changed, and return if it hasn't. */
1518 if (fontsel->size == new_size)
1521 fontsel->size = new_size;
1522 gtk_font_selection_select_best_size (fontsel);
1530 /* This tries to select the closest size to the current size, though it
1531 may have to change the size if only unscaled bitmaps are available.
1532 Note: this will load a font. */
1534 gtk_font_selection_select_best_size(GtkFontSelection *fontsel)
1537 FontStyle *styles, *style;
1539 gint row, best_row = 0, size, size_fraction, best_size = 0, nmatched;
1540 gboolean found = FALSE;
1545 #ifdef FONTSEL_DEBUG
1546 g_message("In select_best_size\n");
1548 font = &fontsel_info->font_info[fontsel->font_index];
1549 styles = &fontsel_info->font_styles[font->style_index];
1550 style = &styles[fontsel->style];
1552 /* Find the closest size available in the size clist. If the exact size is
1553 in the list set found to TRUE. */
1554 for (row = 0; row < GTK_CLIST(fontsel->size_clist)->rows; row++)
1556 gtk_clist_get_text(GTK_CLIST(fontsel->size_clist), row, 0, &text);
1557 nmatched = sscanf(text, "%i.%i", &size, &size_fraction);
1558 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1562 size += size_fraction;
1565 if (size == fontsel->selected_size)
1572 else if (best_size == 0
1573 || abs(size - fontsel->selected_size)
1574 < (abs(best_size - fontsel->selected_size)))
1581 /* If we aren't scaling bitmapped fonts and this is a bitmapped font, we
1582 need to use the closest size found. */
1583 type_filter = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
1584 & fontsel->filters[GTK_FONT_FILTER_USER].font_type;
1586 if (!((style->flags & GTK_FONT_SCALABLE_BITMAP
1587 && type_filter & GTK_FONT_SCALABLE_BITMAP)
1588 || (style->flags & GTK_FONT_SCALABLE
1589 && type_filter & GTK_FONT_SCALABLE)))
1594 fontsel->size = best_size;
1595 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), best_row, -1, 0.5, 0);
1596 gtk_clist_select_row(GTK_CLIST(fontsel->size_clist), best_row, 0);
1600 fontsel->size = fontsel->selected_size;
1601 selection = GTK_CLIST(fontsel->size_clist)->selection;
1603 gtk_clist_unselect_row(GTK_CLIST(fontsel->size_clist),
1604 GPOINTER_TO_INT (selection->data), 0);
1605 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), best_row, -1, 0.5, 0);
1607 /* Show the size in the size entry. */
1608 if (fontsel->metric == GTK_FONT_METRIC_PIXELS)
1609 sprintf(buffer, "%i", fontsel->size);
1612 if (fontsel->size % 10 == 0)
1613 sprintf(buffer, "%i", fontsel->size / 10);
1615 sprintf(buffer, "%i.%i", fontsel->size / 10, fontsel->size % 10);
1617 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
1619 gtk_font_selection_load_font (fontsel);
1623 /* This is called when a size is selected in the list. */
1625 gtk_font_selection_select_size (GtkWidget *w,
1628 GdkEventButton *bevent,
1631 GtkFontSelection *fontsel;
1637 #ifdef FONTSEL_DEBUG
1638 g_message("In select_size\n");
1640 fontsel = GTK_FONT_SELECTION(data);
1642 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1643 gtk_widget_grab_focus (w);
1645 /* Copy the size from the clist to the size entry, but without the bitmapped
1647 gtk_clist_get_text(GTK_CLIST(fontsel->size_clist), row, 0, &text);
1649 while (i < 15 && (text[i] == '.' || (text[i] >= '0' && text[i] <= '9')))
1651 buffer[i] = text[i];
1655 gtk_entry_set_text(GTK_ENTRY(fontsel->size_entry), buffer);
1657 /* Check if the font size has changed, and return if it hasn't. */
1658 new_size = atoi(text);
1659 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1662 if (fontsel->size == new_size)
1665 /* If the size was selected by the user we set the selected_size. */
1666 fontsel->selected_size = new_size;
1668 fontsel->size = new_size;
1669 gtk_font_selection_load_font (fontsel);
1673 /* This is called when the pixels or points radio buttons are pressed. */
1675 gtk_font_selection_metric_callback (GtkWidget *w,
1678 GtkFontSelection *fontsel = GTK_FONT_SELECTION(data);
1680 #ifdef FONTSEL_DEBUG
1681 g_message("In metric_callback\n");
1683 if (GTK_TOGGLE_BUTTON(fontsel->pixels_button)->active)
1685 if (fontsel->metric == GTK_FONT_METRIC_PIXELS)
1687 fontsel->metric = GTK_FONT_METRIC_PIXELS;
1688 fontsel->size = (fontsel->size + 5) / 10;
1689 fontsel->selected_size = (fontsel->selected_size + 5) / 10;
1693 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1695 fontsel->metric = GTK_FONT_METRIC_POINTS;
1696 fontsel->size *= 10;
1697 fontsel->selected_size *= 10;
1699 if (fontsel->font_index != -1)
1701 gtk_font_selection_show_available_sizes (fontsel);
1702 gtk_font_selection_select_best_size (fontsel);
1707 /* This searches the given property table and returns the index of the given
1708 string, or 0, which is the wildcard '*' index, if it's not found. */
1710 gtk_font_selection_field_to_index (gchar **table,
1716 for (i = 0; i < ntable; i++)
1717 if (strcmp (field, table[i]) == 0)
1725 /* This attempts to load the current font, and returns TRUE if it succeeds. */
1727 gtk_font_selection_load_font (GtkFontSelection *fontsel)
1730 gchar *fontname, *label_text;
1733 gdk_font_unref (fontsel->font);
1734 fontsel->font = NULL;
1736 /* If no family has been selected yet, just return FALSE. */
1737 if (fontsel->font_index == -1)
1740 fontname = gtk_font_selection_get_font_name (fontsel);
1743 #ifdef FONTSEL_DEBUG
1744 g_message("Loading: %s\n", fontname);
1746 font = gdk_font_load (fontname);
1751 fontsel->font = font;
1752 /* Make sure the message label is empty, but don't change it unless
1753 it's necessary as it results in a resize of the whole window! */
1754 gtk_label_get(GTK_LABEL(fontsel->message_label), &label_text);
1755 if (strcmp(label_text, ""))
1756 gtk_label_set_text(GTK_LABEL(fontsel->message_label), "");
1757 gtk_font_selection_update_preview (fontsel);
1762 gtk_label_set_text(GTK_LABEL(fontsel->message_label),
1763 _("The selected font is not available."));
1768 gtk_label_set_text(GTK_LABEL(fontsel->message_label),
1769 _("The selected font is not a valid font."));
1776 /* This sets the font in the preview entry to the selected font, and tries to
1777 make sure that the preview entry is a reasonable size, i.e. so that the
1778 text can be seen with a bit of space to spare. But it tries to avoid
1779 resizing the entry every time the font changes.
1780 This also used to shrink the preview if the font size was decreased, but
1781 that made it awkward if the user wanted to resize the window themself. */
1783 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1785 GtkWidget *preview_entry;
1787 gint text_height, new_height;
1791 #ifdef FONTSEL_DEBUG
1792 g_message("In update_preview\n");
1794 style = gtk_style_new ();
1795 gdk_font_unref (style->font);
1796 style->font = fontsel->font;
1797 gdk_font_ref (style->font);
1799 preview_entry = fontsel->preview_entry;
1800 gtk_widget_set_style (preview_entry, style);
1801 gtk_style_unref(style);
1803 text_height = preview_entry->style->font->ascent
1804 + preview_entry->style->font->descent;
1805 /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1806 new_height = text_height + 20;
1807 if (new_height < INITIAL_PREVIEW_HEIGHT)
1808 new_height = INITIAL_PREVIEW_HEIGHT;
1809 if (new_height > MAX_PREVIEW_HEIGHT)
1810 new_height = MAX_PREVIEW_HEIGHT;
1812 if ((preview_entry->requisition.height < text_height + 10)
1813 || (preview_entry->requisition.height > text_height + 40))
1814 gtk_widget_set_usize(preview_entry, -1, new_height);
1816 /* This sets the preview text, if it hasn't been set already. */
1817 text = gtk_entry_get_text(GTK_ENTRY(fontsel->preview_entry));
1818 if (strlen(text) == 0)
1819 gtk_entry_set_text(GTK_ENTRY(fontsel->preview_entry), PREVIEW_TEXT);
1820 gtk_entry_set_position(GTK_ENTRY(fontsel->preview_entry), 0);
1822 /* If this is a 2-byte font display a message to say it may not be
1823 displayed properly. */
1824 xfs = GDK_FONT_XFONT(fontsel->font);
1825 if (xfs->min_byte1 != 0 || xfs->max_byte1 != 0)
1826 gtk_label_set_text(GTK_LABEL(fontsel->message_label),
1827 _("This is a 2-byte font and may not be displayed correctly."));
1832 gtk_font_selection_switch_page (GtkWidget *w,
1833 GtkNotebookPage *page,
1837 GtkFontSelection *fontsel = GTK_FONT_SELECTION(data);
1839 /* This function strangely gets called when the window is destroyed,
1840 so we check here to see if the notebook is visible. */
1841 if (!GTK_WIDGET_VISIBLE(w))
1845 gtk_font_selection_update_filter(fontsel);
1846 else if (page_num == 1)
1847 gtk_font_selection_show_font_info(fontsel);
1852 gtk_font_selection_show_font_info (GtkFontSelection *fontsel)
1854 Atom font_atom, atom;
1858 gchar field_buffer[XLFD_MAX_FIELD_LEN];
1861 gboolean shown_actual_fields = FALSE;
1863 fontname = gtk_font_selection_get_font_name(fontsel);
1864 gtk_entry_set_text(GTK_ENTRY(fontsel->requested_font_name),
1865 fontname ? fontname : "");
1867 gtk_clist_freeze (GTK_CLIST(fontsel->info_clist));
1868 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1871 field = gtk_font_selection_get_xlfd_field (fontname, i, field_buffer);
1876 if (i == XLFD_SLANT)
1877 field = gtk_font_selection_expand_slant_code(field);
1878 else if (i == XLFD_SPACING)
1879 field = gtk_font_selection_expand_spacing_code(field);
1881 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 1,
1882 field ? field : "");
1887 font_atom = XInternAtom(GDK_DISPLAY(), "FONT", True);
1888 if (font_atom != None)
1890 status = XGetFontProperty(GDK_FONT_XFONT(fontsel->font), font_atom,
1894 name = XGetAtomName(GDK_DISPLAY(), atom);
1895 gtk_entry_set_text(GTK_ENTRY(fontsel->actual_font_name), name);
1897 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1899 field = gtk_font_selection_get_xlfd_field (name, i,
1901 if (i == XLFD_SLANT)
1902 field = gtk_font_selection_expand_slant_code(field);
1903 else if (i == XLFD_SPACING)
1904 field = gtk_font_selection_expand_spacing_code(field);
1905 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 2,
1906 field ? field : "");
1908 shown_actual_fields = TRUE;
1913 if (!shown_actual_fields)
1915 gtk_entry_set_text(GTK_ENTRY(fontsel->actual_font_name), "");
1916 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1918 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 2,
1919 fontname ? _("(unknown)") : "");
1922 gtk_clist_thaw (GTK_CLIST(fontsel->info_clist));
1928 gtk_font_selection_expand_slant_code(gchar *slant)
1930 if (!g_strcasecmp(slant, "r")) return(_("roman"));
1931 else if (!g_strcasecmp(slant, "i")) return(_("italic"));
1932 else if (!g_strcasecmp(slant, "o")) return(_("oblique"));
1933 else if (!g_strcasecmp(slant, "ri")) return(_("reverse italic"));
1934 else if (!g_strcasecmp(slant, "ro")) return(_("reverse oblique"));
1935 else if (!g_strcasecmp(slant, "ot")) return(_("other"));
1940 gtk_font_selection_expand_spacing_code(gchar *spacing)
1942 if (!g_strcasecmp(spacing, "p")) return(_("proportional"));
1943 else if (!g_strcasecmp(spacing, "m")) return(_("monospaced"));
1944 else if (!g_strcasecmp(spacing, "c")) return(_("char cell"));
1949 /*****************************************************************************
1950 * These functions all deal with the Filter page and filtering the fonts.
1951 *****************************************************************************/
1953 /* This is called when an item is selected in one of the filter clists.
1954 We make sure that the first row of the clist, i.e. the wildcard '*', is
1955 selected if and only if none of the other items are selected.
1956 Also doesn't allow selections of values filtered out by base filter.
1957 We may need to be careful about triggering other signals. */
1959 gtk_font_selection_select_filter (GtkWidget *w,
1962 GdkEventButton *bevent,
1963 GtkFontSelection *fontsel)
1965 gint i, prop, index;
1969 for (i = 1; i < GTK_CLIST(w)->rows; i++)
1970 gtk_clist_unselect_row(GTK_CLIST(w), i, 0);
1974 /* Find out which property this is. */
1975 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
1976 if (fontsel->filter_clists[prop] == w)
1978 index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(w), row));
1979 if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_BASE,
1980 prop, index) == NOT_FILTERED)
1981 gtk_clist_unselect_row(GTK_CLIST(w), row, 0);
1983 gtk_clist_unselect_row(GTK_CLIST(w), 0, 0);
1988 /* Here a filter item is being deselected. If there are now no items selected
1989 we select the first '*' item, unless that it is the item being deselected,
1990 in which case we select all of the other items. This makes it easy to
1991 select all items in the list except one or two. */
1993 gtk_font_selection_unselect_filter (GtkWidget *w,
1996 GdkEventButton *bevent,
1997 GtkFontSelection *fontsel)
1999 gint i, prop, index;
2001 if (!GTK_CLIST(w)->selection)
2005 /* Find out which property this is. */
2006 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2007 if (fontsel->filter_clists[prop] == w)
2010 for (i = 1; i < GTK_CLIST(w)->rows; i++)
2012 index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(w),
2014 if (gtk_font_selection_filter_state (fontsel,
2015 GTK_FONT_FILTER_BASE,
2018 gtk_clist_select_row(GTK_CLIST(w), i, 0);
2023 gtk_clist_select_row(GTK_CLIST(w), 0, 0);
2029 /* This is called when the main notebook page is selected. It checks if the
2030 filter has changed, an if so it creates the filter settings, and filters the
2031 fonts shown. If an empty filter (all '*'s) is applied, then filtering is
2034 gtk_font_selection_update_filter (GtkFontSelection *fontsel)
2038 gboolean default_filter = TRUE, filter_changed = FALSE;
2039 gint prop, nselected, i, row, index;
2040 GtkFontFilter *filter = &fontsel->filters[GTK_FONT_FILTER_USER];
2041 gint base_font_type, user_font_type, new_font_type;
2043 #ifdef FONTSEL_DEBUG
2044 g_message("In update_filter\n");
2047 /* Check if the user filter has changed, and also if it is the default
2048 filter, i.e. bitmap & scalable fonts and all '*'s selected.
2049 We only look at the bits which are not already filtered out by the base
2050 filter, since that overrides the user filter. */
2051 base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
2053 user_font_type = fontsel->filters[GTK_FONT_FILTER_USER].font_type
2055 new_font_type = GTK_TOGGLE_BUTTON(fontsel->type_bitmaps_button)->active
2056 ? GTK_FONT_BITMAP : 0;
2057 new_font_type |= (GTK_TOGGLE_BUTTON(fontsel->type_scalable_button)->active
2058 ? GTK_FONT_SCALABLE : 0);
2059 new_font_type |= (GTK_TOGGLE_BUTTON(fontsel->type_scaled_bitmaps_button)->active ? GTK_FONT_SCALABLE_BITMAP : 0);
2060 new_font_type &= base_font_type;
2061 new_font_type |= (~base_font_type & user_font_type);
2062 if (new_font_type != (GTK_FONT_BITMAP | GTK_FONT_SCALABLE))
2063 default_filter = FALSE;
2065 if (new_font_type != user_font_type)
2066 filter_changed = TRUE;
2067 fontsel->filters[GTK_FONT_FILTER_USER].font_type = new_font_type;
2069 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2071 clist = fontsel->filter_clists[prop];
2072 selection = GTK_CLIST(clist)->selection;
2073 nselected = g_list_length(selection);
2074 if (nselected != 1 || GPOINTER_TO_INT (selection->data) != 0)
2076 default_filter = FALSE;
2078 if (filter->property_nfilters[prop] != nselected)
2079 filter_changed = TRUE;
2082 for (i = 0; i < nselected; i++)
2084 row = GPOINTER_TO_INT (selection->data);
2085 index = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (clist), row));
2086 if (filter->property_filters[prop][i] != index)
2087 filter_changed = TRUE;
2088 selection = selection->next;
2094 if (filter->property_nfilters[prop] != 0)
2095 filter_changed = TRUE;
2099 /* If the filter hasn't changed we just return. */
2100 if (!filter_changed)
2103 #ifdef FONTSEL_DEBUG
2104 g_message(" update_fonts: filter has changed\n");
2107 /* Free the old filter data and create the new arrays. */
2108 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2110 g_free(filter->property_filters[prop]);
2112 clist = fontsel->filter_clists[prop];
2113 selection = GTK_CLIST(clist)->selection;
2114 nselected = g_list_length(selection);
2115 if (nselected == 1 && GPOINTER_TO_INT (selection->data) == 0)
2117 filter->property_filters[prop] = NULL;
2118 filter->property_nfilters[prop] = 0;
2122 filter->property_filters[prop] = g_new(guint16, nselected);
2123 filter->property_nfilters[prop] = nselected;
2124 for (i = 0; i < nselected; i++)
2126 row = GPOINTER_TO_INT (selection->data);
2127 index = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (clist), row));
2128 filter->property_filters[prop][i] = index;
2129 selection = selection->next;
2134 /* Set the 'Reset Filter' button sensitive if a filter is in effect, and
2135 also set the label above the font list to show this as well. */
2138 gtk_widget_set_sensitive(fontsel->filter_button, FALSE);
2139 gtk_label_set_text(GTK_LABEL(fontsel->font_label), _("Font:"));
2143 gtk_widget_set_sensitive(fontsel->filter_button, TRUE);
2144 gtk_label_set_text(GTK_LABEL(fontsel->font_label), _("Font: (Filter Applied)"));
2146 gtk_font_selection_show_available_fonts(fontsel);
2150 /* This shows all the available fonts in the font clist. */
2152 gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
2154 FontInfo *font_info, *font;
2155 GtkFontFilter *filter;
2156 gint nfonts, i, j, k, row, style, font_row = -1;
2157 gchar font_buffer[XLFD_MAX_FIELD_LEN * 2 + 4];
2159 gboolean matched, matched_style;
2161 #ifdef FONTSEL_DEBUG
2162 g_message("In show_available_fonts\n");
2164 font_info = fontsel_info->font_info;
2165 nfonts = fontsel_info->nfonts;
2167 /* Filter the list of fonts. */
2168 gtk_clist_freeze (GTK_CLIST(fontsel->font_clist));
2169 gtk_clist_clear (GTK_CLIST(fontsel->font_clist));
2170 for (i = 0; i < nfonts; i++)
2172 font = &font_info[i];
2174 /* Check if the foundry passes through all filters. */
2176 for (k = 0; k < GTK_NUM_FONT_FILTERS; k++)
2178 filter = &fontsel->filters[k];
2180 if (filter->property_nfilters[FOUNDRY] != 0)
2183 for (j = 0; j < filter->property_nfilters[FOUNDRY]; j++)
2185 if (font->foundry == filter->property_filters[FOUNDRY][j])
2200 /* Now check if the other properties are matched in at least one style.*/
2201 matched_style = FALSE;
2202 for (style = 0; style < font->nstyles; style++)
2204 if (gtk_font_selection_style_visible(fontsel, font, style))
2206 matched_style = TRUE;
2213 /* Insert the font in the clist. */
2214 if ((i > 0 && font->family == font_info[i-1].family)
2215 || (i < nfonts - 1 && font->family == font_info[i+1].family))
2217 sprintf(font_buffer, "%s (%s)", font->family,
2218 fontsel_info->properties[FOUNDRY][font->foundry]);
2219 font_item = font_buffer;
2220 row = gtk_clist_append(GTK_CLIST(fontsel->font_clist), &font_item);
2224 row = gtk_clist_append(GTK_CLIST(fontsel->font_clist),
2227 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_clist), row,
2228 GINT_TO_POINTER (i));
2229 if (fontsel->font_index == i)
2232 gtk_clist_thaw (GTK_CLIST(fontsel->font_clist));
2234 /* If the currently-selected font isn't in the new list, reset the
2238 fontsel->font_index = -1;
2240 gdk_font_unref(fontsel->font);
2241 fontsel->font = NULL;
2242 gtk_entry_set_text(GTK_ENTRY(fontsel->font_entry), "");
2243 gtk_clist_clear (GTK_CLIST(fontsel->font_style_clist));
2244 gtk_entry_set_text(GTK_ENTRY(fontsel->font_style_entry), "");
2248 gtk_clist_select_row(GTK_CLIST(fontsel->font_clist), font_row, 0);
2249 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_clist), font_row)
2250 != GTK_VISIBILITY_FULL)
2251 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), font_row, -1, 0.5, 0);
2253 gtk_font_selection_show_available_styles (fontsel);
2254 gtk_font_selection_select_best_style (fontsel, FALSE);
2258 /* Returns TRUE if the style is not currently filtered out. */
2260 gtk_font_selection_style_visible(GtkFontSelection *fontsel,
2264 FontStyle *styles, *style;
2265 GtkFontFilter *filter;
2271 styles = &fontsel_info->font_styles[font->style_index];
2272 style = &styles[style_index];
2274 /* Check if font_type of style is filtered. */
2275 type_filter = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
2276 & fontsel->filters[GTK_FONT_FILTER_USER].font_type;
2277 if (!(style->flags & type_filter))
2280 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2282 value = style->properties[prop];
2284 /* Check each filter. */
2285 for (i = 0; i < GTK_NUM_FONT_FILTERS; i++)
2287 filter = &fontsel->filters[i];
2289 if (filter->property_nfilters[prop] != 0)
2292 for (j = 0; j < filter->property_nfilters[prop]; j++)
2294 if (value == filter->property_filters[prop][j])
2309 /* This resets the font type to bitmap or scalable, and sets all the filter
2310 clists to the wildcard '*' options. */
2312 gtk_font_selection_reset_filter (GtkWidget *w,
2313 GtkFontSelection *fontsel)
2315 gint prop, base_font_type;
2317 fontsel->filters[GTK_FONT_FILTER_USER].font_type = GTK_FONT_BITMAP
2318 | GTK_FONT_SCALABLE;
2320 base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type;
2321 if (base_font_type & GTK_FONT_BITMAP)
2322 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), TRUE);
2323 if (base_font_type & GTK_FONT_SCALABLE)
2324 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), TRUE);
2325 if (base_font_type & GTK_FONT_SCALABLE_BITMAP)
2326 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), FALSE);
2328 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2329 gtk_clist_select_row(GTK_CLIST(fontsel->filter_clists[prop]), 0, 0);
2333 /* This clears the filter, showing all fonts and styles again. */
2335 gtk_font_selection_on_clear_filter (GtkWidget *w,
2336 GtkFontSelection *fontsel)
2338 gtk_font_selection_clear_filter(fontsel);
2342 /* This resets the user filter, showing all fonts and styles which pass the
2343 base filter again. Note that the font type is set to bitmaps and scalable
2344 fonts - scaled bitmaps are not shown. */
2346 gtk_font_selection_clear_filter (GtkFontSelection *fontsel)
2348 GtkFontFilter *filter;
2351 #ifdef FONTSEL_DEBUG
2352 g_message("In clear_filter\n");
2354 /* Clear the filter data. */
2355 filter = &fontsel->filters[GTK_FONT_FILTER_USER];
2356 filter->font_type = GTK_FONT_BITMAP | GTK_FONT_SCALABLE;
2357 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2359 g_free(filter->property_filters[prop]);
2360 filter->property_filters[prop] = NULL;
2361 filter->property_nfilters[prop] = 0;
2364 /* Select all the '*'s on the filter page. */
2365 gtk_font_selection_reset_filter(NULL, fontsel);
2367 /* Update the main notebook page. */
2368 gtk_widget_set_sensitive(fontsel->filter_button, FALSE);
2369 gtk_label_set_text(GTK_LABEL(fontsel->font_label), _("Font:"));
2371 gtk_font_selection_show_available_fonts(fontsel);
2376 gtk_font_selection_set_filter (GtkFontSelection *fontsel,
2377 GtkFontFilterType filter_type,
2378 GtkFontType font_type,
2386 GtkFontFilter *filter;
2387 gchar **filter_strings [GTK_NUM_FONT_PROPERTIES];
2388 gchar *filter_string;
2389 gchar *property, *property_alt;
2390 gint prop, nfilters, i, j, num_found;
2391 gint base_font_type, user_font_type;
2392 gboolean filter_set;
2394 /* Put them into an array so we can use a simple loop. */
2395 filter_strings[FOUNDRY] = foundries;
2396 filter_strings[WEIGHT] = weights;
2397 filter_strings[SLANT] = slants;
2398 filter_strings[SET_WIDTH] = setwidths;
2399 filter_strings[SPACING] = spacings;
2400 filter_strings[CHARSET] = charsets;
2402 filter = &fontsel->filters[filter_type];
2403 filter->font_type = font_type;
2405 /* Free the old filter data, and insert the new. */
2406 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2408 g_free(filter->property_filters[prop]);
2409 filter->property_filters[prop] = NULL;
2410 filter->property_nfilters[prop] = 0;
2412 if (filter_strings[prop])
2414 /* Count how many items in the new array. */
2416 while (filter_strings[prop][nfilters])
2419 filter->property_filters[prop] = g_new(guint16, nfilters);
2420 filter->property_nfilters[prop] = 0;
2422 /* Now convert the strings to property indices. */
2424 for (i = 0; i < nfilters; i++)
2426 filter_string = filter_strings[prop][i];
2427 for (j = 0; j < fontsel_info->nproperties[prop]; j++)
2429 property = fontsel_info->properties[prop][j];
2430 property_alt = NULL;
2432 property_alt = gtk_font_selection_expand_slant_code(property);
2433 else if (prop == SPACING)
2434 property_alt = gtk_font_selection_expand_spacing_code(property);
2435 if (!strcmp (filter_string, property)
2436 || (property_alt && !strcmp (filter_string, property_alt)))
2438 filter->property_filters[prop][num_found] = j;
2444 filter->property_nfilters[prop] = num_found;
2448 /* Now set the clists on the filter page according to the new filter. */
2449 gtk_font_selection_update_filter_lists (fontsel);
2451 if (filter_type == GTK_FONT_FILTER_BASE)
2453 user_font_type = fontsel->filters[GTK_FONT_FILTER_USER].font_type;
2454 if (font_type & GTK_FONT_BITMAP)
2456 gtk_widget_set_sensitive (fontsel->type_bitmaps_button, TRUE);
2457 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), user_font_type & GTK_FONT_BITMAP);
2461 gtk_widget_set_sensitive (fontsel->type_bitmaps_button, FALSE);
2462 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), FALSE);
2465 if (font_type & GTK_FONT_SCALABLE)
2467 gtk_widget_set_sensitive (fontsel->type_scalable_button, TRUE);
2468 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), user_font_type & GTK_FONT_SCALABLE);
2472 gtk_widget_set_sensitive (fontsel->type_scalable_button, FALSE);
2473 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), FALSE);
2476 if (font_type & GTK_FONT_SCALABLE_BITMAP)
2478 gtk_widget_set_sensitive (fontsel->type_scaled_bitmaps_button, TRUE);
2479 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), user_font_type & GTK_FONT_SCALABLE_BITMAP);
2483 gtk_widget_set_sensitive (fontsel->type_scaled_bitmaps_button, FALSE);
2484 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), FALSE);
2489 base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type;
2490 if (base_font_type & GTK_FONT_BITMAP)
2491 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), font_type & GTK_FONT_BITMAP);
2493 if (base_font_type & GTK_FONT_SCALABLE)
2494 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), font_type & GTK_FONT_SCALABLE);
2496 if (base_font_type & GTK_FONT_SCALABLE_BITMAP)
2497 gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), font_type & GTK_FONT_SCALABLE_BITMAP);
2499 /* If the user filter is not the default, make the 'Reset Filter' button
2502 if (font_type != (GTK_FONT_BITMAP | GTK_FONT_SCALABLE))
2504 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2506 if (filter->property_nfilters[prop] != 0)
2510 gtk_widget_set_sensitive (fontsel->filter_button, TRUE);
2513 gtk_font_selection_show_available_fonts (fontsel);
2517 /* This sets the colour of each property in the filter clists according to
2518 the base filter. i.e. Filtered properties are shown as insensitive. */
2520 gtk_font_selection_update_filter_lists (GtkFontSelection *fontsel)
2523 GdkColor *inactive_fg, *inactive_bg, *fg, *bg;
2524 gint prop, row, index;
2526 /* We have to make sure the clist is realized to use the colours. */
2527 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2529 clist = fontsel->filter_clists[prop];
2530 gtk_widget_realize (clist);
2531 inactive_fg = &clist->style->fg[GTK_STATE_INSENSITIVE];
2532 inactive_bg = &clist->style->bg[GTK_STATE_INSENSITIVE];
2533 for (row = 1; row < GTK_CLIST(clist)->rows; row++)
2535 index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(clist),
2537 /* Set the colour according to the base filter. */
2538 if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_BASE,
2539 prop, index) == NOT_FILTERED)
2549 gtk_clist_set_foreground(GTK_CLIST(clist), row, fg);
2550 gtk_clist_set_background(GTK_CLIST(clist), row, bg);
2552 /* Set the selection state according to the user filter. */
2553 if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_USER,
2554 prop, index) == FILTERED
2556 gtk_clist_select_row (GTK_CLIST (clist), row, 0);
2558 gtk_clist_unselect_row (GTK_CLIST (clist), row, 0);
2564 /* Returns whether a property value is in the filter or not, or if the
2565 property has no filter set. */
2566 static GtkFontPropertyFilterState
2567 gtk_font_selection_filter_state (GtkFontSelection *fontsel,
2568 GtkFontFilterType filter_type,
2572 GtkFontFilter *filter;
2575 filter = &fontsel->filters[filter_type];
2576 if (filter->property_nfilters[property] == 0)
2579 for (i = 0; i < filter->property_nfilters[property]; i++)
2581 if (filter->property_filters[property][i] == index)
2584 return NOT_FILTERED;
2588 /*****************************************************************************
2589 * These functions all deal with creating the main class arrays containing
2590 * the data about all available fonts.
2591 *****************************************************************************/
2593 gtk_font_selection_get_fonts (void)
2600 gint i, prop, style, size;
2601 gint npixel_sizes = 0, npoint_sizes = 0;
2603 FontStyle *current_style, *prev_style, *tmp_style;
2604 gboolean matched_style, found_size;
2605 gint pixels, points, res_x, res_y;
2606 gchar field_buffer[XLFD_MAX_FIELD_LEN];
2609 guint16 *pixel_sizes, *point_sizes, *tmp_sizes;
2611 fontsel_info = g_new (GtkFontSelInfo, 1);
2613 /* Get a maximum of MAX_FONTS fontnames from the X server.
2614 Use "-*" as the pattern rather than "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" since
2615 the latter may result in fonts being returned which don't actually exist.
2616 xlsfonts also uses "*" so I think it's OK. "-*" gets rid of aliases. */
2617 xfontnames = XListFonts (GDK_DISPLAY(), "-*", MAX_FONTS, &num_fonts);
2618 /* Output a warning if we actually get MAX_FONTS fonts. */
2619 if (num_fonts == MAX_FONTS)
2620 g_warning(_("MAX_FONTS exceeded. Some fonts may be missing."));
2622 /* The maximum size of all these tables is the number of font names
2623 returned. We realloc them later when we know exactly how many
2624 unique entries there are. */
2625 fontsel_info->font_info = g_new (FontInfo, num_fonts);
2626 fontsel_info->font_styles = g_new (FontStyle, num_fonts);
2627 fontsel_info->pixel_sizes = g_new (guint16, num_fonts);
2628 fontsel_info->point_sizes = g_new (guint16, num_fonts);
2630 fontnames = g_new (GSList*, num_fonts);
2632 /* Create the initial arrays for the property value strings, though they
2633 may be realloc'ed later. Put the wildcard '*' in the first elements. */
2634 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2636 fontsel_info->properties[prop] = g_new(gchar*, PROPERTY_ARRAY_INCREMENT);
2637 fontsel_info->space_allocated[prop] = PROPERTY_ARRAY_INCREMENT;
2638 fontsel_info->nproperties[prop] = 1;
2639 fontsel_info->properties[prop][0] = "*";
2643 /* Insert the font families into the main table, sorted by family and
2644 foundry (fonts with different foundries are placed in seaparate FontInfos.
2645 All fontnames in each family + foundry are placed into the fontnames
2647 fontsel_info->nfonts = 0;
2648 for (i = 0; i < num_fonts; i++)
2650 #ifdef FONTSEL_DEBUG
2651 g_message("%s\n", xfontnames[i]);
2653 if (gtk_font_selection_is_xlfd_font_name (xfontnames[i]))
2654 gtk_font_selection_insert_font (fontnames, &fontsel_info->nfonts, xfontnames[i]);
2657 #ifdef FONTSEL_DEBUG
2658 g_warning("Skipping invalid font: %s", xfontnames[i]);
2664 /* Since many font names will be in the same FontInfo not all of the
2665 allocated FontInfo table will be used, so we will now reallocate it
2666 with the real size. */
2667 fontsel_info->font_info = g_realloc(fontsel_info->font_info,
2668 sizeof(FontInfo) * fontsel_info->nfonts);
2671 /* Now we work out which choices of weight/slant etc. are valid for each
2673 fontsel_info->nstyles = 0;
2674 current_style = fontsel_info->font_styles;
2675 for (i = 0; i < fontsel_info->nfonts; i++)
2677 font = &fontsel_info->font_info[i];
2679 /* Use the next free position in the styles array. */
2680 font->style_index = fontsel_info->nstyles;
2682 /* Now step through each of the fontnames with this family, and create
2683 a style for each fontname. Each style contains the index into the
2684 weights/slants etc. arrays, and a number of pixel/point sizes. */
2686 temp_list = fontnames[i];
2689 fontname = temp_list->data;
2690 temp_list = temp_list->next;
2692 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2694 current_style->properties[prop]
2695 = gtk_font_selection_insert_field (fontname, prop);
2697 current_style->pixel_sizes_index = npixel_sizes;
2698 current_style->npixel_sizes = 0;
2699 current_style->point_sizes_index = npoint_sizes;
2700 current_style->npoint_sizes = 0;
2701 current_style->flags = 0;
2704 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_PIXELS,
2706 pixels = atoi(field);
2708 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_POINTS,
2710 points = atoi(field);
2712 field = gtk_font_selection_get_xlfd_field (fontname,
2715 res_x = atoi(field);
2717 field = gtk_font_selection_get_xlfd_field (fontname,
2720 res_y = atoi(field);
2722 if (pixels == 0 && points == 0)
2724 if (res_x == 0 && res_y == 0)
2725 flags = GTK_FONT_SCALABLE;
2727 flags = GTK_FONT_SCALABLE_BITMAP;
2730 flags = GTK_FONT_BITMAP;
2732 /* Now we check to make sure that the style is unique. If it isn't
2734 prev_style = fontsel_info->font_styles + font->style_index;
2735 matched_style = FALSE;
2736 while (prev_style < current_style)
2738 matched_style = TRUE;
2739 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2741 if (prev_style->properties[prop]
2742 != current_style->properties[prop])
2744 matched_style = FALSE;
2753 /* If we matched an existing style, we need to add the pixels &
2754 point sizes to the style. If not, we insert the pixel & point
2755 sizes into our new style. Note that we don't add sizes for
2759 prev_style->flags |= flags;
2760 if (flags == GTK_FONT_BITMAP)
2762 pixel_sizes = fontsel_info->pixel_sizes
2763 + prev_style->pixel_sizes_index;
2765 for (size = 0; size < prev_style->npixel_sizes; size++)
2767 if (pixels == *pixel_sizes)
2772 else if (pixels < *pixel_sizes)
2776 /* We need to move all the following pixel sizes up, and also
2777 update the indexes of any following styles. */
2780 for (tmp_sizes = fontsel_info->pixel_sizes + npixel_sizes;
2781 tmp_sizes > pixel_sizes; tmp_sizes--)
2782 *tmp_sizes = *(tmp_sizes - 1);
2784 *pixel_sizes = pixels;
2786 prev_style->npixel_sizes++;
2788 tmp_style = prev_style + 1;
2789 while (tmp_style < current_style)
2791 tmp_style->pixel_sizes_index++;
2796 point_sizes = fontsel_info->point_sizes
2797 + prev_style->point_sizes_index;
2799 for (size = 0; size < prev_style->npoint_sizes; size++)
2801 if (points == *point_sizes)
2806 else if (points < *point_sizes)
2810 /* We need to move all the following point sizes up, and also
2811 update the indexes of any following styles. */
2814 for (tmp_sizes = fontsel_info->point_sizes + npoint_sizes;
2815 tmp_sizes > point_sizes; tmp_sizes--)
2816 *tmp_sizes = *(tmp_sizes - 1);
2818 *point_sizes = points;
2820 prev_style->npoint_sizes++;
2822 tmp_style = prev_style + 1;
2823 while (tmp_style < current_style)
2825 tmp_style->point_sizes_index++;
2833 current_style->flags = flags;
2834 if (flags == GTK_FONT_BITMAP)
2836 fontsel_info->pixel_sizes[npixel_sizes++] = pixels;
2837 current_style->npixel_sizes = 1;
2838 fontsel_info->point_sizes[npoint_sizes++] = points;
2839 current_style->npoint_sizes = 1;
2842 fontsel_info->nstyles++;
2846 g_slist_free(fontnames[i]);
2848 /* Set nstyles to the real value, minus duplicated fontnames.
2849 Note that we aren't using all the allocated memory if fontnames are
2851 font->nstyles = style;
2854 /* Since some repeated styles may be skipped we won't have used all the
2855 allocated space, so we will now reallocate it with the real size. */
2856 fontsel_info->font_styles = g_realloc(fontsel_info->font_styles,
2857 sizeof(FontStyle) * fontsel_info->nstyles);
2858 fontsel_info->pixel_sizes = g_realloc(fontsel_info->pixel_sizes,
2859 sizeof(guint16) * npixel_sizes);
2860 fontsel_info->point_sizes = g_realloc(fontsel_info->point_sizes,
2861 sizeof(guint16) * npoint_sizes);
2863 XFreeFontNames (xfontnames);
2866 /* Debugging Output */
2867 /* This outputs all FontInfos. */
2868 #ifdef FONTSEL_DEBUG
2869 g_message("\n\n Font Family Weight Slant Set Width Spacing Charset\n\n");
2870 for (i = 0; i < fontsel_info->nfonts; i++)
2872 FontInfo *font = &fontsel_info->font_info[i];
2873 FontStyle *styles = fontsel_info->font_styles + font->style_index;
2874 for (style = 0; style < font->nstyles; style++)
2876 g_message("%5i %-16.16s ", i, font->family);
2877 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2878 g_message("%-9.9s ",
2879 fontsel_info->properties[prop][styles->properties[prop]]);
2882 if (styles->flags & GTK_FONT_BITMAP)
2883 g_message("Bitmapped font ");
2884 if (styles->flags & GTK_FONT_SCALABLE)
2885 g_message("Scalable font ");
2886 if (styles->flags & GTK_FONT_SCALABLE_BITMAP)
2887 g_message("Scalable-Bitmapped font ");
2890 if (styles->npixel_sizes)
2892 g_message(" Pixel sizes: ");
2893 tmp_sizes = fontsel_info->pixel_sizes + styles->pixel_sizes_index;
2894 for (size = 0; size < styles->npixel_sizes; size++)
2895 g_message("%i ", *tmp_sizes++);
2899 if (styles->npoint_sizes)
2901 g_message(" Point sizes: ");
2902 tmp_sizes = fontsel_info->point_sizes + styles->point_sizes_index;
2903 for (size = 0; size < styles->npoint_sizes; size++)
2904 g_message("%i ", *tmp_sizes++);
2912 /* This outputs all available properties. */
2913 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2915 g_message("Property: %s\n", xlfd_field_names[xlfd_index[prop]]);
2916 for (i = 0; i < fontsel_info->nproperties[prop]; i++)
2917 g_message(" %s\n", fontsel_info->properties[prop][i]);
2922 /* This inserts the given fontname into the FontInfo table.
2923 If a FontInfo already exists with the same family and foundry, then the
2924 fontname is added to the FontInfos list of fontnames, else a new FontInfo
2925 is created and inserted in alphabetical order in the table. */
2927 gtk_font_selection_insert_font (GSList *fontnames[],
2933 GSList *temp_fontname;
2935 gboolean family_exists = FALSE;
2939 gchar family_buffer[XLFD_MAX_FIELD_LEN];
2941 table = fontsel_info->font_info;
2943 /* insert a fontname into a table */
2944 family = gtk_font_selection_get_xlfd_field (fontname, XLFD_FAMILY,
2949 foundry = gtk_font_selection_insert_field (fontname, FOUNDRY);
2954 /* Do a binary search to determine if we have already encountered
2955 * a font with this family & foundry. */
2957 while (lower < upper)
2959 middle = (lower + upper) >> 1;
2961 cmp = strcmp (family, table[middle].family);
2962 /* If the family matches we sort by the foundry. */
2965 family_exists = TRUE;
2966 family = table[middle].family;
2967 cmp = strcmp(fontsel_info->properties[FOUNDRY][foundry],
2968 fontsel_info->properties[FOUNDRY][table[middle].foundry]);
2973 fontnames[middle] = g_slist_prepend (fontnames[middle],
2984 /* Add another entry to the table for this new font family */
2985 temp_info.family = family_exists ? family : g_strdup(family);
2986 temp_info.foundry = foundry;
2987 temp_fontname = g_slist_prepend (NULL, fontname);
2991 /* Quickly insert the entry into the table in sorted order
2992 * using a modification of insertion sort and the knowledge
2993 * that the entries proper position in the table was determined
2994 * above in the binary search and is contained in the "lower"
2998 upper = *ntable - 1;
2999 while (lower != upper)
3001 table[upper] = table[upper-1];
3002 fontnames[upper] = fontnames[upper-1];
3006 table[lower] = temp_info;
3007 fontnames[lower] = temp_fontname;
3011 /* This checks that the specified field of the given fontname is in the
3012 appropriate properties array. If not it is added. Thus eventually we get
3013 arrays of all possible weights/slants etc. It returns the array index. */
3015 gtk_font_selection_insert_field (gchar *fontname,
3018 gchar field_buffer[XLFD_MAX_FIELD_LEN];
3022 field = gtk_font_selection_get_xlfd_field (fontname, xlfd_index[prop],
3027 /* If the field is already in the array just return its index. */
3028 for (index = 0; index < fontsel_info->nproperties[prop]; index++)
3029 if (!strcmp(field, fontsel_info->properties[prop][index]))
3032 /* Make sure we have enough space to add the field. */
3033 if (fontsel_info->nproperties[prop] == fontsel_info->space_allocated[prop])
3035 fontsel_info->space_allocated[prop] += PROPERTY_ARRAY_INCREMENT;
3036 fontsel_info->properties[prop] = g_realloc(fontsel_info->properties[prop],
3038 * fontsel_info->space_allocated[prop]);
3041 /* Add the new field. */
3042 index = fontsel_info->nproperties[prop];
3043 fontsel_info->properties[prop][index] = g_strdup(field);
3044 fontsel_info->nproperties[prop]++;
3049 /*****************************************************************************
3050 * These functions are the main public interface for getting/setting the font.
3051 *****************************************************************************/
3054 gtk_font_selection_get_font (GtkFontSelection *fontsel)
3056 g_return_val_if_fail (fontsel != NULL, NULL);
3057 return fontsel->font;
3062 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
3065 gchar *family_str, *foundry_str;
3066 gchar *property_str[GTK_NUM_STYLE_PROPERTIES];
3069 g_return_val_if_fail (fontsel != NULL, NULL);
3070 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
3072 /* If no family has been selected return NULL. */
3073 if (fontsel->font_index == -1)
3076 font = &fontsel_info->font_info[fontsel->font_index];
3077 family_str = font->family;
3078 foundry_str = fontsel_info->properties[FOUNDRY][font->foundry];
3080 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
3083 = fontsel_info->properties[prop][fontsel->property_values[prop]];
3084 if (strcmp (property_str[prop], "(nil)") == 0)
3085 property_str[prop] = "";
3088 return gtk_font_selection_create_xlfd (fontsel->size,
3092 property_str[WEIGHT],
3093 property_str[SLANT],
3094 property_str[SET_WIDTH],
3095 property_str[SPACING],
3096 property_str[CHARSET]);
3100 /* This sets the current font, selecting the appropriate clist rows.
3101 First we check the fontname is valid and try to find the font family
3102 - i.e. the name in the main list. If we can't find that, then just return.
3103 Next we try to set each of the properties according to the fontname.
3104 Finally we select the font family & style in the clists. */
3106 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
3107 const gchar *fontname)
3109 gchar *family, *field;
3110 gint index, prop, size;
3111 guint16 foundry, value;
3112 gchar family_buffer[XLFD_MAX_FIELD_LEN];
3113 gchar field_buffer[XLFD_MAX_FIELD_LEN];
3116 g_return_val_if_fail (fontsel != NULL, FALSE);
3117 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
3118 g_return_val_if_fail (fontname != NULL, FALSE);
3120 /* Check it is a valid fontname. */
3121 if (!gtk_font_selection_is_xlfd_font_name(fontname))
3124 family = gtk_font_selection_get_xlfd_field (fontname, XLFD_FAMILY,
3129 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_FOUNDRY,
3131 foundry = gtk_font_selection_field_to_index (fontsel_info->properties[FOUNDRY],
3132 fontsel_info->nproperties[FOUNDRY],
3135 index = gtk_font_selection_find_font(fontsel, family, foundry);
3139 /* Convert the property fields into indices and set them. */
3140 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
3142 field = gtk_font_selection_get_xlfd_field (fontname, xlfd_index[prop],
3144 value = gtk_font_selection_field_to_index (fontsel_info->properties[prop],
3145 fontsel_info->nproperties[prop],
3147 fontsel->property_values[prop] = value;
3150 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_POINTS,
3157 fontsel->size = fontsel->selected_size = size;
3158 fontsel->metric = GTK_FONT_METRIC_POINTS;
3159 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->points_button),
3162 sprintf (buffer, "%i", size / 10);
3164 sprintf (buffer, "%i.%i", size / 10, size % 10);
3168 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_PIXELS,
3173 fontsel->size = fontsel->selected_size = size;
3174 fontsel->metric = GTK_FONT_METRIC_PIXELS;
3175 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->pixels_button),
3177 sprintf (buffer, "%i", size);
3179 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
3181 /* Clear any current filter. */
3182 gtk_font_selection_clear_filter(fontsel);
3184 /* Now find the best style match. */
3185 fontsel->font_index = index;
3186 gtk_clist_select_row(GTK_CLIST(fontsel->font_clist), index, 0);
3187 if (GTK_WIDGET_MAPPED (fontsel->font_clist))
3188 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), index, -1, 0.5, 0);
3190 gtk_font_selection_show_available_styles (fontsel);
3191 /* This will load the font. */
3192 gtk_font_selection_select_best_style (fontsel, FALSE);
3198 /* Returns the index of the given family, or -1 if not found */
3200 gtk_font_selection_find_font (GtkFontSelection *fontsel,
3204 FontInfo *font_info;
3205 gint lower, upper, middle = -1, cmp, nfonts;
3206 gint found_family = -1;
3208 font_info = fontsel_info->font_info;
3209 nfonts = fontsel_info->nfonts;
3213 /* Do a binary search to find the font family. */
3216 while (lower < upper)
3218 middle = (lower + upper) >> 1;
3220 cmp = strcmp (family, font_info[middle].family);
3223 found_family = middle;
3224 cmp = strcmp(fontsel_info->properties[FOUNDRY][foundry],
3225 fontsel_info->properties[FOUNDRY][font_info[middle].foundry]);
3236 /* We couldn't find the family and foundry, but we may have just found the
3237 family, so we return that. */
3238 return found_family;
3242 /* This returns the text in the preview entry. You should copy the returned
3243 text if you need it. */
3245 gtk_font_selection_get_preview_text (GtkFontSelection *fontsel)
3247 return gtk_entry_get_text(GTK_ENTRY(fontsel->preview_entry));
3251 /* This sets the text in the preview entry. */
3253 gtk_font_selection_set_preview_text (GtkFontSelection *fontsel,
3256 gtk_entry_set_text(GTK_ENTRY(fontsel->preview_entry), text);
3260 /*****************************************************************************
3261 * These functions all deal with X Logical Font Description (XLFD) fontnames.
3262 * See the freely available documentation about this.
3263 *****************************************************************************/
3266 * Returns TRUE if the fontname is a valid XLFD.
3267 * (It just checks if the number of dashes is 14, and that each
3268 * field < XLFD_MAX_FIELD_LEN characters long - that's not in the XLFD but it
3269 * makes it easier for me).
3272 gtk_font_selection_is_xlfd_font_name (const gchar *fontname)
3279 if (*fontname++ == '-')
3281 if (field_len > XLFD_MAX_FIELD_LEN) return FALSE;
3289 return (i == 14) ? TRUE : FALSE;
3293 * This fills the buffer with the specified field from the X Logical Font
3294 * Description name, and returns it. If fontname is NULL or the field is
3295 * longer than XFLD_MAX_FIELD_LEN it returns NULL.
3296 * Note: For the charset field, we also return the encoding, e.g. 'iso8859-1'.
3299 gtk_font_selection_get_xlfd_field (const gchar *fontname,
3300 FontField field_num,
3303 const gchar *t1, *t2;
3304 gint countdown, len, num_dashes;
3309 /* we assume this is a valid fontname...that is, it has 14 fields */
3311 countdown = field_num;
3313 while (*t1 && (countdown >= 0))
3317 num_dashes = (field_num == XLFD_CHARSET) ? 2 : 1;
3318 for (t2 = t1; *t2; t2++)
3320 if (*t2 == '-' && --num_dashes == 0)
3326 /* Check we don't overflow the buffer */
3327 len = (long) t2 - (long) t1;
3328 if (len > XLFD_MAX_FIELD_LEN - 1)
3330 strncpy (buffer, t1, len);
3333 /* Convert to lower case. */
3337 strcpy(buffer, "(nil)");
3343 * This returns a X Logical Font Description font name, given all the pieces.
3344 * Note: this retval must be freed by the caller.
3347 gtk_font_selection_create_xlfd (gint size,
3348 GtkFontMetricType metric,
3358 gchar *pixel_size = "*", *point_size = "*", *fontname;
3364 sprintf (buffer, "%d", (int) size);
3365 if (metric == GTK_FONT_METRIC_PIXELS)
3366 pixel_size = buffer;
3368 point_size = buffer;
3370 /* Note: be careful here - don't overrun the allocated memory. */
3371 length = strlen(foundry) + strlen(family) + strlen(weight) + strlen(slant)
3372 + strlen(set_width) + strlen(pixel_size) + strlen(point_size)
3373 + strlen(spacing) + strlen(charset)
3374 + 1 + 1 + 1 + 1 + 1 + 3 + 1 + 5 + 3
3375 + 1 /* for the terminating '\0'. */;
3377 fontname = g_new(gchar, length);
3378 /* **NOTE**: If you change this string please change length above! */
3379 sprintf(fontname, "-%s-%s-%s-%s-%s-*-%s-%s-*-*-%s-*-%s",
3380 foundry, family, weight, slant, set_width, pixel_size,
3381 point_size, spacing, charset);
3387 /*****************************************************************************
3388 * GtkFontSelectionDialog
3389 *****************************************************************************/
3392 gtk_font_selection_dialog_get_type (void)
3394 static guint font_selection_dialog_type = 0;
3396 if (!font_selection_dialog_type)
3398 GtkTypeInfo fontsel_diag_info =
3400 "GtkFontSelectionDialog",
3401 sizeof (GtkFontSelectionDialog),
3402 sizeof (GtkFontSelectionDialogClass),
3403 (GtkClassInitFunc) gtk_font_selection_dialog_class_init,
3404 (GtkObjectInitFunc) gtk_font_selection_dialog_init,
3405 /* reserved_1 */ NULL,
3406 /* reserved_2 */ NULL,
3407 (GtkClassInitFunc) NULL,
3410 font_selection_dialog_type = gtk_type_unique (GTK_TYPE_WINDOW, &fontsel_diag_info);
3413 return font_selection_dialog_type;
3417 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
3419 GtkObjectClass *object_class;
3421 object_class = (GtkObjectClass*) klass;
3423 font_selection_dialog_parent_class = gtk_type_class (GTK_TYPE_WINDOW);
3427 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
3429 fontseldiag->dialog_width = -1;
3430 fontseldiag->auto_resize = TRUE;
3432 gtk_widget_set_events(GTK_WIDGET(fontseldiag), GDK_STRUCTURE_MASK);
3433 gtk_signal_connect (GTK_OBJECT (fontseldiag), "configure_event",
3434 (GtkSignalFunc) gtk_font_selection_dialog_on_configure,
3437 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag), 4);
3438 gtk_window_set_policy(GTK_WINDOW(fontseldiag), FALSE, TRUE, TRUE);
3440 fontseldiag->main_vbox = gtk_vbox_new (FALSE, 4);
3441 gtk_widget_show (fontseldiag->main_vbox);
3442 gtk_container_add (GTK_CONTAINER (fontseldiag), fontseldiag->main_vbox);
3444 fontseldiag->fontsel = gtk_font_selection_new();
3445 gtk_widget_show (fontseldiag->fontsel);
3446 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
3447 fontseldiag->fontsel, TRUE, TRUE, 0);
3449 /* Create the action area */
3450 fontseldiag->action_area = gtk_hbutton_box_new ();
3451 gtk_button_box_set_layout(GTK_BUTTON_BOX(fontseldiag->action_area),
3453 gtk_button_box_set_spacing(GTK_BUTTON_BOX(fontseldiag->action_area), 5);
3454 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
3455 fontseldiag->action_area, FALSE, FALSE, 0);
3456 gtk_widget_show (fontseldiag->action_area);
3458 fontseldiag->ok_button = gtk_button_new_with_label(_("OK"));
3459 GTK_WIDGET_SET_FLAGS (fontseldiag->ok_button, GTK_CAN_DEFAULT);
3460 gtk_widget_show(fontseldiag->ok_button);
3461 gtk_box_pack_start (GTK_BOX (fontseldiag->action_area),
3462 fontseldiag->ok_button, TRUE, TRUE, 0);
3463 gtk_widget_grab_default (fontseldiag->ok_button);
3465 fontseldiag->apply_button = gtk_button_new_with_label(_("Apply"));
3466 GTK_WIDGET_SET_FLAGS (fontseldiag->apply_button, GTK_CAN_DEFAULT);
3467 /*gtk_widget_show(fontseldiag->apply_button);*/
3468 gtk_box_pack_start (GTK_BOX(fontseldiag->action_area),
3469 fontseldiag->apply_button, TRUE, TRUE, 0);
3471 fontseldiag->cancel_button = gtk_button_new_with_label(_("Cancel"));
3472 GTK_WIDGET_SET_FLAGS (fontseldiag->cancel_button, GTK_CAN_DEFAULT);
3473 gtk_widget_show(fontseldiag->cancel_button);
3474 gtk_box_pack_start (GTK_BOX(fontseldiag->action_area),
3475 fontseldiag->cancel_button, TRUE, TRUE, 0);
3481 gtk_font_selection_dialog_new (const gchar *title)
3483 GtkFontSelectionDialog *fontseldiag;
3485 fontseldiag = gtk_type_new (GTK_TYPE_FONT_SELECTION_DIALOG);
3486 gtk_window_set_title (GTK_WINDOW (fontseldiag),
3487 title ? title : _("Font Selection"));
3489 return GTK_WIDGET (fontseldiag);
3493 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
3495 return gtk_font_selection_get_font_name(GTK_FONT_SELECTION(fsd->fontsel));
3499 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
3501 return gtk_font_selection_get_font(GTK_FONT_SELECTION(fsd->fontsel));
3505 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
3506 const gchar *fontname)
3508 return gtk_font_selection_set_font_name(GTK_FONT_SELECTION(fsd->fontsel),
3513 gtk_font_selection_dialog_set_filter (GtkFontSelectionDialog *fsd,
3514 GtkFontFilterType filter_type,
3515 GtkFontType font_type,
3523 gtk_font_selection_set_filter (GTK_FONT_SELECTION (fsd->fontsel),
3524 filter_type, font_type,
3525 foundries, weights, slants, setwidths,
3526 spacings, charsets);
3530 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
3532 return gtk_font_selection_get_preview_text(GTK_FONT_SELECTION(fsd->fontsel));
3536 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
3539 gtk_font_selection_set_preview_text(GTK_FONT_SELECTION(fsd->fontsel), text);
3543 /* This turns auto-shrink off if the user resizes the width of the dialog.
3544 It also turns it back on again if the user resizes it back to its normal
3547 gtk_font_selection_dialog_on_configure (GtkWidget *widget,
3548 GdkEventConfigure *event,
3549 GtkFontSelectionDialog *fsd)
3551 /* This sets the initial width. */
3552 if (fsd->dialog_width == -1)
3553 fsd->dialog_width = event->width;
3554 else if (fsd->auto_resize && fsd->dialog_width != event->width)
3556 fsd->auto_resize = FALSE;
3557 gtk_window_set_policy(GTK_WINDOW(fsd), FALSE, TRUE, FALSE);
3559 else if (!fsd->auto_resize && fsd->dialog_width == event->width)
3561 fsd->auto_resize = TRUE;
3562 gtk_window_set_policy(GTK_WINDOW(fsd), FALSE, TRUE, TRUE);