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.
25 * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
26 * file for a list of people on the GTK+ Team. See the ChangeLog
27 * files for a list of changes. These files are distributed with
28 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
34 * Fontnames - A maximum of MAX_FONTS (32767) fontnames will be retrieved
35 * from X Windows with XListFonts(). Any more are ignored.
36 * I think this limit may have been set because of a limit in
37 * GtkList. It could possibly be increased since we are using
38 * GtkClists now, but I'd be surprised if it was reached.
39 * Field length - XLFD_MAX_FIELD_LEN is the maximum length that any field of a
40 * fontname can be for it to be considered valid. Others are
42 * Properties - Maximum of 65535 choices for each font property - guint16's
43 * are used as indices, e.g. in the FontInfo struct.
44 * Combinations - Maximum of 65535 combinations of properties for each font
45 * family - a guint16 is used in the FontInfo struct.
46 * Font size - Minimum font size of 2 pixels/points, since trying to load
47 * some fonts with a size of 1 can cause X to hang.
48 * (e.g. the Misc Fixed fonts).
52 * Possible Improvements:
54 * Font Styles - could sort the styles into a reasonable order - regular
55 * first, then bold, bold italic etc.
57 * I18N - the default preview text is not useful for international
58 * fonts. Maybe the first few characters of the font could be
60 * - fontsets? should these be handled by the font dialog?
64 * Debugging: compile with -DFONTSEL_DEBUG for lots of debugging output.
75 #include "gdk/gdkkeysyms.h"
77 #include "gtkbutton.h"
78 #include "gtkcheckbutton.h"
81 #include "gtkfontsel.h"
86 #include "gtknotebook.h"
87 #include "gtkradiobutton.h"
88 #include "gtksignal.h"
91 #include "gtkscrolledwindow.h"
94 /* The maximum number of fontnames requested with XListFonts(). */
95 #define MAX_FONTS 32767
97 /* This is the largest field length we will accept. If a fontname has a field
98 larger than this we will skip it. */
99 #define XLFD_MAX_FIELD_LEN 64
101 /* These are what we use as the standard font sizes, for the size clist.
102 Note that when using points we still show these integer point values but
103 we work internally in decipoints (and decipoint values can be typed in). */
104 static const guint16 font_sizes[] = {
105 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28,
106 32, 36, 40, 48, 56, 64, 72
109 /* Initial font metric & size (Remember point sizes are in decipoints).
110 The font size should match one of those in the font_sizes array. */
111 #define INITIAL_METRIC GTK_FONT_METRIC_POINTS
112 #define INITIAL_FONT_SIZE 140
114 /* This is the default text shown in the preview entry, though the user
115 can set it. Remember that some fonts only have capital letters. */
116 #define PREVIEW_TEXT "abcdefghijk ABCDEFGHIJK"
118 /* This is the initial and maximum height of the preview entry (it expands
119 when large font sizes are selected). Initial height is also the minimum. */
120 #define INITIAL_PREVIEW_HEIGHT 44
121 #define MAX_PREVIEW_HEIGHT 300
123 /* These are the sizes of the font, style & size clists. */
124 #define FONT_LIST_HEIGHT 136
125 #define FONT_LIST_WIDTH 190
126 #define FONT_STYLE_LIST_WIDTH 170
127 #define FONT_SIZE_LIST_WIDTH 60
129 /* This is the number of fields in an X Logical Font Description font name.
130 Note that we count the registry & encoding as 1. */
131 #define GTK_XLFD_NUM_FIELDS 13
133 typedef struct _GtkFontSelInfo GtkFontSelInfo;
134 typedef struct _FontInfo FontInfo;
135 typedef struct _FontStyle FontStyle;
137 /* This struct represents one family of fonts (with one foundry), e.g. adobe
138 courier or sony fixed. It stores the family name, the index of the foundry
139 name, and the index of and number of available styles. */
148 /* This represents one style, as displayed in the Font Style clist. It can
149 have a number of available pixel sizes and point sizes. The indexes point
150 into the two big fontsel_info->pixel_sizes & fontsel_info->point_sizes
151 arrays. The displayed flag is used when displaying styles to remember which
152 styles have already been displayed. Note that it is combined with the
153 GtkFontType in the flags field. */
154 #define GTK_FONT_DISPLAYED (1 << 7)
157 guint16 properties[GTK_NUM_STYLE_PROPERTIES];
158 gint pixel_sizes_index;
159 guint16 npixel_sizes;
160 gint point_sizes_index;
161 guint16 npoint_sizes;
165 struct _GtkFontSelInfo {
167 /* This is a table with each FontInfo representing one font family+foundry */
171 /* This stores all the valid combinations of properties for every family.
172 Each FontInfo holds an index into its own space in this one big array. */
173 FontStyle *font_styles;
176 /* This stores all the font sizes available for every style.
177 Each style holds an index into these arrays. */
178 guint16 *pixel_sizes;
179 guint16 *point_sizes;
181 /* These are the arrays of strings of all possible weights, slants,
182 set widths, spacings, charsets & foundries, and the amount of space
183 allocated for each array. */
184 gchar **properties[GTK_NUM_FONT_PROPERTIES];
185 guint16 nproperties[GTK_NUM_FONT_PROPERTIES];
186 guint16 space_allocated[GTK_NUM_FONT_PROPERTIES];
189 /* These are the field numbers in the X Logical Font Description fontnames,
190 e.g. -adobe-courier-bold-o-normal--25-180-100-100-m-150-iso8859-1 */
201 XLFD_RESOLUTION_X = 8,
202 XLFD_RESOLUTION_Y = 9,
204 XLFD_AVERAGE_WIDTH = 11,
208 /* These are the names of the fields, used on the info & filter page. */
209 static const gchar* xlfd_field_names[GTK_XLFD_NUM_FIELDS] = {
221 N_("Average Width:"),
225 /* These are the array indices of the font properties used in several arrays,
226 and should match the xlfd_index array below. */
237 /* This is used to look up a field in a fontname given one of the above
239 static const FontField xlfd_index[GTK_NUM_FONT_PROPERTIES] = {
248 /* These are the positions of the properties in the filter table - x, y. */
249 static const gint filter_positions[GTK_NUM_FONT_PROPERTIES][2] = {
250 { 1, 0 }, { 0, 2 }, { 1, 2 }, { 2, 2 }, { 2, 0 }, { 0, 0 }
252 static const gint filter_heights[GTK_NUM_FONT_PROPERTIES] = {
253 100, 70, 70, 40, 100, 100
256 /* This is returned by gtk_font_selection_filter_state to describe if a
257 property value is filtered. e.g. if 'bold' has been selected on the filter
258 page, then that will return 'FILTERED' and 'black' will be 'NOT_FILTERED'.
259 If none of the weight values are selected, they all return 'NOT_SET'. */
265 } GtkFontPropertyFilterState;
267 static GtkFontSelInfo *fontsel_info = NULL;
269 /* The initial size and increment of each of the arrays of property values. */
270 #define PROPERTY_ARRAY_INCREMENT 16
272 static void gtk_font_selection_class_init (GtkFontSelectionClass *klass);
273 static void gtk_font_selection_init (GtkFontSelection *fontsel);
274 static void gtk_font_selection_destroy (GtkObject *object);
276 /* These are all used for class initialization - loading in the fonts etc. */
277 static void gtk_font_selection_get_fonts (void);
278 static void gtk_font_selection_insert_font (GSList *fontnames[],
281 static gint gtk_font_selection_insert_field (gchar *fontname,
284 /* These are the callbacks & related functions. */
285 static void gtk_font_selection_select_font (GtkWidget *w,
288 GdkEventButton *bevent,
290 static gint gtk_font_selection_on_clist_key_press (GtkWidget *clist,
292 GtkFontSelection *fs);
293 static gboolean gtk_font_selection_select_next (GtkFontSelection *fs,
296 static void gtk_font_selection_show_available_styles
297 (GtkFontSelection *fs);
298 static void gtk_font_selection_select_best_style (GtkFontSelection *fs,
301 static void gtk_font_selection_select_style (GtkWidget *w,
304 GdkEventButton *bevent,
306 static void gtk_font_selection_show_available_sizes
307 (GtkFontSelection *fs);
308 static gint gtk_font_selection_size_key_press (GtkWidget *w,
311 static void gtk_font_selection_select_best_size (GtkFontSelection *fs);
312 static void gtk_font_selection_select_size (GtkWidget *w,
315 GdkEventButton *bevent,
318 static void gtk_font_selection_metric_callback (GtkWidget *w,
320 static void gtk_font_selection_expose_list (GtkWidget *w,
321 GdkEventExpose *event,
323 static void gtk_font_selection_realize_list (GtkWidget *widget,
326 static void gtk_font_selection_switch_page (GtkWidget *w,
327 GtkNotebookPage *page,
330 static void gtk_font_selection_show_font_info (GtkFontSelection *fs);
332 static void gtk_font_selection_select_filter (GtkWidget *w,
335 GdkEventButton *bevent,
336 GtkFontSelection *fs);
337 static void gtk_font_selection_unselect_filter (GtkWidget *w,
340 GdkEventButton *bevent,
341 GtkFontSelection *fs);
342 static void gtk_font_selection_update_filter (GtkFontSelection *fs);
343 static gboolean gtk_font_selection_style_visible (GtkFontSelection *fs,
346 static void gtk_font_selection_reset_filter (GtkWidget *w,
347 GtkFontSelection *fs);
348 static void gtk_font_selection_on_clear_filter (GtkWidget *w,
349 GtkFontSelection *fs);
350 static void gtk_font_selection_show_available_fonts
351 (GtkFontSelection *fs);
352 static void gtk_font_selection_clear_filter (GtkFontSelection *fs);
353 static void gtk_font_selection_update_filter_lists(GtkFontSelection *fs);
354 static GtkFontPropertyFilterState gtk_font_selection_filter_state
355 (GtkFontSelection *fs,
356 GtkFontFilterType filter_type,
360 /* Misc. utility functions. */
361 static gboolean gtk_font_selection_load_font (GtkFontSelection *fs);
362 static void gtk_font_selection_update_preview (GtkFontSelection *fs);
364 static gint gtk_font_selection_find_font (GtkFontSelection *fs,
367 static guint16 gtk_font_selection_field_to_index (gchar **table,
371 static gchar* gtk_font_selection_expand_slant_code (gchar *slant);
372 static gchar* gtk_font_selection_expand_spacing_code(gchar *spacing);
374 /* Functions for handling X Logical Font Description fontnames. */
375 static gboolean gtk_font_selection_is_xlfd_font_name (const gchar *fontname);
376 static char* gtk_font_selection_get_xlfd_field (const gchar *fontname,
379 static gchar * gtk_font_selection_create_xlfd (gint size,
380 GtkFontMetricType metric,
390 /* FontSelectionDialog */
391 static void gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass);
392 static void gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag);
394 static gint gtk_font_selection_dialog_on_configure(GtkWidget *widget,
395 GdkEventConfigure *event,
396 GtkFontSelectionDialog *fsd);
398 static GtkWindowClass *font_selection_parent_class = NULL;
399 static GtkNotebookClass *font_selection_dialog_parent_class = NULL;
402 gtk_font_selection_get_type()
404 static GtkType font_selection_type = 0;
406 if(!font_selection_type)
408 static const GtkTypeInfo fontsel_type_info =
411 sizeof (GtkFontSelection),
412 sizeof (GtkFontSelectionClass),
413 (GtkClassInitFunc) gtk_font_selection_class_init,
414 (GtkObjectInitFunc) gtk_font_selection_init,
415 /* reserved_1 */ NULL,
416 /* reserved_2 */ NULL,
417 (GtkClassInitFunc) NULL,
420 font_selection_type = gtk_type_unique (GTK_TYPE_NOTEBOOK,
424 return font_selection_type;
428 gtk_font_selection_class_init(GtkFontSelectionClass *klass)
430 GtkObjectClass *object_class;
432 object_class = (GtkObjectClass *) klass;
434 font_selection_parent_class = gtk_type_class (GTK_TYPE_NOTEBOOK);
436 object_class->destroy = gtk_font_selection_destroy;
438 gtk_font_selection_get_fonts ();
442 gtk_font_selection_init(GtkFontSelection *fontsel)
444 GtkWidget *scrolled_win;
445 GtkWidget *text_frame;
446 GtkWidget *text_box, *frame;
447 GtkWidget *table, *label, *hbox, *hbox2, *clist, *button, *vbox, *alignment;
449 gchar *titles[] = { NULL, NULL, NULL };
454 gchar *property, *text;
457 /* Number of internationalized titles here must match number
458 of NULL initializers above */
459 titles[0] = _("Font Property");
460 titles[1] = _("Requested Value");
461 titles[2] = _("Actual Value");
463 /* Initialize the GtkFontSelection struct. We do this here in case any
464 callbacks are triggered while creating the interface. */
465 fontsel->font = NULL;
466 fontsel->font_index = -1;
468 fontsel->metric = INITIAL_METRIC;
469 fontsel->size = INITIAL_FONT_SIZE;
470 fontsel->selected_size = INITIAL_FONT_SIZE;
472 fontsel->filters[GTK_FONT_FILTER_BASE].font_type = GTK_FONT_ALL;
473 fontsel->filters[GTK_FONT_FILTER_USER].font_type = GTK_FONT_BITMAP
477 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
479 fontsel->filters[GTK_FONT_FILTER_BASE].property_filters[prop] = NULL;
480 fontsel->filters[GTK_FONT_FILTER_BASE].property_nfilters[prop] = 0;
481 fontsel->filters[GTK_FONT_FILTER_USER].property_filters[prop] = NULL;
482 fontsel->filters[GTK_FONT_FILTER_USER].property_nfilters[prop] = 0;
485 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
486 fontsel->property_values[prop] = 0;
488 /* Create the main notebook page. */
489 gtk_notebook_set_homogeneous_tabs (GTK_NOTEBOOK (fontsel), TRUE);
490 gtk_notebook_set_tab_hborder (GTK_NOTEBOOK (fontsel), 8);
491 fontsel->main_vbox = gtk_vbox_new (FALSE, 4);
492 gtk_widget_show (fontsel->main_vbox);
493 gtk_container_set_border_width (GTK_CONTAINER (fontsel->main_vbox), 6);
494 label = gtk_label_new(_("Font"));
495 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
496 fontsel->main_vbox, label);
498 /* Create the table of font, style & size. */
499 table = gtk_table_new (3, 3, FALSE);
500 gtk_widget_show (table);
501 gtk_table_set_col_spacings(GTK_TABLE(table), 8);
502 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), table, TRUE, TRUE, 0);
504 fontsel->font_label = gtk_label_new(_("Font:"));
505 gtk_misc_set_alignment (GTK_MISC (fontsel->font_label), 0.0, 0.5);
506 gtk_widget_show (fontsel->font_label);
507 gtk_table_attach (GTK_TABLE (table), fontsel->font_label, 0, 1, 0, 1,
509 label = gtk_label_new(_("Font Style:"));
510 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
511 gtk_widget_show (label);
512 gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1,
514 label = gtk_label_new(_("Size:"));
515 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
516 gtk_widget_show (label);
517 gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
520 fontsel->font_entry = gtk_entry_new();
521 gtk_entry_set_editable(GTK_ENTRY(fontsel->font_entry), FALSE);
522 gtk_widget_set_usize (fontsel->font_entry, 20, -1);
523 gtk_widget_show (fontsel->font_entry);
524 gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
526 fontsel->font_style_entry = gtk_entry_new();
527 gtk_entry_set_editable(GTK_ENTRY(fontsel->font_style_entry), FALSE);
528 gtk_widget_set_usize (fontsel->font_style_entry, 20, -1);
529 gtk_widget_show (fontsel->font_style_entry);
530 gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
532 fontsel->size_entry = gtk_entry_new();
533 gtk_widget_set_usize (fontsel->size_entry, 20, -1);
534 gtk_widget_show (fontsel->size_entry);
535 gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
537 gtk_signal_connect (GTK_OBJECT (fontsel->size_entry), "key_press_event",
538 (GtkSignalFunc) gtk_font_selection_size_key_press,
541 /* Create the clists */
542 fontsel->font_clist = gtk_clist_new(1);
543 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->font_clist));
544 gtk_clist_set_column_auto_resize (GTK_CLIST (fontsel->font_clist), 0, TRUE);
545 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
546 gtk_widget_set_usize (scrolled_win, FONT_LIST_WIDTH, FONT_LIST_HEIGHT);
547 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->font_clist);
548 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
549 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
550 gtk_widget_show(fontsel->font_clist);
551 gtk_widget_show(scrolled_win);
553 gtk_table_attach (GTK_TABLE (table), scrolled_win, 0, 1, 2, 3,
554 GTK_EXPAND | GTK_FILL,
555 GTK_EXPAND | GTK_FILL, 0, 0);
557 fontsel->font_style_clist = gtk_clist_new(1);
558 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->font_style_clist));
559 gtk_clist_set_column_auto_resize (GTK_CLIST (fontsel->font_style_clist),
561 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
562 gtk_widget_set_usize (scrolled_win, FONT_STYLE_LIST_WIDTH, -1);
563 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->font_style_clist);
564 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
565 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
566 gtk_widget_show(fontsel->font_style_clist);
567 gtk_widget_show(scrolled_win);
568 gtk_table_attach (GTK_TABLE (table), scrolled_win, 1, 2, 2, 3,
569 GTK_EXPAND | GTK_FILL,
570 GTK_EXPAND | GTK_FILL, 0, 0);
572 fontsel->size_clist = gtk_clist_new(1);
573 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->size_clist));
574 gtk_clist_set_column_width (GTK_CLIST(fontsel->size_clist), 0, 20);
575 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
576 gtk_widget_set_usize (scrolled_win, FONT_SIZE_LIST_WIDTH, -1);
577 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->size_clist);
578 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
579 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
580 gtk_widget_show(fontsel->size_clist);
581 gtk_widget_show(scrolled_win);
582 gtk_table_attach (GTK_TABLE (table), scrolled_win, 2, 3, 2, 3,
583 GTK_FILL, GTK_FILL, 0, 0);
586 /* Insert the fonts. If there exist fonts with the same family but
587 different foundries, then the foundry name is appended in brackets. */
588 gtk_font_selection_show_available_fonts(fontsel);
590 gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "select_row",
591 GTK_SIGNAL_FUNC(gtk_font_selection_select_font),
593 GTK_WIDGET_SET_FLAGS (fontsel->font_clist, GTK_CAN_FOCUS);
594 gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "key_press_event",
595 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
597 gtk_signal_connect_after (GTK_OBJECT (fontsel->font_clist), "expose_event",
598 GTK_SIGNAL_FUNC(gtk_font_selection_expose_list),
601 gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist), "select_row",
602 GTK_SIGNAL_FUNC(gtk_font_selection_select_style),
604 GTK_WIDGET_SET_FLAGS (fontsel->font_style_clist, GTK_CAN_FOCUS);
605 gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist),
607 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
609 gtk_signal_connect_after (GTK_OBJECT (fontsel->font_style_clist),
611 GTK_SIGNAL_FUNC(gtk_font_selection_realize_list),
614 /* Insert the standard font sizes */
615 gtk_clist_freeze (GTK_CLIST(fontsel->size_clist));
616 size_to_match = INITIAL_FONT_SIZE;
617 if (INITIAL_METRIC == GTK_FONT_METRIC_POINTS)
618 size_to_match = size_to_match / 10;
619 for (i = 0; i < sizeof(font_sizes) / sizeof(font_sizes[0]); i++)
621 sprintf(buffer, "%i", font_sizes[i]);
623 gtk_clist_append(GTK_CLIST(fontsel->size_clist), &size);
624 if (font_sizes[i] == size_to_match)
626 gtk_clist_select_row(GTK_CLIST(fontsel->size_clist), i, 0);
627 gtk_entry_set_text(GTK_ENTRY(fontsel->size_entry), buffer);
630 gtk_clist_thaw (GTK_CLIST(fontsel->size_clist));
632 gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "select_row",
633 GTK_SIGNAL_FUNC(gtk_font_selection_select_size),
635 GTK_WIDGET_SET_FLAGS (fontsel->size_clist, GTK_CAN_FOCUS);
636 gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "key_press_event",
637 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
641 /* create the Reset Filter & Metric buttons */
642 hbox = gtk_hbox_new(FALSE, 8);
643 gtk_widget_show (hbox);
644 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), hbox, FALSE, TRUE, 0);
646 fontsel->filter_button = gtk_button_new_with_label(_("Reset Filter"));
647 gtk_misc_set_padding (GTK_MISC (GTK_BIN (fontsel->filter_button)->child),
649 gtk_widget_show(fontsel->filter_button);
650 gtk_box_pack_start (GTK_BOX (hbox), fontsel->filter_button, FALSE, FALSE, 0);
651 gtk_widget_set_sensitive (fontsel->filter_button, FALSE);
652 gtk_signal_connect (GTK_OBJECT (fontsel->filter_button), "clicked",
653 GTK_SIGNAL_FUNC(gtk_font_selection_on_clear_filter),
656 hbox2 = gtk_hbox_new(FALSE, 0);
657 gtk_widget_show (hbox2);
658 gtk_box_pack_end (GTK_BOX (hbox), hbox2, FALSE, FALSE, 0);
660 label = gtk_label_new(_("Metric:"));
661 gtk_widget_show (label);
662 gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 8);
664 fontsel->points_button = gtk_radio_button_new_with_label(NULL, _("Points"));
665 gtk_widget_show (fontsel->points_button);
666 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->points_button, FALSE, TRUE, 0);
667 if (INITIAL_METRIC == GTK_FONT_METRIC_POINTS)
668 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fontsel->points_button),
671 fontsel->pixels_button = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(fontsel->points_button), _("Pixels"));
672 gtk_widget_show (fontsel->pixels_button);
673 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->pixels_button, FALSE, TRUE, 0);
674 if (INITIAL_METRIC == GTK_FONT_METRIC_PIXELS)
675 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fontsel->pixels_button),
678 gtk_signal_connect(GTK_OBJECT(fontsel->points_button), "toggled",
679 (GtkSignalFunc) gtk_font_selection_metric_callback,
681 gtk_signal_connect(GTK_OBJECT(fontsel->pixels_button), "toggled",
682 (GtkSignalFunc) gtk_font_selection_metric_callback,
686 /* create the text entry widget */
687 text_frame = gtk_frame_new (_("Preview:"));
688 gtk_widget_show (text_frame);
689 gtk_frame_set_shadow_type(GTK_FRAME(text_frame), GTK_SHADOW_ETCHED_IN);
690 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), text_frame,
693 /* This is just used to get a 4-pixel space around the preview entry. */
694 text_box = gtk_hbox_new (FALSE, 0);
695 gtk_widget_show (text_box);
696 gtk_container_add (GTK_CONTAINER (text_frame), text_box);
697 gtk_container_set_border_width (GTK_CONTAINER (text_box), 4);
699 fontsel->preview_entry = gtk_entry_new ();
700 gtk_widget_show (fontsel->preview_entry);
701 gtk_widget_set_usize (fontsel->preview_entry, -1, INITIAL_PREVIEW_HEIGHT);
702 gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
705 /* Create the message area */
706 fontsel->message_label = gtk_label_new("");
707 gtk_widget_show (fontsel->message_label);
708 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), fontsel->message_label,
712 /* Create the font info page */
713 fontsel->info_vbox = gtk_vbox_new (FALSE, 4);
714 gtk_widget_show (fontsel->info_vbox);
715 gtk_container_set_border_width (GTK_CONTAINER (fontsel->info_vbox), 2);
716 label = gtk_label_new(_("Font Information"));
717 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
718 fontsel->info_vbox, label);
720 fontsel->info_clist = gtk_clist_new_with_titles (3, titles);
721 gtk_widget_set_usize (fontsel->info_clist, 390, 150);
722 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 0, 130);
723 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 1, 130);
724 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 2, 130);
725 gtk_clist_column_titles_passive(GTK_CLIST(fontsel->info_clist));
726 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
727 gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->info_clist);
728 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
729 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
730 gtk_widget_show(fontsel->info_clist);
731 gtk_widget_show(scrolled_win);
732 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), scrolled_win,
735 /* Insert the property names */
736 gtk_clist_freeze (GTK_CLIST(fontsel->info_clist));
739 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
741 row_text[0] = _(xlfd_field_names[i]);
742 gtk_clist_append(GTK_CLIST(fontsel->info_clist), row_text);
743 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 0, 0, 4);
744 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 1, 0, 4);
745 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 2, 0, 4);
747 gtk_clist_thaw (GTK_CLIST(fontsel->info_clist));
749 label = gtk_label_new(_("Requested Font Name:"));
750 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
751 gtk_widget_show (label);
752 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, TRUE, 0);
754 fontsel->requested_font_name = gtk_entry_new();
755 gtk_entry_set_editable(GTK_ENTRY(fontsel->requested_font_name), FALSE);
756 gtk_widget_show (fontsel->requested_font_name);
757 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox),
758 fontsel->requested_font_name, FALSE, TRUE, 0);
760 label = gtk_label_new(_("Actual Font Name:"));
761 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
762 gtk_widget_show (label);
763 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, TRUE, 0);
765 fontsel->actual_font_name = gtk_entry_new();
766 gtk_entry_set_editable(GTK_ENTRY(fontsel->actual_font_name), FALSE);
767 gtk_widget_show (fontsel->actual_font_name);
768 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox),
769 fontsel->actual_font_name, FALSE, TRUE, 0);
771 sprintf(buffer, _("%i fonts available with a total of %i styles."),
772 fontsel_info->nfonts, fontsel_info->nstyles);
773 label = gtk_label_new(buffer);
774 gtk_widget_show (label);
775 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, FALSE, 0);
777 gtk_signal_connect (GTK_OBJECT (fontsel), "switch_page",
778 GTK_SIGNAL_FUNC(gtk_font_selection_switch_page),
782 /* Create the Filter page. */
783 fontsel->filter_vbox = gtk_vbox_new (FALSE, 4);
784 gtk_widget_show (fontsel->filter_vbox);
785 gtk_container_set_border_width (GTK_CONTAINER (fontsel->filter_vbox), 2);
786 label = gtk_label_new(_("Filter"));
787 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
788 fontsel->filter_vbox, label);
790 /* Create the font type checkbuttons. */
791 frame = gtk_frame_new (NULL);
792 gtk_widget_show (frame);
793 gtk_box_pack_start (GTK_BOX (fontsel->filter_vbox), frame, FALSE, TRUE, 0);
795 hbox = gtk_hbox_new (FALSE, 20);
796 gtk_widget_show (hbox);
797 gtk_container_add (GTK_CONTAINER (frame), hbox);
799 label = gtk_label_new(_("Font Types:"));
800 gtk_widget_show (label);
801 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 10);
803 hbox2 = gtk_hbox_new (TRUE, 0);
804 gtk_widget_show (hbox2);
805 gtk_box_pack_start (GTK_BOX (hbox), hbox2, FALSE, TRUE, 0);
807 fontsel->type_bitmaps_button = gtk_check_button_new_with_label (_("Bitmap"));
808 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), TRUE);
809 gtk_widget_show (fontsel->type_bitmaps_button);
810 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_bitmaps_button,
813 fontsel->type_scalable_button = gtk_check_button_new_with_label (_("Scalable"));
814 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), TRUE);
815 gtk_widget_show (fontsel->type_scalable_button);
816 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_scalable_button,
819 fontsel->type_scaled_bitmaps_button = gtk_check_button_new_with_label (_("Scaled Bitmap"));
820 gtk_widget_show (fontsel->type_scaled_bitmaps_button);
821 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->type_scaled_bitmaps_button,
824 table = gtk_table_new (4, 3, FALSE);
825 gtk_table_set_col_spacings(GTK_TABLE(table), 2);
826 gtk_widget_show (table);
827 gtk_box_pack_start (GTK_BOX (fontsel->filter_vbox), table, TRUE, TRUE, 0);
829 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
831 gint left = filter_positions[prop][0];
832 gint top = filter_positions[prop][1];
834 label = gtk_label_new(_(xlfd_field_names[xlfd_index[prop]]));
835 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 1.0);
836 gtk_misc_set_padding (GTK_MISC (label), 0, 2);
837 gtk_widget_show(label);
838 gtk_table_attach (GTK_TABLE (table), label, left, left + 1,
839 top, top + 1, GTK_FILL, GTK_FILL, 0, 0);
841 clist = gtk_clist_new(1);
842 gtk_widget_set_usize (clist, 100, filter_heights[prop]);
843 gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_MULTIPLE);
844 gtk_clist_column_titles_hide(GTK_CLIST(clist));
845 gtk_clist_set_column_auto_resize (GTK_CLIST (clist), 0, TRUE);
846 scrolled_win = gtk_scrolled_window_new (NULL, NULL);
847 gtk_container_add (GTK_CONTAINER (scrolled_win), clist);
848 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
849 GTK_POLICY_AUTOMATIC,
850 GTK_POLICY_AUTOMATIC);
851 gtk_widget_show(clist);
852 gtk_widget_show(scrolled_win);
854 /* For the bottom-right cell we add the 'Reset Filter' button. */
855 if (top == 2 && left == 2)
857 vbox = gtk_vbox_new(FALSE, 0);
858 gtk_widget_show(vbox);
859 gtk_table_attach (GTK_TABLE (table), vbox, left, left + 1,
860 top + 1, top + 2, GTK_FILL, GTK_FILL, 0, 0);
862 gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0);
864 alignment = gtk_alignment_new(0.5, 0.0, 0.8, 0.0);
865 gtk_widget_show(alignment);
866 gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, TRUE, 4);
868 button = gtk_button_new_with_label(_("Reset Filter"));
869 gtk_widget_show(button);
870 gtk_container_add(GTK_CONTAINER(alignment), button);
871 gtk_signal_connect (GTK_OBJECT (button), "clicked",
872 GTK_SIGNAL_FUNC(gtk_font_selection_reset_filter),
876 gtk_table_attach (GTK_TABLE (table), scrolled_win,
877 left, left + 1, top + 1, top + 2,
878 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
880 gtk_signal_connect (GTK_OBJECT (clist), "select_row",
881 GTK_SIGNAL_FUNC(gtk_font_selection_select_filter),
883 gtk_signal_connect (GTK_OBJECT (clist), "unselect_row",
884 GTK_SIGNAL_FUNC(gtk_font_selection_unselect_filter),
887 /* Insert the property names, expanded, and in sorted order.
888 But we make sure that the wildcard '*' is first. */
889 gtk_clist_freeze (GTK_CLIST(clist));
891 gtk_clist_append(GTK_CLIST(clist), &property);
893 for (i = 1; i < fontsel_info->nproperties[prop]; i++) {
894 property = fontsel_info->properties[prop][i];
896 property = gtk_font_selection_expand_slant_code(property);
897 else if (prop == SPACING)
898 property = gtk_font_selection_expand_spacing_code(property);
901 for (row = 1; row < GTK_CLIST(clist)->rows; row++)
903 gtk_clist_get_text(GTK_CLIST(clist), row, 0, &text);
904 if (strcmp(property, text) < 0)
907 gtk_clist_insert(GTK_CLIST(clist), row, &property);
912 row = gtk_clist_append(GTK_CLIST(clist), &property);
913 gtk_clist_set_row_data(GTK_CLIST(clist), row, GINT_TO_POINTER (i));
915 gtk_clist_select_row(GTK_CLIST(clist), 0, 0);
916 gtk_clist_thaw (GTK_CLIST(clist));
917 fontsel->filter_clists[prop] = clist;
922 gtk_font_selection_new()
924 GtkFontSelection *fontsel;
926 fontsel = gtk_type_new (GTK_TYPE_FONT_SELECTION);
928 return GTK_WIDGET (fontsel);
932 gtk_font_selection_destroy (GtkObject *object)
934 GtkFontSelection *fontsel;
936 g_return_if_fail (object != NULL);
937 g_return_if_fail (GTK_IS_FONT_SELECTION (object));
939 fontsel = GTK_FONT_SELECTION (object);
941 /* All we have to do is unref the font, if we have one. */
943 gdk_font_unref (fontsel->font);
945 if (GTK_OBJECT_CLASS (font_selection_parent_class)->destroy)
946 (* GTK_OBJECT_CLASS (font_selection_parent_class)->destroy) (object);
950 /* This is called when the clist is exposed. Here we scroll to the current
951 font if necessary. */
953 gtk_font_selection_expose_list (GtkWidget *widget,
954 GdkEventExpose *event,
957 GtkFontSelection *fontsel;
963 g_message("In expose_list\n");
965 fontsel = GTK_FONT_SELECTION(data);
967 font_info = fontsel_info->font_info;
969 /* Try to scroll the font family clist to the selected item */
970 selection = GTK_CLIST(fontsel->font_clist)->selection;
973 index = GPOINTER_TO_INT (selection->data);
974 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_clist), index)
975 != GTK_VISIBILITY_FULL)
976 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), index, -1, 0.5, 0);
979 /* Try to scroll the font style clist to the selected item */
980 selection = GTK_CLIST(fontsel->font_style_clist)->selection;
983 index = GPOINTER_TO_INT (selection->data);
984 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_style_clist), index)
985 != GTK_VISIBILITY_FULL)
986 gtk_clist_moveto(GTK_CLIST(fontsel->font_style_clist), index, -1,
990 /* Try to scroll the font size clist to the selected item */
991 selection = GTK_CLIST(fontsel->size_clist)->selection;
994 index = GPOINTER_TO_INT (selection->data);
995 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->size_clist), index)
996 != GTK_VISIBILITY_FULL)
997 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), index, -1, 0.5, 0);
1002 /* This is called when the style clist is realized. We need to set any
1003 charset rows to insensitive colours. */
1005 gtk_font_selection_realize_list (GtkWidget *widget,
1008 GtkFontSelection *fontsel;
1010 GdkColor *inactive_fg, *inactive_bg;
1012 #ifdef FONTSEL_DEBUG
1013 g_message("In realize_list\n");
1015 fontsel = GTK_FONT_SELECTION (data);
1017 /* Set the colours for any charset rows to insensitive. */
1018 inactive_fg = &fontsel->font_style_clist->style->fg[GTK_STATE_INSENSITIVE];
1019 inactive_bg = &fontsel->font_style_clist->style->bg[GTK_STATE_INSENSITIVE];
1021 for (row = 0; row < GTK_CLIST (fontsel->font_style_clist)->rows; row++)
1023 if (GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_style_clist), row)) == -1)
1025 gtk_clist_set_foreground (GTK_CLIST (fontsel->font_style_clist),
1027 gtk_clist_set_background (GTK_CLIST (fontsel->font_style_clist),
1034 /* This is called when a family is selected in the list. */
1036 gtk_font_selection_select_font (GtkWidget *w,
1039 GdkEventButton *bevent,
1042 GtkFontSelection *fontsel;
1043 FontInfo *font_info;
1046 #ifdef FONTSEL_DEBUG
1047 g_message("In select_font\n");
1049 fontsel = GTK_FONT_SELECTION(data);
1050 font_info = fontsel_info->font_info;
1052 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1053 gtk_widget_grab_focus (w);
1055 row = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_clist), row));
1056 font = &font_info[row];
1057 gtk_entry_set_text(GTK_ENTRY(fontsel->font_entry), font->family);
1059 /* If it is already the current font, just return. */
1060 if (fontsel->font_index == row)
1063 fontsel->font_index = row;
1064 gtk_font_selection_show_available_styles (fontsel);
1065 gtk_font_selection_select_best_style (fontsel, TRUE);
1070 gtk_font_selection_on_clist_key_press (GtkWidget *clist,
1072 GtkFontSelection *fontsel)
1074 #ifdef FONTSEL_DEBUG
1075 g_message("In on_clist_key_press\n");
1077 if (event->keyval == GDK_Up)
1078 return gtk_font_selection_select_next (fontsel, clist, -1);
1079 else if (event->keyval == GDK_Down)
1080 return gtk_font_selection_select_next (fontsel, clist, 1);
1087 gtk_font_selection_select_next (GtkFontSelection *fontsel,
1092 gint current_row, row;
1094 selection = GTK_CLIST(clist)->selection;
1097 current_row = GPOINTER_TO_INT (selection->data);
1099 /* Stop the normal clist key handler from being run. */
1100 gtk_signal_emit_stop_by_name (GTK_OBJECT (clist), "key_press_event");
1102 for (row = current_row + step;
1103 row >= 0 && row < GTK_CLIST(clist)->rows;
1106 /* If this is the style clist, make sure that the item is not a charset
1108 if (clist == fontsel->font_style_clist)
1109 if (GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(clist), row)) == -1)
1112 /* Now we've found the row to select. */
1113 if (gtk_clist_row_is_visible(GTK_CLIST(clist), row)
1114 != GTK_VISIBILITY_FULL)
1115 gtk_clist_moveto(GTK_CLIST(clist), row, -1, (step < 0) ? 0 : 1, 0);
1116 gtk_clist_select_row(GTK_CLIST(clist), row, 0);
1123 /* This fills the font style clist with all the possible style combinations
1124 for the current font family. */
1126 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
1130 gint style, tmpstyle, row;
1131 gint weight_index, slant_index, set_width_index, spacing_index;
1133 gchar *weight, *slant, *set_width, *spacing;
1134 gchar *charset = NULL;
1136 gchar buffer[XLFD_MAX_FIELD_LEN * 6 + 2];
1137 GdkColor *inactive_fg, *inactive_bg;
1138 gboolean show_charset;
1140 #ifdef FONTSEL_DEBUG
1141 g_message("In show_available_styles\n");
1143 font = &fontsel_info->font_info[fontsel->font_index];
1144 styles = &fontsel_info->font_styles[font->style_index];
1146 gtk_clist_freeze (GTK_CLIST(fontsel->font_style_clist));
1147 gtk_clist_clear (GTK_CLIST(fontsel->font_style_clist));
1149 /* First we mark all visible styles as not having been displayed yet,
1150 and check if every style has the same charset. If not then we will
1151 display the charset in the list before the styles. */
1152 show_charset = FALSE;
1154 for (style = 0; style < font->nstyles; style++)
1156 if (gtk_font_selection_style_visible(fontsel, font, style))
1158 styles[style].flags &= ~GTK_FONT_DISPLAYED;
1160 if (charset_index == -1)
1161 charset_index = styles[style].properties[CHARSET];
1162 else if (charset_index != styles[style].properties[CHARSET])
1163 show_charset = TRUE;
1166 styles[style].flags |= GTK_FONT_DISPLAYED;
1169 /* Step through the undisplayed styles, finding the next charset which
1170 hasn't been displayed yet. Then display the charset on one line, if
1171 necessary, and the visible styles indented beneath it. */
1172 inactive_fg = &fontsel->font_style_clist->style->fg[GTK_STATE_INSENSITIVE];
1173 inactive_bg = &fontsel->font_style_clist->style->bg[GTK_STATE_INSENSITIVE];
1175 for (style = 0; style < font->nstyles; style++)
1177 if (styles[style].flags & GTK_FONT_DISPLAYED)
1182 charset_index = styles[style].properties[CHARSET];
1183 charset = fontsel_info->properties[CHARSET] [charset_index];
1184 row = gtk_clist_append(GTK_CLIST(fontsel->font_style_clist),
1186 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_style_clist), row,
1188 if (GTK_WIDGET_REALIZED (fontsel->font_style_clist))
1190 gtk_clist_set_foreground(GTK_CLIST(fontsel->font_style_clist),
1192 gtk_clist_set_background(GTK_CLIST(fontsel->font_style_clist),
1197 for (tmpstyle = style; tmpstyle < font->nstyles; tmpstyle++)
1199 if (styles[tmpstyle].flags & GTK_FONT_DISPLAYED
1200 || charset_index != styles[tmpstyle].properties[CHARSET])
1203 styles[tmpstyle].flags |= GTK_FONT_DISPLAYED;
1205 weight_index = styles[tmpstyle].properties[WEIGHT];
1206 slant_index = styles[tmpstyle].properties[SLANT];
1207 set_width_index = styles[tmpstyle].properties[SET_WIDTH];
1208 spacing_index = styles[tmpstyle].properties[SPACING];
1209 weight = fontsel_info->properties[WEIGHT] [weight_index];
1210 slant = fontsel_info->properties[SLANT] [slant_index];
1211 set_width = fontsel_info->properties[SET_WIDTH][set_width_index];
1212 spacing = fontsel_info->properties[SPACING] [spacing_index];
1214 /* Convert '(nil)' weights to 'regular', since it looks nicer. */
1215 if (!g_strcasecmp(weight, "(nil)")) weight = _("regular");
1217 /* We don't show default values or (nil) in the other properties. */
1218 if (!g_strcasecmp(slant, "r")) slant = NULL;
1219 else if (!g_strcasecmp(slant, "(nil)")) slant = NULL;
1220 else if (!g_strcasecmp(slant, "i")) slant = _("italic");
1221 else if (!g_strcasecmp(slant, "o")) slant = _("oblique");
1222 else if (!g_strcasecmp(slant, "ri")) slant = _("reverse italic");
1223 else if (!g_strcasecmp(slant, "ro")) slant = _("reverse oblique");
1224 else if (!g_strcasecmp(slant, "ot")) slant = _("other");
1226 if (!g_strcasecmp(set_width, "normal")) set_width = NULL;
1227 else if (!g_strcasecmp(set_width, "(nil)")) set_width = NULL;
1229 if (!g_strcasecmp(spacing, "p")) spacing = NULL;
1230 else if (!g_strcasecmp(spacing, "(nil)")) spacing = NULL;
1231 else if (!g_strcasecmp(spacing, "m")) spacing = _("[M]");
1232 else if (!g_strcasecmp(spacing, "c")) spacing = _("[C]");
1234 /* Add the strings together, making sure there is 1 space between
1236 strcpy(buffer, weight);
1239 strcat(buffer, " ");
1240 strcat(buffer, slant);
1244 strcat(buffer, " ");
1245 strcat(buffer, set_width);
1249 strcat(buffer, " ");
1250 strcat(buffer, spacing);
1254 row = gtk_clist_append(GTK_CLIST(fontsel->font_style_clist),
1257 gtk_clist_set_shift(GTK_CLIST(fontsel->font_style_clist), row, 0,
1259 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_style_clist), row,
1260 GINT_TO_POINTER (tmpstyle));
1264 gtk_clist_thaw (GTK_CLIST(fontsel->font_style_clist));
1268 /* This selects a style when the user selects a font. It just uses the first
1269 available style at present. I was thinking of trying to maintain the
1270 selected style, e.g. bold italic, when the user selects different fonts.
1271 However, the interface is so easy to use now I'm not sure it's worth it.
1272 Note: This will load a font. */
1274 gtk_font_selection_select_best_style(GtkFontSelection *fontsel,
1279 gint row, prop, style, matched;
1280 gint best_matched = -1, best_style = -1, best_row = -1;
1282 #ifdef FONTSEL_DEBUG
1283 g_message("In select_best_style\n");
1285 font = &fontsel_info->font_info[fontsel->font_index];
1286 styles = &fontsel_info->font_styles[font->style_index];
1288 for (row = 0; row < GTK_CLIST(fontsel->font_style_clist)->rows; row++)
1290 style = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_style_clist), row));
1291 /* Skip charset rows. */
1295 /* If we just want the first style, we've got it. */
1304 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1306 if (fontsel->property_values[prop] == styles[style].properties[prop])
1309 if (matched > best_matched)
1311 best_matched = matched;
1316 g_return_if_fail (best_style != -1);
1317 g_return_if_fail (best_row != -1);
1319 fontsel->style = best_style;
1321 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1322 fontsel->property_values[prop] = styles[fontsel->style].properties[prop];
1324 gtk_clist_select_row(GTK_CLIST(fontsel->font_style_clist), best_row, 0);
1325 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_style_clist), best_row)
1326 != GTK_VISIBILITY_FULL)
1327 gtk_clist_moveto(GTK_CLIST(fontsel->font_style_clist), best_row, -1,
1329 gtk_font_selection_show_available_sizes (fontsel);
1330 gtk_font_selection_select_best_size (fontsel);
1334 /* This is called when a style is selected in the list. */
1336 gtk_font_selection_select_style (GtkWidget *w,
1339 GdkEventButton *bevent,
1342 GtkFontSelection *fontsel;
1343 FontInfo *font_info;
1349 #ifdef FONTSEL_DEBUG
1350 g_message("In select_style\n");
1352 fontsel = GTK_FONT_SELECTION(data);
1353 font_info = fontsel_info->font_info;
1354 font = &font_info[fontsel->font_index];
1355 styles = &fontsel_info->font_styles[font->style_index];
1357 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1358 gtk_widget_grab_focus (w);
1360 /* The style index is stored in the row data, so we just need to copy
1361 the style values into the fontsel and reload the font. */
1362 style = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(fontsel->font_style_clist), row));
1364 /* Don't allow selection of charset rows. */
1367 gtk_clist_unselect_row(GTK_CLIST(fontsel->font_style_clist), row, 0);
1371 gtk_clist_get_text(GTK_CLIST(fontsel->font_style_clist), row, 0, &text);
1372 gtk_entry_set_text(GTK_ENTRY(fontsel->font_style_entry), text);
1374 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1375 fontsel->property_values[prop] = styles[style].properties[prop];
1377 if (fontsel->style == style)
1380 fontsel->style = style;
1381 gtk_font_selection_show_available_sizes (fontsel);
1382 gtk_font_selection_select_best_size (fontsel);
1386 /* This shows all the available sizes in the size clist, according to the
1387 current metric and the current font & style. */
1389 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel)
1392 FontStyle *styles, *style;
1393 const guint16 *standard_sizes;
1394 guint16 *bitmapped_sizes, bitmap_size;
1395 gint nstandard_sizes, nbitmapped_sizes;
1396 gchar buffer[16], *size;
1397 gfloat bitmap_size_float;
1401 #ifdef FONTSEL_DEBUG
1402 g_message("In show_available_sizes\n");
1404 font = &fontsel_info->font_info[fontsel->font_index];
1405 styles = &fontsel_info->font_styles[font->style_index];
1406 style = &styles[fontsel->style];
1408 standard_sizes = font_sizes;
1409 nstandard_sizes = sizeof(font_sizes) / sizeof(font_sizes[0]);
1410 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1412 bitmapped_sizes = &fontsel_info->point_sizes[style->point_sizes_index];
1413 nbitmapped_sizes = style->npoint_sizes;
1417 bitmapped_sizes = &fontsel_info->pixel_sizes[style->pixel_sizes_index];
1418 nbitmapped_sizes = style->npixel_sizes;
1421 /* Only show the standard sizes if a scalable font is available. */
1422 type_filter = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
1423 & fontsel->filters[GTK_FONT_FILTER_USER].font_type;
1425 if (!((style->flags & GTK_FONT_SCALABLE_BITMAP
1426 && type_filter & GTK_FONT_SCALABLE_BITMAP)
1427 || (style->flags & GTK_FONT_SCALABLE
1428 && type_filter & GTK_FONT_SCALABLE)))
1429 nstandard_sizes = 0;
1431 gtk_clist_freeze (GTK_CLIST(fontsel->size_clist));
1432 gtk_clist_clear (GTK_CLIST(fontsel->size_clist));
1434 /* Interleave the standard sizes with the bitmapped sizes so we get a list
1435 of ascending sizes. If the metric is points, we have to convert the
1436 decipoints to points. */
1437 while (nstandard_sizes || nbitmapped_sizes)
1440 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1442 if (*bitmapped_sizes % 10 != 0)
1444 bitmap_size = *bitmapped_sizes / 10;
1445 bitmap_size_float = *bitmapped_sizes / 10;
1449 bitmap_size = *bitmapped_sizes;
1450 bitmap_size_float = *bitmapped_sizes;
1453 if (can_match && nstandard_sizes && nbitmapped_sizes
1454 && *standard_sizes == bitmap_size)
1456 sprintf(buffer, "%i *", *standard_sizes);
1462 else if (nstandard_sizes
1463 && (!nbitmapped_sizes
1464 || (gfloat)*standard_sizes < bitmap_size_float))
1466 sprintf(buffer, "%i", *standard_sizes);
1472 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1474 if (*bitmapped_sizes % 10 == 0)
1475 sprintf(buffer, "%i *", *bitmapped_sizes / 10);
1477 sprintf(buffer, "%i.%i *", *bitmapped_sizes / 10,
1478 *bitmapped_sizes % 10);
1482 sprintf(buffer, "%i *", *bitmapped_sizes);
1488 gtk_clist_append(GTK_CLIST(fontsel->size_clist), &size);
1490 gtk_clist_thaw (GTK_CLIST(fontsel->size_clist));
1494 /* If the user hits return in the font size entry, we change to the new font
1497 gtk_font_selection_size_key_press (GtkWidget *w,
1501 GtkFontSelection *fontsel;
1503 gfloat new_size_float;
1506 #ifdef FONTSEL_DEBUG
1507 g_message("In size_key_press\n");
1509 fontsel = GTK_FONT_SELECTION(data);
1511 if (event->keyval == GDK_Return)
1513 text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1514 if (fontsel->metric == GTK_FONT_METRIC_PIXELS)
1516 new_size = atoi (text);
1522 new_size_float = atof (text) * 10;
1523 new_size = (gint) new_size_float;
1528 /* Remember that this size was set explicitly. */
1529 fontsel->selected_size = new_size;
1531 /* Check if the font size has changed, and return if it hasn't. */
1532 if (fontsel->size == new_size)
1535 fontsel->size = new_size;
1536 gtk_font_selection_select_best_size (fontsel);
1544 /* This tries to select the closest size to the current size, though it
1545 may have to change the size if only unscaled bitmaps are available.
1546 Note: this will load a font. */
1548 gtk_font_selection_select_best_size(GtkFontSelection *fontsel)
1551 FontStyle *styles, *style;
1553 gint row, best_row = 0, size, size_fraction, best_size = 0, nmatched;
1554 gboolean found = FALSE;
1559 #ifdef FONTSEL_DEBUG
1560 g_message("In select_best_size\n");
1562 font = &fontsel_info->font_info[fontsel->font_index];
1563 styles = &fontsel_info->font_styles[font->style_index];
1564 style = &styles[fontsel->style];
1566 /* Find the closest size available in the size clist. If the exact size is
1567 in the list set found to TRUE. */
1568 for (row = 0; row < GTK_CLIST(fontsel->size_clist)->rows; row++)
1570 gtk_clist_get_text(GTK_CLIST(fontsel->size_clist), row, 0, &text);
1571 nmatched = sscanf(text, "%i.%i", &size, &size_fraction);
1572 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1576 size += size_fraction;
1579 if (size == fontsel->selected_size)
1586 else if (best_size == 0
1587 || abs(size - fontsel->selected_size)
1588 < (abs(best_size - fontsel->selected_size)))
1595 /* If we aren't scaling bitmapped fonts and this is a bitmapped font, we
1596 need to use the closest size found. */
1597 type_filter = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
1598 & fontsel->filters[GTK_FONT_FILTER_USER].font_type;
1600 if (!((style->flags & GTK_FONT_SCALABLE_BITMAP
1601 && type_filter & GTK_FONT_SCALABLE_BITMAP)
1602 || (style->flags & GTK_FONT_SCALABLE
1603 && type_filter & GTK_FONT_SCALABLE)))
1608 fontsel->size = best_size;
1609 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), best_row, -1, 0.5, 0);
1610 gtk_clist_select_row(GTK_CLIST(fontsel->size_clist), best_row, 0);
1614 fontsel->size = fontsel->selected_size;
1615 selection = GTK_CLIST(fontsel->size_clist)->selection;
1617 gtk_clist_unselect_row(GTK_CLIST(fontsel->size_clist),
1618 GPOINTER_TO_INT (selection->data), 0);
1619 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), best_row, -1, 0.5, 0);
1621 /* Show the size in the size entry. */
1622 if (fontsel->metric == GTK_FONT_METRIC_PIXELS)
1623 sprintf(buffer, "%i", fontsel->size);
1626 if (fontsel->size % 10 == 0)
1627 sprintf(buffer, "%i", fontsel->size / 10);
1629 sprintf(buffer, "%i.%i", fontsel->size / 10, fontsel->size % 10);
1631 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
1633 gtk_font_selection_load_font (fontsel);
1637 /* This is called when a size is selected in the list. */
1639 gtk_font_selection_select_size (GtkWidget *w,
1642 GdkEventButton *bevent,
1645 GtkFontSelection *fontsel;
1651 #ifdef FONTSEL_DEBUG
1652 g_message("In select_size\n");
1654 fontsel = GTK_FONT_SELECTION(data);
1656 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1657 gtk_widget_grab_focus (w);
1659 /* Copy the size from the clist to the size entry, but without the bitmapped
1661 gtk_clist_get_text(GTK_CLIST(fontsel->size_clist), row, 0, &text);
1663 while (i < 15 && (text[i] == '.' || (text[i] >= '0' && text[i] <= '9')))
1665 buffer[i] = text[i];
1669 gtk_entry_set_text(GTK_ENTRY(fontsel->size_entry), buffer);
1671 /* Check if the font size has changed, and return if it hasn't. */
1672 new_size = atoi(text);
1673 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1676 if (fontsel->size == new_size)
1679 /* If the size was selected by the user we set the selected_size. */
1680 fontsel->selected_size = new_size;
1682 fontsel->size = new_size;
1683 gtk_font_selection_load_font (fontsel);
1687 /* This is called when the pixels or points radio buttons are pressed. */
1689 gtk_font_selection_metric_callback (GtkWidget *w,
1692 GtkFontSelection *fontsel = GTK_FONT_SELECTION(data);
1694 #ifdef FONTSEL_DEBUG
1695 g_message("In metric_callback\n");
1697 if (GTK_TOGGLE_BUTTON(fontsel->pixels_button)->active)
1699 if (fontsel->metric == GTK_FONT_METRIC_PIXELS)
1701 fontsel->metric = GTK_FONT_METRIC_PIXELS;
1702 fontsel->size = (fontsel->size + 5) / 10;
1703 fontsel->selected_size = (fontsel->selected_size + 5) / 10;
1707 if (fontsel->metric == GTK_FONT_METRIC_POINTS)
1709 fontsel->metric = GTK_FONT_METRIC_POINTS;
1710 fontsel->size *= 10;
1711 fontsel->selected_size *= 10;
1713 if (fontsel->font_index != -1)
1715 gtk_font_selection_show_available_sizes (fontsel);
1716 gtk_font_selection_select_best_size (fontsel);
1721 /* This searches the given property table and returns the index of the given
1722 string, or 0, which is the wildcard '*' index, if it's not found. */
1724 gtk_font_selection_field_to_index (gchar **table,
1730 for (i = 0; i < ntable; i++)
1731 if (strcmp (field, table[i]) == 0)
1739 /* This attempts to load the current font, and returns TRUE if it succeeds. */
1741 gtk_font_selection_load_font (GtkFontSelection *fontsel)
1744 gchar *fontname, *label_text;
1747 gdk_font_unref (fontsel->font);
1748 fontsel->font = NULL;
1750 /* If no family has been selected yet, just return FALSE. */
1751 if (fontsel->font_index == -1)
1754 fontname = gtk_font_selection_get_font_name (fontsel);
1757 #ifdef FONTSEL_DEBUG
1758 g_message("Loading: %s\n", fontname);
1760 font = gdk_font_load (fontname);
1765 fontsel->font = font;
1766 /* Make sure the message label is empty, but don't change it unless
1767 it's necessary as it results in a resize of the whole window! */
1768 gtk_label_get(GTK_LABEL(fontsel->message_label), &label_text);
1769 if (strcmp(label_text, ""))
1770 gtk_label_set_text(GTK_LABEL(fontsel->message_label), "");
1771 gtk_font_selection_update_preview (fontsel);
1776 gtk_label_set_text(GTK_LABEL(fontsel->message_label),
1777 _("The selected font is not available."));
1782 gtk_label_set_text(GTK_LABEL(fontsel->message_label),
1783 _("The selected font is not a valid font."));
1790 /* This sets the font in the preview entry to the selected font, and tries to
1791 make sure that the preview entry is a reasonable size, i.e. so that the
1792 text can be seen with a bit of space to spare. But it tries to avoid
1793 resizing the entry every time the font changes.
1794 This also used to shrink the preview if the font size was decreased, but
1795 that made it awkward if the user wanted to resize the window themself. */
1797 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1799 GtkWidget *preview_entry;
1801 gint text_height, new_height;
1805 #ifdef FONTSEL_DEBUG
1806 g_message("In update_preview\n");
1808 style = gtk_style_new ();
1809 gdk_font_unref (style->font);
1810 style->font = fontsel->font;
1811 gdk_font_ref (style->font);
1813 preview_entry = fontsel->preview_entry;
1814 gtk_widget_set_style (preview_entry, style);
1815 gtk_style_unref(style);
1817 text_height = preview_entry->style->font->ascent
1818 + preview_entry->style->font->descent;
1819 /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1820 new_height = text_height + 20;
1821 if (new_height < INITIAL_PREVIEW_HEIGHT)
1822 new_height = INITIAL_PREVIEW_HEIGHT;
1823 if (new_height > MAX_PREVIEW_HEIGHT)
1824 new_height = MAX_PREVIEW_HEIGHT;
1826 if ((preview_entry->requisition.height < text_height + 10)
1827 || (preview_entry->requisition.height > text_height + 40))
1828 gtk_widget_set_usize(preview_entry, -1, new_height);
1830 /* This sets the preview text, if it hasn't been set already. */
1831 text = gtk_entry_get_text(GTK_ENTRY(fontsel->preview_entry));
1832 if (strlen(text) == 0)
1833 gtk_entry_set_text(GTK_ENTRY(fontsel->preview_entry), PREVIEW_TEXT);
1834 gtk_entry_set_position(GTK_ENTRY(fontsel->preview_entry), 0);
1836 /* If this is a 2-byte font display a message to say it may not be
1837 displayed properly. */
1838 xfs = GDK_FONT_XFONT(fontsel->font);
1839 if (xfs->min_byte1 != 0 || xfs->max_byte1 != 0)
1840 gtk_label_set_text(GTK_LABEL(fontsel->message_label),
1841 _("This is a 2-byte font and may not be displayed correctly."));
1846 gtk_font_selection_switch_page (GtkWidget *w,
1847 GtkNotebookPage *page,
1851 GtkFontSelection *fontsel = GTK_FONT_SELECTION(data);
1853 /* This function strangely gets called when the window is destroyed,
1854 so we check here to see if the notebook is visible. */
1855 if (!GTK_WIDGET_VISIBLE(w))
1859 gtk_font_selection_update_filter(fontsel);
1860 else if (page_num == 1)
1861 gtk_font_selection_show_font_info(fontsel);
1866 gtk_font_selection_show_font_info (GtkFontSelection *fontsel)
1868 Atom font_atom, atom;
1872 gchar field_buffer[XLFD_MAX_FIELD_LEN];
1875 gboolean shown_actual_fields = FALSE;
1877 fontname = gtk_font_selection_get_font_name(fontsel);
1878 gtk_entry_set_text(GTK_ENTRY(fontsel->requested_font_name),
1879 fontname ? fontname : "");
1881 gtk_clist_freeze (GTK_CLIST(fontsel->info_clist));
1882 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1885 field = gtk_font_selection_get_xlfd_field (fontname, i, field_buffer);
1890 if (i == XLFD_SLANT)
1891 field = gtk_font_selection_expand_slant_code(field);
1892 else if (i == XLFD_SPACING)
1893 field = gtk_font_selection_expand_spacing_code(field);
1895 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 1,
1896 field ? field : "");
1901 font_atom = XInternAtom(GDK_DISPLAY(), "FONT", True);
1902 if (font_atom != None)
1904 status = XGetFontProperty(GDK_FONT_XFONT(fontsel->font), font_atom,
1908 name = XGetAtomName(GDK_DISPLAY(), atom);
1909 gtk_entry_set_text(GTK_ENTRY(fontsel->actual_font_name), name);
1911 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1913 field = gtk_font_selection_get_xlfd_field (name, i,
1915 if (i == XLFD_SLANT)
1916 field = gtk_font_selection_expand_slant_code(field);
1917 else if (i == XLFD_SPACING)
1918 field = gtk_font_selection_expand_spacing_code(field);
1919 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 2,
1920 field ? field : "");
1922 shown_actual_fields = TRUE;
1927 if (!shown_actual_fields)
1929 gtk_entry_set_text(GTK_ENTRY(fontsel->actual_font_name), "");
1930 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1932 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 2,
1933 fontname ? _("(unknown)") : "");
1936 gtk_clist_thaw (GTK_CLIST(fontsel->info_clist));
1942 gtk_font_selection_expand_slant_code(gchar *slant)
1944 if (!g_strcasecmp(slant, "r")) return(_("roman"));
1945 else if (!g_strcasecmp(slant, "i")) return(_("italic"));
1946 else if (!g_strcasecmp(slant, "o")) return(_("oblique"));
1947 else if (!g_strcasecmp(slant, "ri")) return(_("reverse italic"));
1948 else if (!g_strcasecmp(slant, "ro")) return(_("reverse oblique"));
1949 else if (!g_strcasecmp(slant, "ot")) return(_("other"));
1954 gtk_font_selection_expand_spacing_code(gchar *spacing)
1956 if (!g_strcasecmp(spacing, "p")) return(_("proportional"));
1957 else if (!g_strcasecmp(spacing, "m")) return(_("monospaced"));
1958 else if (!g_strcasecmp(spacing, "c")) return(_("char cell"));
1963 /*****************************************************************************
1964 * These functions all deal with the Filter page and filtering the fonts.
1965 *****************************************************************************/
1967 /* This is called when an item is selected in one of the filter clists.
1968 We make sure that the first row of the clist, i.e. the wildcard '*', is
1969 selected if and only if none of the other items are selected.
1970 Also doesn't allow selections of values filtered out by base filter.
1971 We may need to be careful about triggering other signals. */
1973 gtk_font_selection_select_filter (GtkWidget *w,
1976 GdkEventButton *bevent,
1977 GtkFontSelection *fontsel)
1979 gint i, prop, index;
1983 for (i = 1; i < GTK_CLIST(w)->rows; i++)
1984 gtk_clist_unselect_row(GTK_CLIST(w), i, 0);
1988 /* Find out which property this is. */
1989 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
1990 if (fontsel->filter_clists[prop] == w)
1992 index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(w), row));
1993 if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_BASE,
1994 prop, index) == NOT_FILTERED)
1995 gtk_clist_unselect_row(GTK_CLIST(w), row, 0);
1997 gtk_clist_unselect_row(GTK_CLIST(w), 0, 0);
2002 /* Here a filter item is being deselected. If there are now no items selected
2003 we select the first '*' item, unless that it is the item being deselected,
2004 in which case we select all of the other items. This makes it easy to
2005 select all items in the list except one or two. */
2007 gtk_font_selection_unselect_filter (GtkWidget *w,
2010 GdkEventButton *bevent,
2011 GtkFontSelection *fontsel)
2013 gint i, prop, index;
2015 if (!GTK_CLIST(w)->selection)
2019 /* Find out which property this is. */
2020 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2021 if (fontsel->filter_clists[prop] == w)
2024 for (i = 1; i < GTK_CLIST(w)->rows; i++)
2026 index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(w),
2028 if (gtk_font_selection_filter_state (fontsel,
2029 GTK_FONT_FILTER_BASE,
2032 gtk_clist_select_row(GTK_CLIST(w), i, 0);
2037 gtk_clist_select_row(GTK_CLIST(w), 0, 0);
2043 /* This is called when the main notebook page is selected. It checks if the
2044 filter has changed, an if so it creates the filter settings, and filters the
2045 fonts shown. If an empty filter (all '*'s) is applied, then filtering is
2048 gtk_font_selection_update_filter (GtkFontSelection *fontsel)
2052 gboolean default_filter = TRUE, filter_changed = FALSE;
2053 gint prop, nselected, i, row, index;
2054 GtkFontFilter *filter = &fontsel->filters[GTK_FONT_FILTER_USER];
2055 gint base_font_type, user_font_type, new_font_type;
2057 #ifdef FONTSEL_DEBUG
2058 g_message("In update_filter\n");
2061 /* Check if the user filter has changed, and also if it is the default
2062 filter, i.e. bitmap & scalable fonts and all '*'s selected.
2063 We only look at the bits which are not already filtered out by the base
2064 filter, since that overrides the user filter. */
2065 base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
2067 user_font_type = fontsel->filters[GTK_FONT_FILTER_USER].font_type
2069 new_font_type = GTK_TOGGLE_BUTTON(fontsel->type_bitmaps_button)->active
2070 ? GTK_FONT_BITMAP : 0;
2071 new_font_type |= (GTK_TOGGLE_BUTTON(fontsel->type_scalable_button)->active
2072 ? GTK_FONT_SCALABLE : 0);
2073 new_font_type |= (GTK_TOGGLE_BUTTON(fontsel->type_scaled_bitmaps_button)->active ? GTK_FONT_SCALABLE_BITMAP : 0);
2074 new_font_type &= base_font_type;
2075 new_font_type |= (~base_font_type & user_font_type);
2076 if (new_font_type != (GTK_FONT_BITMAP | GTK_FONT_SCALABLE))
2077 default_filter = FALSE;
2079 if (new_font_type != user_font_type)
2080 filter_changed = TRUE;
2081 fontsel->filters[GTK_FONT_FILTER_USER].font_type = new_font_type;
2083 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2085 clist = fontsel->filter_clists[prop];
2086 selection = GTK_CLIST(clist)->selection;
2087 nselected = g_list_length(selection);
2088 if (nselected != 1 || GPOINTER_TO_INT (selection->data) != 0)
2090 default_filter = FALSE;
2092 if (filter->property_nfilters[prop] != nselected)
2093 filter_changed = TRUE;
2096 for (i = 0; i < nselected; i++)
2098 row = GPOINTER_TO_INT (selection->data);
2099 index = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (clist), row));
2100 if (filter->property_filters[prop][i] != index)
2101 filter_changed = TRUE;
2102 selection = selection->next;
2108 if (filter->property_nfilters[prop] != 0)
2109 filter_changed = TRUE;
2113 /* If the filter hasn't changed we just return. */
2114 if (!filter_changed)
2117 #ifdef FONTSEL_DEBUG
2118 g_message(" update_fonts: filter has changed\n");
2121 /* Free the old filter data and create the new arrays. */
2122 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2124 g_free(filter->property_filters[prop]);
2126 clist = fontsel->filter_clists[prop];
2127 selection = GTK_CLIST(clist)->selection;
2128 nselected = g_list_length(selection);
2129 if (nselected == 1 && GPOINTER_TO_INT (selection->data) == 0)
2131 filter->property_filters[prop] = NULL;
2132 filter->property_nfilters[prop] = 0;
2136 filter->property_filters[prop] = g_new(guint16, nselected);
2137 filter->property_nfilters[prop] = nselected;
2138 for (i = 0; i < nselected; i++)
2140 row = GPOINTER_TO_INT (selection->data);
2141 index = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (clist), row));
2142 filter->property_filters[prop][i] = index;
2143 selection = selection->next;
2148 /* Set the 'Reset Filter' button sensitive if a filter is in effect, and
2149 also set the label above the font list to show this as well. */
2152 gtk_widget_set_sensitive(fontsel->filter_button, FALSE);
2153 gtk_label_set_text(GTK_LABEL(fontsel->font_label), _("Font:"));
2157 gtk_widget_set_sensitive(fontsel->filter_button, TRUE);
2158 gtk_label_set_text(GTK_LABEL(fontsel->font_label), _("Font: (Filter Applied)"));
2160 gtk_font_selection_show_available_fonts(fontsel);
2164 /* This shows all the available fonts in the font clist. */
2166 gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
2168 FontInfo *font_info, *font;
2169 GtkFontFilter *filter;
2170 gint nfonts, i, j, k, row, style, font_row = -1;
2171 gchar font_buffer[XLFD_MAX_FIELD_LEN * 2 + 4];
2173 gboolean matched, matched_style;
2175 #ifdef FONTSEL_DEBUG
2176 g_message("In show_available_fonts\n");
2178 font_info = fontsel_info->font_info;
2179 nfonts = fontsel_info->nfonts;
2181 /* Filter the list of fonts. */
2182 gtk_clist_freeze (GTK_CLIST(fontsel->font_clist));
2183 gtk_clist_clear (GTK_CLIST(fontsel->font_clist));
2184 for (i = 0; i < nfonts; i++)
2186 font = &font_info[i];
2188 /* Check if the foundry passes through all filters. */
2190 for (k = 0; k < GTK_NUM_FONT_FILTERS; k++)
2192 filter = &fontsel->filters[k];
2194 if (filter->property_nfilters[FOUNDRY] != 0)
2197 for (j = 0; j < filter->property_nfilters[FOUNDRY]; j++)
2199 if (font->foundry == filter->property_filters[FOUNDRY][j])
2214 /* Now check if the other properties are matched in at least one style.*/
2215 matched_style = FALSE;
2216 for (style = 0; style < font->nstyles; style++)
2218 if (gtk_font_selection_style_visible(fontsel, font, style))
2220 matched_style = TRUE;
2227 /* Insert the font in the clist. */
2228 if ((i > 0 && font->family == font_info[i-1].family)
2229 || (i < nfonts - 1 && font->family == font_info[i+1].family))
2231 sprintf(font_buffer, "%s (%s)", font->family,
2232 fontsel_info->properties[FOUNDRY][font->foundry]);
2233 font_item = font_buffer;
2234 row = gtk_clist_append(GTK_CLIST(fontsel->font_clist), &font_item);
2238 row = gtk_clist_append(GTK_CLIST(fontsel->font_clist),
2241 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_clist), row,
2242 GINT_TO_POINTER (i));
2243 if (fontsel->font_index == i)
2246 gtk_clist_thaw (GTK_CLIST(fontsel->font_clist));
2248 /* If the currently-selected font isn't in the new list, reset the
2252 fontsel->font_index = -1;
2254 gdk_font_unref(fontsel->font);
2255 fontsel->font = NULL;
2256 gtk_entry_set_text(GTK_ENTRY(fontsel->font_entry), "");
2257 gtk_clist_clear (GTK_CLIST(fontsel->font_style_clist));
2258 gtk_entry_set_text(GTK_ENTRY(fontsel->font_style_entry), "");
2262 gtk_clist_select_row(GTK_CLIST(fontsel->font_clist), font_row, 0);
2263 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_clist), font_row)
2264 != GTK_VISIBILITY_FULL)
2265 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), font_row, -1, 0.5, 0);
2267 gtk_font_selection_show_available_styles (fontsel);
2268 gtk_font_selection_select_best_style (fontsel, FALSE);
2272 /* Returns TRUE if the style is not currently filtered out. */
2274 gtk_font_selection_style_visible(GtkFontSelection *fontsel,
2278 FontStyle *styles, *style;
2279 GtkFontFilter *filter;
2285 styles = &fontsel_info->font_styles[font->style_index];
2286 style = &styles[style_index];
2288 /* Check if font_type of style is filtered. */
2289 type_filter = fontsel->filters[GTK_FONT_FILTER_BASE].font_type
2290 & fontsel->filters[GTK_FONT_FILTER_USER].font_type;
2291 if (!(style->flags & type_filter))
2294 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2296 value = style->properties[prop];
2298 /* Check each filter. */
2299 for (i = 0; i < GTK_NUM_FONT_FILTERS; i++)
2301 filter = &fontsel->filters[i];
2303 if (filter->property_nfilters[prop] != 0)
2306 for (j = 0; j < filter->property_nfilters[prop]; j++)
2308 if (value == filter->property_filters[prop][j])
2323 /* This resets the font type to bitmap or scalable, and sets all the filter
2324 clists to the wildcard '*' options. */
2326 gtk_font_selection_reset_filter (GtkWidget *w,
2327 GtkFontSelection *fontsel)
2329 gint prop, base_font_type;
2331 fontsel->filters[GTK_FONT_FILTER_USER].font_type = GTK_FONT_BITMAP
2332 | GTK_FONT_SCALABLE;
2334 base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type;
2335 if (base_font_type & GTK_FONT_BITMAP)
2336 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), TRUE);
2337 if (base_font_type & GTK_FONT_SCALABLE)
2338 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), TRUE);
2339 if (base_font_type & GTK_FONT_SCALABLE_BITMAP)
2340 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), FALSE);
2342 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2343 gtk_clist_select_row(GTK_CLIST(fontsel->filter_clists[prop]), 0, 0);
2347 /* This clears the filter, showing all fonts and styles again. */
2349 gtk_font_selection_on_clear_filter (GtkWidget *w,
2350 GtkFontSelection *fontsel)
2352 gtk_font_selection_clear_filter(fontsel);
2356 /* This resets the user filter, showing all fonts and styles which pass the
2357 base filter again. Note that the font type is set to bitmaps and scalable
2358 fonts - scaled bitmaps are not shown. */
2360 gtk_font_selection_clear_filter (GtkFontSelection *fontsel)
2362 GtkFontFilter *filter;
2365 #ifdef FONTSEL_DEBUG
2366 g_message("In clear_filter\n");
2368 /* Clear the filter data. */
2369 filter = &fontsel->filters[GTK_FONT_FILTER_USER];
2370 filter->font_type = GTK_FONT_BITMAP | GTK_FONT_SCALABLE;
2371 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2373 g_free(filter->property_filters[prop]);
2374 filter->property_filters[prop] = NULL;
2375 filter->property_nfilters[prop] = 0;
2378 /* Select all the '*'s on the filter page. */
2379 gtk_font_selection_reset_filter(NULL, fontsel);
2381 /* Update the main notebook page. */
2382 gtk_widget_set_sensitive(fontsel->filter_button, FALSE);
2383 gtk_label_set_text(GTK_LABEL(fontsel->font_label), _("Font:"));
2385 gtk_font_selection_show_available_fonts(fontsel);
2390 gtk_font_selection_set_filter (GtkFontSelection *fontsel,
2391 GtkFontFilterType filter_type,
2392 GtkFontType font_type,
2400 GtkFontFilter *filter;
2401 gchar **filter_strings [GTK_NUM_FONT_PROPERTIES];
2402 gchar *filter_string;
2403 gchar *property, *property_alt;
2404 gint prop, nfilters, i, j, num_found;
2405 gint base_font_type, user_font_type;
2406 gboolean filter_set;
2408 /* Put them into an array so we can use a simple loop. */
2409 filter_strings[FOUNDRY] = foundries;
2410 filter_strings[WEIGHT] = weights;
2411 filter_strings[SLANT] = slants;
2412 filter_strings[SET_WIDTH] = setwidths;
2413 filter_strings[SPACING] = spacings;
2414 filter_strings[CHARSET] = charsets;
2416 filter = &fontsel->filters[filter_type];
2417 filter->font_type = font_type;
2419 /* Free the old filter data, and insert the new. */
2420 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2422 g_free(filter->property_filters[prop]);
2423 filter->property_filters[prop] = NULL;
2424 filter->property_nfilters[prop] = 0;
2426 if (filter_strings[prop])
2428 /* Count how many items in the new array. */
2430 while (filter_strings[prop][nfilters])
2433 filter->property_filters[prop] = g_new(guint16, nfilters);
2434 filter->property_nfilters[prop] = 0;
2436 /* Now convert the strings to property indices. */
2438 for (i = 0; i < nfilters; i++)
2440 filter_string = filter_strings[prop][i];
2441 for (j = 0; j < fontsel_info->nproperties[prop]; j++)
2443 property = fontsel_info->properties[prop][j];
2444 property_alt = NULL;
2446 property_alt = gtk_font_selection_expand_slant_code(property);
2447 else if (prop == SPACING)
2448 property_alt = gtk_font_selection_expand_spacing_code(property);
2449 if (!strcmp (filter_string, property)
2450 || (property_alt && !strcmp (filter_string, property_alt)))
2452 filter->property_filters[prop][num_found] = j;
2458 filter->property_nfilters[prop] = num_found;
2462 /* Now set the clists on the filter page according to the new filter. */
2463 gtk_font_selection_update_filter_lists (fontsel);
2465 if (filter_type == GTK_FONT_FILTER_BASE)
2467 user_font_type = fontsel->filters[GTK_FONT_FILTER_USER].font_type;
2468 if (font_type & GTK_FONT_BITMAP)
2470 gtk_widget_set_sensitive (fontsel->type_bitmaps_button, TRUE);
2471 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), user_font_type & GTK_FONT_BITMAP);
2475 gtk_widget_set_sensitive (fontsel->type_bitmaps_button, FALSE);
2476 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), FALSE);
2479 if (font_type & GTK_FONT_SCALABLE)
2481 gtk_widget_set_sensitive (fontsel->type_scalable_button, TRUE);
2482 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), user_font_type & GTK_FONT_SCALABLE);
2486 gtk_widget_set_sensitive (fontsel->type_scalable_button, FALSE);
2487 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), FALSE);
2490 if (font_type & GTK_FONT_SCALABLE_BITMAP)
2492 gtk_widget_set_sensitive (fontsel->type_scaled_bitmaps_button, TRUE);
2493 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), user_font_type & GTK_FONT_SCALABLE_BITMAP);
2497 gtk_widget_set_sensitive (fontsel->type_scaled_bitmaps_button, FALSE);
2498 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), FALSE);
2503 base_font_type = fontsel->filters[GTK_FONT_FILTER_BASE].font_type;
2504 if (base_font_type & GTK_FONT_BITMAP)
2505 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_bitmaps_button), font_type & GTK_FONT_BITMAP);
2507 if (base_font_type & GTK_FONT_SCALABLE)
2508 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scalable_button), font_type & GTK_FONT_SCALABLE);
2510 if (base_font_type & GTK_FONT_SCALABLE_BITMAP)
2511 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (fontsel->type_scaled_bitmaps_button), font_type & GTK_FONT_SCALABLE_BITMAP);
2513 /* If the user filter is not the default, make the 'Reset Filter' button
2516 if (font_type != (GTK_FONT_BITMAP | GTK_FONT_SCALABLE))
2518 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2520 if (filter->property_nfilters[prop] != 0)
2524 gtk_widget_set_sensitive (fontsel->filter_button, TRUE);
2527 gtk_font_selection_show_available_fonts (fontsel);
2531 /* This sets the colour of each property in the filter clists according to
2532 the base filter. i.e. Filtered properties are shown as insensitive. */
2534 gtk_font_selection_update_filter_lists (GtkFontSelection *fontsel)
2537 GdkColor *inactive_fg, *inactive_bg, *fg, *bg;
2538 gint prop, row, index;
2540 /* We have to make sure the clist is realized to use the colours. */
2541 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2543 clist = fontsel->filter_clists[prop];
2544 gtk_widget_realize (clist);
2545 inactive_fg = &clist->style->fg[GTK_STATE_INSENSITIVE];
2546 inactive_bg = &clist->style->bg[GTK_STATE_INSENSITIVE];
2547 for (row = 1; row < GTK_CLIST(clist)->rows; row++)
2549 index = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(clist),
2551 /* Set the colour according to the base filter. */
2552 if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_BASE,
2553 prop, index) == NOT_FILTERED)
2563 gtk_clist_set_foreground(GTK_CLIST(clist), row, fg);
2564 gtk_clist_set_background(GTK_CLIST(clist), row, bg);
2566 /* Set the selection state according to the user filter. */
2567 if (gtk_font_selection_filter_state (fontsel, GTK_FONT_FILTER_USER,
2568 prop, index) == FILTERED
2570 gtk_clist_select_row (GTK_CLIST (clist), row, 0);
2572 gtk_clist_unselect_row (GTK_CLIST (clist), row, 0);
2578 /* Returns whether a property value is in the filter or not, or if the
2579 property has no filter set. */
2580 static GtkFontPropertyFilterState
2581 gtk_font_selection_filter_state (GtkFontSelection *fontsel,
2582 GtkFontFilterType filter_type,
2586 GtkFontFilter *filter;
2589 filter = &fontsel->filters[filter_type];
2590 if (filter->property_nfilters[property] == 0)
2593 for (i = 0; i < filter->property_nfilters[property]; i++)
2595 if (filter->property_filters[property][i] == index)
2598 return NOT_FILTERED;
2602 /*****************************************************************************
2603 * These functions all deal with creating the main class arrays containing
2604 * the data about all available fonts.
2605 *****************************************************************************/
2607 gtk_font_selection_get_fonts (void)
2614 gint i, prop, style, size;
2615 gint npixel_sizes = 0, npoint_sizes = 0;
2617 FontStyle *current_style, *prev_style, *tmp_style;
2618 gboolean matched_style, found_size;
2619 gint pixels, points, res_x, res_y;
2620 gchar field_buffer[XLFD_MAX_FIELD_LEN];
2623 guint16 *pixel_sizes, *point_sizes, *tmp_sizes;
2625 fontsel_info = g_new (GtkFontSelInfo, 1);
2627 /* Get a maximum of MAX_FONTS fontnames from the X server.
2628 Use "-*" as the pattern rather than "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" since
2629 the latter may result in fonts being returned which don't actually exist.
2630 xlsfonts also uses "*" so I think it's OK. "-*" gets rid of aliases. */
2631 xfontnames = XListFonts (GDK_DISPLAY(), "-*", MAX_FONTS, &num_fonts);
2632 /* Output a warning if we actually get MAX_FONTS fonts. */
2633 if (num_fonts == MAX_FONTS)
2634 g_warning(_("MAX_FONTS exceeded. Some fonts may be missing."));
2636 /* The maximum size of all these tables is the number of font names
2637 returned. We realloc them later when we know exactly how many
2638 unique entries there are. */
2639 fontsel_info->font_info = g_new (FontInfo, num_fonts);
2640 fontsel_info->font_styles = g_new (FontStyle, num_fonts);
2641 fontsel_info->pixel_sizes = g_new (guint16, num_fonts);
2642 fontsel_info->point_sizes = g_new (guint16, num_fonts);
2644 fontnames = g_new (GSList*, num_fonts);
2646 /* Create the initial arrays for the property value strings, though they
2647 may be realloc'ed later. Put the wildcard '*' in the first elements. */
2648 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2650 fontsel_info->properties[prop] = g_new(gchar*, PROPERTY_ARRAY_INCREMENT);
2651 fontsel_info->space_allocated[prop] = PROPERTY_ARRAY_INCREMENT;
2652 fontsel_info->nproperties[prop] = 1;
2653 fontsel_info->properties[prop][0] = "*";
2657 /* Insert the font families into the main table, sorted by family and
2658 foundry (fonts with different foundries are placed in seaparate FontInfos.
2659 All fontnames in each family + foundry are placed into the fontnames
2661 fontsel_info->nfonts = 0;
2662 for (i = 0; i < num_fonts; i++)
2664 #ifdef FONTSEL_DEBUG
2665 g_message("%s\n", xfontnames[i]);
2667 if (gtk_font_selection_is_xlfd_font_name (xfontnames[i]))
2668 gtk_font_selection_insert_font (fontnames, &fontsel_info->nfonts, xfontnames[i]);
2671 #ifdef FONTSEL_DEBUG
2672 g_warning("Skipping invalid font: %s", xfontnames[i]);
2678 /* Since many font names will be in the same FontInfo not all of the
2679 allocated FontInfo table will be used, so we will now reallocate it
2680 with the real size. */
2681 fontsel_info->font_info = g_realloc(fontsel_info->font_info,
2682 sizeof(FontInfo) * fontsel_info->nfonts);
2685 /* Now we work out which choices of weight/slant etc. are valid for each
2687 fontsel_info->nstyles = 0;
2688 current_style = fontsel_info->font_styles;
2689 for (i = 0; i < fontsel_info->nfonts; i++)
2691 font = &fontsel_info->font_info[i];
2693 /* Use the next free position in the styles array. */
2694 font->style_index = fontsel_info->nstyles;
2696 /* Now step through each of the fontnames with this family, and create
2697 a style for each fontname. Each style contains the index into the
2698 weights/slants etc. arrays, and a number of pixel/point sizes. */
2700 temp_list = fontnames[i];
2703 fontname = temp_list->data;
2704 temp_list = temp_list->next;
2706 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2708 current_style->properties[prop]
2709 = gtk_font_selection_insert_field (fontname, prop);
2711 current_style->pixel_sizes_index = npixel_sizes;
2712 current_style->npixel_sizes = 0;
2713 current_style->point_sizes_index = npoint_sizes;
2714 current_style->npoint_sizes = 0;
2715 current_style->flags = 0;
2718 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_PIXELS,
2720 pixels = atoi(field);
2722 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_POINTS,
2724 points = atoi(field);
2726 field = gtk_font_selection_get_xlfd_field (fontname,
2729 res_x = atoi(field);
2731 field = gtk_font_selection_get_xlfd_field (fontname,
2734 res_y = atoi(field);
2736 if (pixels == 0 && points == 0)
2738 if (res_x == 0 && res_y == 0)
2739 flags = GTK_FONT_SCALABLE;
2741 flags = GTK_FONT_SCALABLE_BITMAP;
2744 flags = GTK_FONT_BITMAP;
2746 /* Now we check to make sure that the style is unique. If it isn't
2748 prev_style = fontsel_info->font_styles + font->style_index;
2749 matched_style = FALSE;
2750 while (prev_style < current_style)
2752 matched_style = TRUE;
2753 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2755 if (prev_style->properties[prop]
2756 != current_style->properties[prop])
2758 matched_style = FALSE;
2767 /* If we matched an existing style, we need to add the pixels &
2768 point sizes to the style. If not, we insert the pixel & point
2769 sizes into our new style. Note that we don't add sizes for
2773 prev_style->flags |= flags;
2774 if (flags == GTK_FONT_BITMAP)
2776 pixel_sizes = fontsel_info->pixel_sizes
2777 + prev_style->pixel_sizes_index;
2779 for (size = 0; size < prev_style->npixel_sizes; size++)
2781 if (pixels == *pixel_sizes)
2786 else if (pixels < *pixel_sizes)
2790 /* We need to move all the following pixel sizes up, and also
2791 update the indexes of any following styles. */
2794 for (tmp_sizes = fontsel_info->pixel_sizes + npixel_sizes;
2795 tmp_sizes > pixel_sizes; tmp_sizes--)
2796 *tmp_sizes = *(tmp_sizes - 1);
2798 *pixel_sizes = pixels;
2800 prev_style->npixel_sizes++;
2802 tmp_style = prev_style + 1;
2803 while (tmp_style < current_style)
2805 tmp_style->pixel_sizes_index++;
2810 point_sizes = fontsel_info->point_sizes
2811 + prev_style->point_sizes_index;
2813 for (size = 0; size < prev_style->npoint_sizes; size++)
2815 if (points == *point_sizes)
2820 else if (points < *point_sizes)
2824 /* We need to move all the following point sizes up, and also
2825 update the indexes of any following styles. */
2828 for (tmp_sizes = fontsel_info->point_sizes + npoint_sizes;
2829 tmp_sizes > point_sizes; tmp_sizes--)
2830 *tmp_sizes = *(tmp_sizes - 1);
2832 *point_sizes = points;
2834 prev_style->npoint_sizes++;
2836 tmp_style = prev_style + 1;
2837 while (tmp_style < current_style)
2839 tmp_style->point_sizes_index++;
2847 current_style->flags = flags;
2848 if (flags == GTK_FONT_BITMAP)
2850 fontsel_info->pixel_sizes[npixel_sizes++] = pixels;
2851 current_style->npixel_sizes = 1;
2852 fontsel_info->point_sizes[npoint_sizes++] = points;
2853 current_style->npoint_sizes = 1;
2856 fontsel_info->nstyles++;
2860 g_slist_free(fontnames[i]);
2862 /* Set nstyles to the real value, minus duplicated fontnames.
2863 Note that we aren't using all the allocated memory if fontnames are
2865 font->nstyles = style;
2868 /* Since some repeated styles may be skipped we won't have used all the
2869 allocated space, so we will now reallocate it with the real size. */
2870 fontsel_info->font_styles = g_realloc(fontsel_info->font_styles,
2871 sizeof(FontStyle) * fontsel_info->nstyles);
2872 fontsel_info->pixel_sizes = g_realloc(fontsel_info->pixel_sizes,
2873 sizeof(guint16) * npixel_sizes);
2874 fontsel_info->point_sizes = g_realloc(fontsel_info->point_sizes,
2875 sizeof(guint16) * npoint_sizes);
2877 XFreeFontNames (xfontnames);
2880 /* Debugging Output */
2881 /* This outputs all FontInfos. */
2882 #ifdef FONTSEL_DEBUG
2883 g_message("\n\n Font Family Weight Slant Set Width Spacing Charset\n\n");
2884 for (i = 0; i < fontsel_info->nfonts; i++)
2886 FontInfo *font = &fontsel_info->font_info[i];
2887 FontStyle *styles = fontsel_info->font_styles + font->style_index;
2888 for (style = 0; style < font->nstyles; style++)
2890 g_message("%5i %-16.16s ", i, font->family);
2891 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2892 g_message("%-9.9s ",
2893 fontsel_info->properties[prop][styles->properties[prop]]);
2896 if (styles->flags & GTK_FONT_BITMAP)
2897 g_message("Bitmapped font ");
2898 if (styles->flags & GTK_FONT_SCALABLE)
2899 g_message("Scalable font ");
2900 if (styles->flags & GTK_FONT_SCALABLE_BITMAP)
2901 g_message("Scalable-Bitmapped font ");
2904 if (styles->npixel_sizes)
2906 g_message(" Pixel sizes: ");
2907 tmp_sizes = fontsel_info->pixel_sizes + styles->pixel_sizes_index;
2908 for (size = 0; size < styles->npixel_sizes; size++)
2909 g_message("%i ", *tmp_sizes++);
2913 if (styles->npoint_sizes)
2915 g_message(" Point sizes: ");
2916 tmp_sizes = fontsel_info->point_sizes + styles->point_sizes_index;
2917 for (size = 0; size < styles->npoint_sizes; size++)
2918 g_message("%i ", *tmp_sizes++);
2926 /* This outputs all available properties. */
2927 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2929 g_message("Property: %s\n", xlfd_field_names[xlfd_index[prop]]);
2930 for (i = 0; i < fontsel_info->nproperties[prop]; i++)
2931 g_message(" %s\n", fontsel_info->properties[prop][i]);
2936 /* This inserts the given fontname into the FontInfo table.
2937 If a FontInfo already exists with the same family and foundry, then the
2938 fontname is added to the FontInfos list of fontnames, else a new FontInfo
2939 is created and inserted in alphabetical order in the table. */
2941 gtk_font_selection_insert_font (GSList *fontnames[],
2947 GSList *temp_fontname;
2949 gboolean family_exists = FALSE;
2953 gchar family_buffer[XLFD_MAX_FIELD_LEN];
2955 table = fontsel_info->font_info;
2957 /* insert a fontname into a table */
2958 family = gtk_font_selection_get_xlfd_field (fontname, XLFD_FAMILY,
2963 foundry = gtk_font_selection_insert_field (fontname, FOUNDRY);
2968 /* Do a binary search to determine if we have already encountered
2969 * a font with this family & foundry. */
2971 while (lower < upper)
2973 middle = (lower + upper) >> 1;
2975 cmp = strcmp (family, table[middle].family);
2976 /* If the family matches we sort by the foundry. */
2979 family_exists = TRUE;
2980 family = table[middle].family;
2981 cmp = strcmp(fontsel_info->properties[FOUNDRY][foundry],
2982 fontsel_info->properties[FOUNDRY][table[middle].foundry]);
2987 fontnames[middle] = g_slist_prepend (fontnames[middle],
2998 /* Add another entry to the table for this new font family */
2999 temp_info.family = family_exists ? family : g_strdup(family);
3000 temp_info.foundry = foundry;
3001 temp_fontname = g_slist_prepend (NULL, fontname);
3005 /* Quickly insert the entry into the table in sorted order
3006 * using a modification of insertion sort and the knowledge
3007 * that the entries proper position in the table was determined
3008 * above in the binary search and is contained in the "lower"
3012 upper = *ntable - 1;
3013 while (lower != upper)
3015 table[upper] = table[upper-1];
3016 fontnames[upper] = fontnames[upper-1];
3020 table[lower] = temp_info;
3021 fontnames[lower] = temp_fontname;
3025 /* This checks that the specified field of the given fontname is in the
3026 appropriate properties array. If not it is added. Thus eventually we get
3027 arrays of all possible weights/slants etc. It returns the array index. */
3029 gtk_font_selection_insert_field (gchar *fontname,
3032 gchar field_buffer[XLFD_MAX_FIELD_LEN];
3036 field = gtk_font_selection_get_xlfd_field (fontname, xlfd_index[prop],
3041 /* If the field is already in the array just return its index. */
3042 for (index = 0; index < fontsel_info->nproperties[prop]; index++)
3043 if (!strcmp(field, fontsel_info->properties[prop][index]))
3046 /* Make sure we have enough space to add the field. */
3047 if (fontsel_info->nproperties[prop] == fontsel_info->space_allocated[prop])
3049 fontsel_info->space_allocated[prop] += PROPERTY_ARRAY_INCREMENT;
3050 fontsel_info->properties[prop] = g_realloc(fontsel_info->properties[prop],
3052 * fontsel_info->space_allocated[prop]);
3055 /* Add the new field. */
3056 index = fontsel_info->nproperties[prop];
3057 fontsel_info->properties[prop][index] = g_strdup(field);
3058 fontsel_info->nproperties[prop]++;
3063 /*****************************************************************************
3064 * These functions are the main public interface for getting/setting the font.
3065 *****************************************************************************/
3068 gtk_font_selection_get_font (GtkFontSelection *fontsel)
3070 g_return_val_if_fail (fontsel != NULL, NULL);
3071 return fontsel->font;
3076 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
3079 gchar *family_str, *foundry_str;
3080 gchar *property_str[GTK_NUM_STYLE_PROPERTIES];
3083 g_return_val_if_fail (fontsel != NULL, NULL);
3084 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
3086 /* If no family has been selected return NULL. */
3087 if (fontsel->font_index == -1)
3090 font = &fontsel_info->font_info[fontsel->font_index];
3091 family_str = font->family;
3092 foundry_str = fontsel_info->properties[FOUNDRY][font->foundry];
3094 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
3097 = fontsel_info->properties[prop][fontsel->property_values[prop]];
3098 if (strcmp (property_str[prop], "(nil)") == 0)
3099 property_str[prop] = "";
3102 return gtk_font_selection_create_xlfd (fontsel->size,
3106 property_str[WEIGHT],
3107 property_str[SLANT],
3108 property_str[SET_WIDTH],
3109 property_str[SPACING],
3110 property_str[CHARSET]);
3114 /* This sets the current font, selecting the appropriate clist rows.
3115 First we check the fontname is valid and try to find the font family
3116 - i.e. the name in the main list. If we can't find that, then just return.
3117 Next we try to set each of the properties according to the fontname.
3118 Finally we select the font family & style in the clists. */
3120 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
3121 const gchar *fontname)
3123 gchar *family, *field;
3124 gint index, prop, size;
3125 guint16 foundry, value;
3126 gchar family_buffer[XLFD_MAX_FIELD_LEN];
3127 gchar field_buffer[XLFD_MAX_FIELD_LEN];
3130 g_return_val_if_fail (fontsel != NULL, FALSE);
3131 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
3132 g_return_val_if_fail (fontname != NULL, FALSE);
3134 /* Check it is a valid fontname. */
3135 if (!gtk_font_selection_is_xlfd_font_name(fontname))
3138 family = gtk_font_selection_get_xlfd_field (fontname, XLFD_FAMILY,
3143 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_FOUNDRY,
3145 foundry = gtk_font_selection_field_to_index (fontsel_info->properties[FOUNDRY],
3146 fontsel_info->nproperties[FOUNDRY],
3149 index = gtk_font_selection_find_font(fontsel, family, foundry);
3153 /* Convert the property fields into indices and set them. */
3154 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
3156 field = gtk_font_selection_get_xlfd_field (fontname, xlfd_index[prop],
3158 value = gtk_font_selection_field_to_index (fontsel_info->properties[prop],
3159 fontsel_info->nproperties[prop],
3161 fontsel->property_values[prop] = value;
3164 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_POINTS,
3171 fontsel->size = fontsel->selected_size = size;
3172 fontsel->metric = GTK_FONT_METRIC_POINTS;
3173 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fontsel->points_button),
3176 sprintf (buffer, "%i", size / 10);
3178 sprintf (buffer, "%i.%i", size / 10, size % 10);
3182 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_PIXELS,
3187 fontsel->size = fontsel->selected_size = size;
3188 fontsel->metric = GTK_FONT_METRIC_PIXELS;
3189 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fontsel->pixels_button),
3191 sprintf (buffer, "%i", size);
3193 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
3195 /* Clear any current filter. */
3196 gtk_font_selection_clear_filter(fontsel);
3198 /* Now find the best style match. */
3199 fontsel->font_index = index;
3200 gtk_clist_select_row(GTK_CLIST(fontsel->font_clist), index, 0);
3201 if (GTK_WIDGET_MAPPED (fontsel->font_clist))
3202 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), index, -1, 0.5, 0);
3204 gtk_font_selection_show_available_styles (fontsel);
3205 /* This will load the font. */
3206 gtk_font_selection_select_best_style (fontsel, FALSE);
3212 /* Returns the index of the given family, or -1 if not found */
3214 gtk_font_selection_find_font (GtkFontSelection *fontsel,
3218 FontInfo *font_info;
3219 gint lower, upper, middle = -1, cmp, nfonts;
3220 gint found_family = -1;
3222 font_info = fontsel_info->font_info;
3223 nfonts = fontsel_info->nfonts;
3227 /* Do a binary search to find the font family. */
3230 while (lower < upper)
3232 middle = (lower + upper) >> 1;
3234 cmp = strcmp (family, font_info[middle].family);
3237 found_family = middle;
3238 cmp = strcmp(fontsel_info->properties[FOUNDRY][foundry],
3239 fontsel_info->properties[FOUNDRY][font_info[middle].foundry]);
3250 /* We couldn't find the family and foundry, but we may have just found the
3251 family, so we return that. */
3252 return found_family;
3256 /* This returns the text in the preview entry. You should copy the returned
3257 text if you need it. */
3259 gtk_font_selection_get_preview_text (GtkFontSelection *fontsel)
3261 return gtk_entry_get_text(GTK_ENTRY(fontsel->preview_entry));
3265 /* This sets the text in the preview entry. */
3267 gtk_font_selection_set_preview_text (GtkFontSelection *fontsel,
3270 gtk_entry_set_text(GTK_ENTRY(fontsel->preview_entry), text);
3274 /*****************************************************************************
3275 * These functions all deal with X Logical Font Description (XLFD) fontnames.
3276 * See the freely available documentation about this.
3277 *****************************************************************************/
3280 * Returns TRUE if the fontname is a valid XLFD.
3281 * (It just checks if the number of dashes is 14, and that each
3282 * field < XLFD_MAX_FIELD_LEN characters long - that's not in the XLFD but it
3283 * makes it easier for me).
3286 gtk_font_selection_is_xlfd_font_name (const gchar *fontname)
3293 if (*fontname++ == '-')
3295 if (field_len > XLFD_MAX_FIELD_LEN) return FALSE;
3303 return (i == 14) ? TRUE : FALSE;
3307 * This fills the buffer with the specified field from the X Logical Font
3308 * Description name, and returns it. If fontname is NULL or the field is
3309 * longer than XFLD_MAX_FIELD_LEN it returns NULL.
3310 * Note: For the charset field, we also return the encoding, e.g. 'iso8859-1'.
3313 gtk_font_selection_get_xlfd_field (const gchar *fontname,
3314 FontField field_num,
3317 const gchar *t1, *t2;
3318 gint countdown, len, num_dashes;
3323 /* we assume this is a valid fontname...that is, it has 14 fields */
3325 countdown = field_num;
3327 while (*t1 && (countdown >= 0))
3331 num_dashes = (field_num == XLFD_CHARSET) ? 2 : 1;
3332 for (t2 = t1; *t2; t2++)
3334 if (*t2 == '-' && --num_dashes == 0)
3340 /* Check we don't overflow the buffer */
3341 len = (long) t2 - (long) t1;
3342 if (len > XLFD_MAX_FIELD_LEN - 1)
3344 strncpy (buffer, t1, len);
3347 /* Convert to lower case. */
3351 strcpy(buffer, "(nil)");
3357 * This returns a X Logical Font Description font name, given all the pieces.
3358 * Note: this retval must be freed by the caller.
3361 gtk_font_selection_create_xlfd (gint size,
3362 GtkFontMetricType metric,
3372 gchar *pixel_size = "*", *point_size = "*", *fontname;
3378 sprintf (buffer, "%d", (int) size);
3379 if (metric == GTK_FONT_METRIC_PIXELS)
3380 pixel_size = buffer;
3382 point_size = buffer;
3384 /* Note: be careful here - don't overrun the allocated memory. */
3385 length = strlen(foundry) + strlen(family) + strlen(weight) + strlen(slant)
3386 + strlen(set_width) + strlen(pixel_size) + strlen(point_size)
3387 + strlen(spacing) + strlen(charset)
3388 + 1 + 1 + 1 + 1 + 1 + 3 + 1 + 5 + 3
3389 + 1 /* for the terminating '\0'. */;
3391 fontname = g_new(gchar, length);
3392 /* **NOTE**: If you change this string please change length above! */
3393 sprintf(fontname, "-%s-%s-%s-%s-%s-*-%s-%s-*-*-%s-*-%s",
3394 foundry, family, weight, slant, set_width, pixel_size,
3395 point_size, spacing, charset);
3401 /*****************************************************************************
3402 * GtkFontSelectionDialog
3403 *****************************************************************************/
3406 gtk_font_selection_dialog_get_type (void)
3408 static guint font_selection_dialog_type = 0;
3410 if (!font_selection_dialog_type)
3412 GtkTypeInfo fontsel_diag_info =
3414 "GtkFontSelectionDialog",
3415 sizeof (GtkFontSelectionDialog),
3416 sizeof (GtkFontSelectionDialogClass),
3417 (GtkClassInitFunc) gtk_font_selection_dialog_class_init,
3418 (GtkObjectInitFunc) gtk_font_selection_dialog_init,
3419 /* reserved_1 */ NULL,
3420 /* reserved_2 */ NULL,
3421 (GtkClassInitFunc) NULL,
3424 font_selection_dialog_type = gtk_type_unique (GTK_TYPE_WINDOW, &fontsel_diag_info);
3427 return font_selection_dialog_type;
3431 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
3433 GtkObjectClass *object_class;
3435 object_class = (GtkObjectClass*) klass;
3437 font_selection_dialog_parent_class = gtk_type_class (GTK_TYPE_WINDOW);
3441 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
3443 fontseldiag->dialog_width = -1;
3444 fontseldiag->auto_resize = TRUE;
3446 gtk_widget_set_events(GTK_WIDGET(fontseldiag), GDK_STRUCTURE_MASK);
3447 gtk_signal_connect (GTK_OBJECT (fontseldiag), "configure_event",
3448 (GtkSignalFunc) gtk_font_selection_dialog_on_configure,
3451 gtk_container_set_border_width (GTK_CONTAINER (fontseldiag), 4);
3452 gtk_window_set_policy(GTK_WINDOW(fontseldiag), FALSE, TRUE, TRUE);
3454 fontseldiag->main_vbox = gtk_vbox_new (FALSE, 4);
3455 gtk_widget_show (fontseldiag->main_vbox);
3456 gtk_container_add (GTK_CONTAINER (fontseldiag), fontseldiag->main_vbox);
3458 fontseldiag->fontsel = gtk_font_selection_new();
3459 gtk_widget_show (fontseldiag->fontsel);
3460 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
3461 fontseldiag->fontsel, TRUE, TRUE, 0);
3463 /* Create the action area */
3464 fontseldiag->action_area = gtk_hbutton_box_new ();
3465 gtk_button_box_set_layout(GTK_BUTTON_BOX(fontseldiag->action_area),
3467 gtk_button_box_set_spacing(GTK_BUTTON_BOX(fontseldiag->action_area), 5);
3468 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
3469 fontseldiag->action_area, FALSE, FALSE, 0);
3470 gtk_widget_show (fontseldiag->action_area);
3472 fontseldiag->ok_button = gtk_button_new_with_label(_("OK"));
3473 GTK_WIDGET_SET_FLAGS (fontseldiag->ok_button, GTK_CAN_DEFAULT);
3474 gtk_widget_show(fontseldiag->ok_button);
3475 gtk_box_pack_start (GTK_BOX (fontseldiag->action_area),
3476 fontseldiag->ok_button, TRUE, TRUE, 0);
3477 gtk_widget_grab_default (fontseldiag->ok_button);
3479 fontseldiag->apply_button = gtk_button_new_with_label(_("Apply"));
3480 GTK_WIDGET_SET_FLAGS (fontseldiag->apply_button, GTK_CAN_DEFAULT);
3481 /*gtk_widget_show(fontseldiag->apply_button);*/
3482 gtk_box_pack_start (GTK_BOX(fontseldiag->action_area),
3483 fontseldiag->apply_button, TRUE, TRUE, 0);
3485 fontseldiag->cancel_button = gtk_button_new_with_label(_("Cancel"));
3486 GTK_WIDGET_SET_FLAGS (fontseldiag->cancel_button, GTK_CAN_DEFAULT);
3487 gtk_widget_show(fontseldiag->cancel_button);
3488 gtk_box_pack_start (GTK_BOX(fontseldiag->action_area),
3489 fontseldiag->cancel_button, TRUE, TRUE, 0);
3495 gtk_font_selection_dialog_new (const gchar *title)
3497 GtkFontSelectionDialog *fontseldiag;
3499 fontseldiag = gtk_type_new (GTK_TYPE_FONT_SELECTION_DIALOG);
3500 gtk_window_set_title (GTK_WINDOW (fontseldiag),
3501 title ? title : _("Font Selection"));
3503 return GTK_WIDGET (fontseldiag);
3507 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
3509 return gtk_font_selection_get_font_name(GTK_FONT_SELECTION(fsd->fontsel));
3513 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
3515 return gtk_font_selection_get_font(GTK_FONT_SELECTION(fsd->fontsel));
3519 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
3520 const gchar *fontname)
3522 return gtk_font_selection_set_font_name(GTK_FONT_SELECTION(fsd->fontsel),
3527 gtk_font_selection_dialog_set_filter (GtkFontSelectionDialog *fsd,
3528 GtkFontFilterType filter_type,
3529 GtkFontType font_type,
3537 gtk_font_selection_set_filter (GTK_FONT_SELECTION (fsd->fontsel),
3538 filter_type, font_type,
3539 foundries, weights, slants, setwidths,
3540 spacings, charsets);
3544 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
3546 return gtk_font_selection_get_preview_text(GTK_FONT_SELECTION(fsd->fontsel));
3550 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
3553 gtk_font_selection_set_preview_text(GTK_FONT_SELECTION(fsd->fontsel), text);
3557 /* This turns auto-shrink off if the user resizes the width of the dialog.
3558 It also turns it back on again if the user resizes it back to its normal
3561 gtk_font_selection_dialog_on_configure (GtkWidget *widget,
3562 GdkEventConfigure *event,
3563 GtkFontSelectionDialog *fsd)
3565 /* This sets the initial width. */
3566 if (fsd->dialog_width == -1)
3567 fsd->dialog_width = event->width;
3568 else if (fsd->auto_resize && fsd->dialog_width != event->width)
3570 fsd->auto_resize = FALSE;
3571 gtk_window_set_policy(GTK_WINDOW(fsd), FALSE, TRUE, FALSE);
3573 else if (!fsd->auto_resize && fsd->dialog_width == event->width)
3575 fsd->auto_resize = TRUE;
3576 gtk_window_set_policy(GTK_WINDOW(fsd), FALSE, TRUE, TRUE);