1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * GtkFontSelection widget for Gtk+, by Damon Chaplin, May 1998.
5 * Based on the GnomeFontSelector widget, by Elliot Lee, but major changes.
6 * The GnomeFontSelector was derived from app/text_tool.c in the GIMP.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
27 * Fontnames - A maximum of MAX_FONTS (32767) fontnames will be retrieved
28 * from X Windows with XListFonts(). Any more are ignored.
29 * I think this limit may have been set because of a limit in
30 * GtkList. It could possibly be increased since we are using
31 * GtkClists now, but I'd be surprised if it was reached.
32 * Field length - XLFD_MAX_FIELD_LEN is the maximum length that any field of a
33 * fontname can be for it to be considered valid. Others are
35 * Properties - Maximum of 65535 choices for each font property - guint16's
36 * are used as indices, e.g. in the FontInfo struct.
37 * Combinations - Maximum of 65535 combinations of properties for each font
38 * family - a guint16 is used in the FontInfo struct.
39 * Font size - Minimum font size of 2 pixels/points, since trying to load
40 * some fonts with a size of 1 can cause X to hang.
41 * (e.g. the Misc Fixed fonts).
45 * Possible Improvements:
47 * Font Styles - could sort the styles into a reasonable order - regular
48 * first, then bold, bold italic etc. Could also try to keep
49 * a similar style as the user selects different fonts.
51 * I18N - the default preview text is not useful for international
52 * fonts. Maybe the first few characters of the font could be
54 * - fontsets? should these be handled by the font dialog?
58 * Debugging: compile with -DFONTSEL_DEBUG for lots of debugging output.
69 #include "gdk/gdkkeysyms.h"
71 #include "gtkbutton.h"
74 #include "gtkfontsel.h"
79 #include "gtknotebook.h"
80 #include "gtkradiobutton.h"
81 #include "gtksignal.h"
85 /* The maximum number of fontnames requested with XListFonts(). */
86 #define MAX_FONTS 32767
88 /* This is the largest field length we will accept. If a fontname has a field
89 larger than this we will skip it. */
90 #define XLFD_MAX_FIELD_LEN 64
92 /* These are what we use as the standard font sizes, for the size clist.
93 Note that when using points we still show these integer point values but
94 we work internally in decipoints (and decipoint values can be typed in). */
95 static guint16 font_sizes[] = {
96 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28,
97 32, 36, 40, 48, 56, 64, 72
100 /* Initial font metric & size (Remember point sizes are in decipoints).
101 The font size should match one of those in the font_sizes array. */
102 #define INITIAL_METRIC POINTS_METRIC
103 #define INITIAL_FONT_SIZE 140
105 /* This is the default text shown in the preview entry, though the user
106 can set it. Remember that some fonts only have capital letters. */
107 #define PREVIEW_TEXT "abcdefghijk ABCDEFGHIJK"
109 /* This is the initial and maximum height of the preview entry (it expands
110 when large font sizes are selected). Initial height is also the minimum. */
111 #define INITIAL_PREVIEW_HEIGHT 44
112 #define MAX_PREVIEW_HEIGHT 300
114 /* These are the sizes of the font, style & size clists. */
115 #define FONT_LIST_HEIGHT 136
116 #define FONT_LIST_WIDTH 180
117 #define FONT_STYLE_LIST_WIDTH 160
118 #define FONT_SIZE_LIST_WIDTH 60
120 /* This is the number of fields in an X Logical Font Description font name.
121 Note that we count the registry & encoding as 1. */
122 #define GTK_XLFD_NUM_FIELDS 13
124 /* Used for the flags field in FontStyle. Note that they can be combined,
125 e.g. a style can have multiple bitmaps and a true scalable version.
126 The displayed flag is used when displaying styles to remember which
127 styles have already been displayed. */
130 BITMAP_FONT = 1 << 0,
131 SCALABLE_FONT = 1 << 1,
132 SCALABLE_BITMAP_FONT = 1 << 2,
136 typedef struct _GtkFontSelInfo GtkFontSelInfo;
137 typedef struct _FontInfo FontInfo;
138 typedef struct _FontStyle FontStyle;
140 /* This struct represents one family of fonts (with one foundry), e.g. adobe
141 courier or sony fixed. It stores the family name, the index of the foundry
142 name, and the index of and number of available styles. */
150 /* This represents one style, as displayed in the Font Style clist. It can
151 have a number of available pixel sizes and point sizes. The indexes point
152 into the two big fontsel_info->pixel_sizes & fontsel_info->point_sizes arrays. */
155 guint16 properties[GTK_NUM_STYLE_PROPERTIES];
156 gint pixel_sizes_index;
157 guint16 npixel_sizes;
158 gint point_sizes_index;
159 guint16 npoint_sizes;
163 struct _GtkFontSelInfo {
165 /* This is a table with each FontInfo representing one font family+foundry */
169 /* This stores all the valid combinations of properties for every family.
170 Each FontInfo holds an index into its own space in this one big array. */
171 FontStyle *font_styles;
174 /* This stores all the font sizes available for every style.
175 Each style holds an index into these arrays. */
176 guint16 *pixel_sizes;
177 guint16 *point_sizes;
179 /* These are the arrays of strings of all possible weights, slants,
180 set widths, spacings, charsets & foundries, and the amount of space
181 allocated for each array. */
182 gchar **properties[GTK_NUM_FONT_PROPERTIES];
183 guint16 nproperties[GTK_NUM_FONT_PROPERTIES];
184 guint16 space_allocated[GTK_NUM_FONT_PROPERTIES];
186 /* Whether any scalable bitmap fonts are available. If not, the 'Allow
187 scaled bitmap fonts' toggle button is made insensitive. */
188 gboolean scaled_bitmaps_available;
191 /* These are the field numbers in the X Logical Font Description fontnames,
192 e.g. -adobe-courier-bold-o-normal--25-180-100-100-m-150-iso8859-1 */
203 XLFD_RESOLUTION_X = 8,
204 XLFD_RESOLUTION_Y = 9,
206 XLFD_AVERAGE_WIDTH = 11,
210 /* These are the names of the fields, used on the info & filter page. */
211 static gchar* xlfd_field_names[GTK_XLFD_NUM_FIELDS] = {
227 /* These are the array indices of the font properties used in several arrays,
228 and should match the xlfd_index array below. */
239 /* This is used to look up a field in a fontname given one of the above
241 static FontField xlfd_index[GTK_NUM_FONT_PROPERTIES] = {
250 /* These are the positions of the properties in the filter table - x, y. */
251 static gint filter_positions[GTK_NUM_FONT_PROPERTIES][2] = {
252 { 1, 0 }, { 0, 2 }, { 1, 2 }, { 2, 2 }, { 2, 0 }, { 0, 0 }
254 static gint filter_heights[GTK_NUM_FONT_PROPERTIES] = {
255 100, 80, 80, 50, 100, 100
258 static GtkFontSelInfo *fontsel_info = NULL;
260 /* The initial size and increment of each of the arrays of property values. */
261 #define PROPERTY_ARRAY_INCREMENT 16
263 static void gtk_font_selection_class_init (GtkFontSelectionClass *klass);
264 static void gtk_font_selection_init (GtkFontSelection *fontsel);
265 static void gtk_font_selection_destroy (GtkObject *object);
267 /* These are all used for class initialization - loading in the fonts etc. */
268 static void gtk_font_selection_get_fonts (void);
269 static void gtk_font_selection_insert_font (GSList *fontnames[],
272 static gint gtk_font_selection_insert_field (gchar *fontname,
275 /* These are the callbacks & related functions. */
276 static void gtk_font_selection_select_font (GtkWidget *w,
279 GdkEventButton *bevent,
281 static gint gtk_font_selection_on_clist_key_press (GtkWidget *clist,
283 GtkFontSelection *fs);
284 static gboolean gtk_font_selection_select_next (GtkFontSelection *fs,
287 static void gtk_font_selection_show_available_styles
288 (GtkFontSelection *fs);
289 static void gtk_font_selection_select_best_style (GtkFontSelection *fs,
291 static gint gtk_font_selection_get_best_match (GtkFontSelection *fs);
293 static void gtk_font_selection_select_style (GtkWidget *w,
296 GdkEventButton *bevent,
298 static void gtk_font_selection_show_available_sizes
299 (GtkFontSelection *fs);
300 static gint gtk_font_selection_size_key_press (GtkWidget *w,
303 static void gtk_font_selection_select_best_size (GtkFontSelection *fs);
304 static void gtk_font_selection_select_size (GtkWidget *w,
307 GdkEventButton *bevent,
310 static void gtk_font_selection_metric_callback (GtkWidget *w,
312 static void gtk_font_selection_expose_list (GtkWidget *w,
313 GdkEventExpose *event,
316 static void gtk_font_selection_switch_page (GtkWidget *w,
317 GtkNotebookPage *page,
320 static void gtk_font_selection_show_font_info (GtkFontSelection *fs);
322 static void gtk_font_selection_select_filter (GtkWidget *w,
325 GdkEventButton *bevent,
327 static void gtk_font_selection_unselect_filter (GtkWidget *w,
330 GdkEventButton *bevent,
332 static void gtk_font_selection_filter_fonts (GtkFontSelection *fs);
333 static gboolean gtk_font_selection_style_visible (GtkFontSelection *fs,
336 static void gtk_font_selection_reset_filter (GtkWidget *w,
338 static void gtk_font_selection_on_clear_filter (GtkWidget *w,
340 static void gtk_font_selection_apply_filter (GtkFontSelection *fs);
341 static void gtk_font_selection_clear_filter (GtkFontSelection *fs);
342 static void gtk_font_selection_toggle_scaled_bitmaps
346 /* Misc. utility functions. */
347 static void gtk_font_selection_insert_fonts (GtkFontSelection *fs);
348 static gboolean gtk_font_selection_load_font (GtkFontSelection *fs);
349 static void gtk_font_selection_update_preview (GtkFontSelection *fs);
351 static gint gtk_font_selection_find_font (GtkFontSelection *fs,
354 static guint16 gtk_font_selection_field_to_index (gchar **table,
358 static gchar* gtk_font_selection_expand_slant_code (gchar *slant);
359 static gchar* gtk_font_selection_expand_spacing_code(gchar *spacing);
361 /* Functions for handling X Logical Font Description fontnames. */
362 static gboolean gtk_font_selection_is_xlfd_font_name (const gchar *fontname);
363 static char* gtk_font_selection_get_xlfd_field (const gchar *fontname,
366 static gchar * gtk_font_selection_create_xlfd (gint size,
367 GtkFontMetricType metric,
377 /* FontSelectionDialog */
378 static void gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass);
379 static void gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag);
381 static gint gtk_font_selection_dialog_on_configure(GtkWidget *widget,
382 GdkEventConfigure *event,
383 GtkFontSelectionDialog *fsd);
385 static GtkWindowClass *font_selection_parent_class = NULL;
386 static GtkNotebookClass *font_selection_dialog_parent_class = NULL;
389 gtk_font_selection_get_type()
391 static guint font_selection_type = 0;
393 if(!font_selection_type)
395 GtkTypeInfo fontsel_info =
398 sizeof(GtkFontSelection),
399 sizeof(GtkFontSelectionClass),
400 (GtkClassInitFunc) gtk_font_selection_class_init,
401 (GtkObjectInitFunc) gtk_font_selection_init,
402 /* reserved_1 */ NULL,
403 /* reserved_2 */ NULL,
404 (GtkClassInitFunc) NULL,
407 font_selection_type = gtk_type_unique (gtk_notebook_get_type(),
411 return font_selection_type;
415 gtk_font_selection_class_init(GtkFontSelectionClass *klass)
417 GtkObjectClass *object_class;
419 object_class = (GtkObjectClass *) klass;
421 font_selection_parent_class = gtk_type_class (gtk_notebook_get_type ());
423 object_class->destroy = gtk_font_selection_destroy;
425 gtk_font_selection_get_fonts ();
429 gtk_font_selection_init(GtkFontSelection *fontsel)
431 GtkWidget *text_frame;
433 GtkWidget *table, *label, *hbox, *hbox2, *clist, *button, *vbox, *alignment;
435 gchar *titles[] = { "Font Property", "Requested Value", "Actual Value" };
440 gchar *property, *text;
443 /* Initialize the GtkFontSelection struct. We do this here in case any
444 callbacks are triggered while creating the interface. */
445 fontsel->font = NULL;
446 fontsel->font_index = -1;
448 fontsel->metric = INITIAL_METRIC;
449 fontsel->size = INITIAL_FONT_SIZE;
450 fontsel->selected_size = INITIAL_FONT_SIZE;
451 fontsel->scale_bitmapped_fonts = FALSE;
453 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
455 fontsel->property_filters[prop] = NULL;
456 fontsel->property_nfilters[prop] = 0;
459 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
460 fontsel->property_values[prop] = 0;
462 fontsel->scroll_on_expose = TRUE;
464 /* Create the main notebook page. */
465 fontsel->main_vbox = gtk_vbox_new (FALSE, 4);
466 gtk_widget_show (fontsel->main_vbox);
467 gtk_container_border_width (GTK_CONTAINER (fontsel->main_vbox), 6);
468 label = gtk_label_new("Font");
469 gtk_widget_set_usize (label, 120, -1);
470 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
471 fontsel->main_vbox, label);
473 /* Create the table of font, style & size. */
474 table = gtk_table_new (3, 3, FALSE);
475 gtk_widget_show (table);
476 gtk_table_set_col_spacings(GTK_TABLE(table), 8);
477 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), table, TRUE, TRUE, 0);
479 fontsel->font_label = gtk_label_new("Font:");
480 gtk_misc_set_alignment (GTK_MISC (fontsel->font_label), 0.0, 0.5);
481 gtk_widget_show (fontsel->font_label);
482 gtk_table_attach (GTK_TABLE (table), fontsel->font_label, 0, 1, 0, 1,
484 label = gtk_label_new("Font Style:");
485 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
486 gtk_widget_show (label);
487 gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1,
489 label = gtk_label_new("Size:");
490 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
491 gtk_widget_show (label);
492 gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
495 fontsel->font_entry = gtk_entry_new();
496 gtk_entry_set_editable(GTK_ENTRY(fontsel->font_entry), FALSE);
497 gtk_widget_set_usize (fontsel->font_entry, 20, -1);
498 gtk_widget_show (fontsel->font_entry);
499 gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
501 fontsel->font_style_entry = gtk_entry_new();
502 gtk_entry_set_editable(GTK_ENTRY(fontsel->font_style_entry), FALSE);
503 gtk_widget_set_usize (fontsel->font_style_entry, 20, -1);
504 gtk_widget_show (fontsel->font_style_entry);
505 gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
507 fontsel->size_entry = gtk_entry_new();
508 gtk_widget_set_usize (fontsel->size_entry, 20, -1);
509 gtk_widget_show (fontsel->size_entry);
510 gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
512 gtk_signal_connect (GTK_OBJECT (fontsel->size_entry), "key_press_event",
513 (GtkSignalFunc) gtk_font_selection_size_key_press,
516 /* Create the clists */
517 fontsel->font_clist = gtk_clist_new(1);
518 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->font_clist));
519 gtk_clist_set_column_width (GTK_CLIST(fontsel->font_clist), 0, 300);
520 gtk_clist_set_policy(GTK_CLIST(fontsel->font_clist), GTK_POLICY_ALWAYS,
521 GTK_POLICY_AUTOMATIC);
522 gtk_widget_set_usize (fontsel->font_clist, FONT_LIST_WIDTH,
524 gtk_widget_show(fontsel->font_clist);
525 gtk_table_attach (GTK_TABLE (table), fontsel->font_clist, 0, 1, 2, 3,
526 GTK_EXPAND | GTK_FILL,
527 GTK_EXPAND | GTK_FILL, 0, 0);
529 fontsel->font_style_clist = gtk_clist_new(1);
530 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->font_style_clist));
531 gtk_clist_set_column_width (GTK_CLIST(fontsel->font_style_clist), 0, 300);
532 gtk_clist_set_policy(GTK_CLIST(fontsel->font_style_clist), GTK_POLICY_ALWAYS,
533 GTK_POLICY_AUTOMATIC);
534 gtk_widget_set_usize (fontsel->font_style_clist, FONT_STYLE_LIST_WIDTH, -1);
535 gtk_widget_show(fontsel->font_style_clist);
536 gtk_table_attach (GTK_TABLE (table), fontsel->font_style_clist, 1, 2, 2, 3,
537 GTK_EXPAND | GTK_FILL,
538 GTK_EXPAND | GTK_FILL, 0, 0);
540 fontsel->size_clist = gtk_clist_new(1);
541 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->size_clist));
542 gtk_clist_set_policy(GTK_CLIST(fontsel->size_clist), GTK_POLICY_ALWAYS,
543 GTK_POLICY_AUTOMATIC);
544 gtk_widget_set_usize (fontsel->size_clist, FONT_SIZE_LIST_WIDTH, -1);
545 gtk_widget_show(fontsel->size_clist);
546 gtk_table_attach (GTK_TABLE (table), fontsel->size_clist, 2, 3, 2, 3,
547 GTK_FILL, GTK_FILL, 0, 0);
550 /* Insert the fonts. If there exist fonts with the same family but
551 different foundries, then the foundry name is appended in brackets. */
552 gtk_font_selection_insert_fonts(fontsel);
554 gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "select_row",
555 GTK_SIGNAL_FUNC(gtk_font_selection_select_font),
557 GTK_WIDGET_SET_FLAGS (fontsel->font_clist, GTK_CAN_FOCUS);
558 gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "key_press_event",
559 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
561 gtk_signal_connect_after (GTK_OBJECT (fontsel->font_clist), "expose_event",
562 GTK_SIGNAL_FUNC(gtk_font_selection_expose_list),
565 gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist), "select_row",
566 GTK_SIGNAL_FUNC(gtk_font_selection_select_style),
568 GTK_WIDGET_SET_FLAGS (fontsel->font_style_clist, GTK_CAN_FOCUS);
569 gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist),
571 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
574 /* Insert the standard font sizes */
575 gtk_clist_freeze (GTK_CLIST(fontsel->size_clist));
576 size_to_match = INITIAL_FONT_SIZE;
577 if (INITIAL_METRIC == POINTS_METRIC)
578 size_to_match = size_to_match / 10;
579 for (i = 0; i < sizeof(font_sizes) / sizeof(font_sizes[0]); i++)
581 sprintf(buffer, "%i", font_sizes[i]);
583 gtk_clist_append(GTK_CLIST(fontsel->size_clist), &size);
584 if (font_sizes[i] == size_to_match)
586 gtk_clist_select_row(GTK_CLIST(fontsel->size_clist), i, 0);
587 gtk_entry_set_text(GTK_ENTRY(fontsel->size_entry), buffer);
590 gtk_clist_thaw (GTK_CLIST(fontsel->size_clist));
592 gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "select_row",
593 GTK_SIGNAL_FUNC(gtk_font_selection_select_size),
595 GTK_WIDGET_SET_FLAGS (fontsel->size_clist, GTK_CAN_FOCUS);
596 gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "key_press_event",
597 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
601 /* create the Filter, Scale Bitmaps & Metric buttons */
602 hbox = gtk_hbox_new(FALSE, 8);
603 gtk_widget_show (hbox);
604 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), hbox, FALSE, TRUE, 0);
606 fontsel->filter_button = gtk_button_new_with_label(" Clear Filter ");
607 gtk_widget_show(fontsel->filter_button);
608 gtk_box_pack_start (GTK_BOX (hbox), fontsel->filter_button, FALSE, FALSE, 0);
609 gtk_widget_set_sensitive (fontsel->filter_button, FALSE);
610 gtk_signal_connect (GTK_OBJECT (fontsel->filter_button), "clicked",
611 GTK_SIGNAL_FUNC(gtk_font_selection_on_clear_filter),
614 fontsel->scaled_bitmaps_button
615 = gtk_check_button_new_with_label("Allow scaled bitmap fonts");
616 gtk_widget_show(fontsel->scaled_bitmaps_button);
617 gtk_box_pack_start (GTK_BOX (hbox), fontsel->scaled_bitmaps_button,
619 if (!fontsel_info->scaled_bitmaps_available)
620 gtk_widget_set_sensitive (fontsel->scaled_bitmaps_button, FALSE);
621 gtk_signal_connect (GTK_OBJECT (fontsel->scaled_bitmaps_button), "clicked",
622 GTK_SIGNAL_FUNC(gtk_font_selection_toggle_scaled_bitmaps),
626 hbox2 = gtk_hbox_new(FALSE, 0);
627 gtk_widget_show (hbox2);
628 gtk_box_pack_end (GTK_BOX (hbox), hbox2, FALSE, FALSE, 0);
630 label = gtk_label_new("Metric:");
631 gtk_widget_show (label);
632 gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 8);
634 fontsel->points_button = gtk_radio_button_new_with_label(NULL, "Points");
635 gtk_widget_show (fontsel->points_button);
636 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->points_button, FALSE, TRUE, 0);
637 if (INITIAL_METRIC == POINTS_METRIC)
638 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->points_button),
641 fontsel->pixels_button = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(fontsel->points_button), "Pixels");
642 gtk_widget_show (fontsel->pixels_button);
643 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->pixels_button, FALSE, TRUE, 0);
644 if (INITIAL_METRIC == PIXELS_METRIC)
645 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->pixels_button),
648 gtk_signal_connect(GTK_OBJECT(fontsel->points_button), "toggled",
649 (GtkSignalFunc) gtk_font_selection_metric_callback,
651 gtk_signal_connect(GTK_OBJECT(fontsel->pixels_button), "toggled",
652 (GtkSignalFunc) gtk_font_selection_metric_callback,
656 /* create the text entry widget */
657 text_frame = gtk_frame_new ("Preview:");
658 gtk_widget_show (text_frame);
659 gtk_frame_set_shadow_type(GTK_FRAME(text_frame), GTK_SHADOW_ETCHED_IN);
660 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), text_frame,
663 /* This is just used to get a 4-pixel space around the preview entry. */
664 text_box = gtk_hbox_new (FALSE, 0);
665 gtk_widget_show (text_box);
666 gtk_container_add (GTK_CONTAINER (text_frame), text_box);
667 gtk_container_border_width (GTK_CONTAINER (text_box), 4);
669 fontsel->preview_entry = gtk_entry_new ();
670 gtk_widget_show (fontsel->preview_entry);
671 gtk_widget_set_usize (fontsel->preview_entry, -1, INITIAL_PREVIEW_HEIGHT);
672 gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
675 /* Create the message area */
676 fontsel->message_label = gtk_label_new("");
677 gtk_widget_show (fontsel->message_label);
678 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), fontsel->message_label,
682 /* Create the font info page */
683 fontsel->info_vbox = gtk_vbox_new (FALSE, 4);
684 gtk_widget_show (fontsel->info_vbox);
685 gtk_container_border_width (GTK_CONTAINER (fontsel->info_vbox), 2);
686 label = gtk_label_new("Font Information");
687 gtk_widget_set_usize (label, 120, -1);
688 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
689 fontsel->info_vbox, label);
691 fontsel->info_clist = gtk_clist_new_with_titles(3, titles);
692 gtk_widget_set_usize (fontsel->info_clist, 390, 150);
693 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 0, 130);
694 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 1, 130);
695 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 2, 130);
696 gtk_clist_column_titles_passive(GTK_CLIST(fontsel->info_clist));
697 gtk_clist_set_policy(GTK_CLIST(fontsel->info_clist), GTK_POLICY_AUTOMATIC,
698 GTK_POLICY_AUTOMATIC);
699 gtk_widget_show(fontsel->info_clist);
700 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), fontsel->info_clist,
703 /* Insert the property names */
704 gtk_clist_freeze (GTK_CLIST(fontsel->info_clist));
707 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
709 row_text[0] = xlfd_field_names[i];
710 gtk_clist_append(GTK_CLIST(fontsel->info_clist), row_text);
711 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 0, 0, 4);
712 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 1, 0, 4);
713 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 2, 0, 4);
715 gtk_clist_thaw (GTK_CLIST(fontsel->info_clist));
717 label = gtk_label_new("Requested Font Name:");
718 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
719 gtk_widget_show (label);
720 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, TRUE, 0);
722 fontsel->requested_font_name = gtk_entry_new();
723 gtk_entry_set_editable(GTK_ENTRY(fontsel->requested_font_name), FALSE);
724 gtk_widget_show (fontsel->requested_font_name);
725 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox),
726 fontsel->requested_font_name, FALSE, TRUE, 0);
728 label = gtk_label_new("Actual Font Name:");
729 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
730 gtk_widget_show (label);
731 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, TRUE, 0);
733 fontsel->actual_font_name = gtk_entry_new();
734 gtk_entry_set_editable(GTK_ENTRY(fontsel->actual_font_name), FALSE);
735 gtk_widget_show (fontsel->actual_font_name);
736 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox),
737 fontsel->actual_font_name, FALSE, TRUE, 0);
739 sprintf(buffer, "%i fonts available with a total of %i styles.",
740 fontsel_info->nfonts, fontsel_info->nstyles);
741 label = gtk_label_new(buffer);
742 gtk_widget_show (label);
743 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, FALSE, 0);
745 gtk_signal_connect (GTK_OBJECT (fontsel), "switch_page",
746 GTK_SIGNAL_FUNC(gtk_font_selection_switch_page),
750 /* Create the Filter page. */
751 fontsel->filter_vbox = gtk_vbox_new (FALSE, 4);
752 gtk_widget_show (fontsel->filter_vbox);
753 gtk_container_border_width (GTK_CONTAINER (fontsel->filter_vbox), 2);
754 label = gtk_label_new("Filter");
755 gtk_widget_set_usize (label, 120, -1);
756 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
757 fontsel->filter_vbox, label);
759 table = gtk_table_new (4, 3, FALSE);
760 gtk_table_set_col_spacings(GTK_TABLE(table), 2);
761 gtk_widget_show (table);
762 gtk_box_pack_start (GTK_BOX (fontsel->filter_vbox), table, TRUE, TRUE, 0);
764 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
766 gint left = filter_positions[prop][0];
767 gint top = filter_positions[prop][1];
769 label = gtk_label_new(xlfd_field_names[xlfd_index[prop]]);
770 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 1.0);
771 gtk_misc_set_padding (GTK_MISC (label), 0, 2);
772 gtk_widget_show(label);
773 gtk_table_attach (GTK_TABLE (table), label, left, left + 1,
774 top, top + 1, GTK_FILL, GTK_FILL, 0, 0);
776 clist = gtk_clist_new(1);
777 gtk_widget_set_usize (clist, 100, filter_heights[prop]);
778 gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_MULTIPLE);
779 gtk_clist_column_titles_hide(GTK_CLIST(clist));
780 gtk_clist_set_policy(GTK_CLIST(clist), GTK_POLICY_AUTOMATIC,
781 GTK_POLICY_AUTOMATIC);
782 gtk_widget_show(clist);
784 /* For the bottom-right cell we add the 'Clear Filter' button. */
785 if (top == 2 && left == 2)
787 vbox = gtk_vbox_new(FALSE, 0);
788 gtk_widget_show(vbox);
789 gtk_table_attach (GTK_TABLE (table), vbox, left, left + 1,
790 top + 1, top + 2, GTK_FILL, GTK_FILL, 0, 0);
792 gtk_box_pack_start (GTK_BOX (vbox), clist, TRUE, TRUE, 0);
794 alignment = gtk_alignment_new(0.5, 0.0, 0.8, 0.0);
795 gtk_widget_show(alignment);
796 gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, TRUE, 4);
798 button = gtk_button_new_with_label("Clear Filter");
799 gtk_widget_show(button);
800 gtk_container_add(GTK_CONTAINER(alignment), button);
801 gtk_signal_connect (GTK_OBJECT (button), "clicked",
802 GTK_SIGNAL_FUNC(gtk_font_selection_reset_filter),
806 gtk_table_attach (GTK_TABLE (table), clist,
807 left, left + 1, top + 1, top + 2,
808 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
810 gtk_signal_connect (GTK_OBJECT (clist), "select_row",
811 GTK_SIGNAL_FUNC(gtk_font_selection_select_filter),
813 gtk_signal_connect (GTK_OBJECT (clist), "unselect_row",
814 GTK_SIGNAL_FUNC(gtk_font_selection_unselect_filter),
817 /* Insert the property names, expanded, and in sorted order.
818 But we make sure that the wildcard '*' is first. */
819 gtk_clist_freeze (GTK_CLIST(clist));
821 gtk_clist_append(GTK_CLIST(clist), &property);
823 for (i = 1; i < fontsel_info->nproperties[prop]; i++) {
824 property = fontsel_info->properties[prop][i];
826 property = gtk_font_selection_expand_slant_code(property);
827 else if (prop == SPACING)
828 property = gtk_font_selection_expand_spacing_code(property);
831 for (row = 1; row < GTK_CLIST(clist)->rows; row++)
833 gtk_clist_get_text(GTK_CLIST(clist), row, 0, &text);
834 if (strcmp(property, text) < 0)
837 gtk_clist_insert(GTK_CLIST(clist), row, &property);
842 row = gtk_clist_append(GTK_CLIST(clist), &property);
843 gtk_clist_set_row_data(GTK_CLIST(clist), row, GINT_TO_POINTER (i));
845 gtk_clist_select_row(GTK_CLIST(clist), 0, 0);
846 gtk_clist_thaw (GTK_CLIST(clist));
847 fontsel->filter_clists[prop] = clist;
852 gtk_font_selection_new()
854 GtkFontSelection *fontsel;
856 fontsel = gtk_type_new (gtk_font_selection_get_type ());
858 return GTK_WIDGET (fontsel);
862 gtk_font_selection_destroy (GtkObject *object)
864 GtkFontSelection *fontsel;
866 g_return_if_fail (object != NULL);
867 g_return_if_fail (GTK_IS_FONT_SELECTION (object));
869 fontsel = GTK_FONT_SELECTION (object);
871 /* All we have to do is unref the font, if we have one. */
873 gdk_font_unref (fontsel->font);
875 if (GTK_OBJECT_CLASS (font_selection_parent_class)->destroy)
876 (* GTK_OBJECT_CLASS (font_selection_parent_class)->destroy) (object);
880 /* This inserts all the fonts into the family clist. */
882 gtk_font_selection_insert_fonts (GtkFontSelection *fontsel)
884 FontInfo *font_info, *font;
885 gchar font_buffer[XLFD_MAX_FIELD_LEN * 2 + 4];
889 font_info = fontsel_info->font_info;
890 nfonts = fontsel_info->nfonts;
892 gtk_clist_freeze (GTK_CLIST(fontsel->font_clist));
893 gtk_clist_clear (GTK_CLIST(fontsel->font_clist));
894 for (i = 0; i < nfonts; i++)
896 font = &font_info[i];
897 if ((i > 0 && font->family == font_info[i-1].family)
898 || (i < nfonts - 1 && font->family == font_info[i+1].family))
900 sprintf(font_buffer, "%s (%s)", font->family,
901 fontsel_info->properties[FOUNDRY][font->foundry]);
902 font_item = font_buffer;
903 row = gtk_clist_append(GTK_CLIST(fontsel->font_clist), &font_item);
906 row = gtk_clist_append(GTK_CLIST(fontsel->font_clist), &font->family);
907 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_clist), row, GINT_TO_POINTER (i));
909 gtk_clist_thaw (GTK_CLIST(fontsel->font_clist));
913 /* This is called when the clist is exposed. Here we scroll to the current
914 font if necessary. */
916 gtk_font_selection_expose_list (GtkWidget *widget,
917 GdkEventExpose *event,
920 GtkFontSelection *fontsel;
926 g_print("In expose_list\n");
928 fontsel = GTK_FONT_SELECTION(data);
930 if (fontsel->scroll_on_expose)
932 fontsel->scroll_on_expose = FALSE;
934 font_info = fontsel_info->font_info;
936 /* Try to scroll the font family clist to the selected item */
937 selection = GTK_CLIST(fontsel->font_clist)->selection;
940 index = GPOINTER_TO_INT (selection->data);
941 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), index, -1, 0.5, 0);
944 /* Try to scroll the font style clist to the selected item */
945 selection = GTK_CLIST(fontsel->font_style_clist)->selection;
948 index = GPOINTER_TO_INT (selection->data);
949 gtk_clist_moveto(GTK_CLIST(fontsel->font_style_clist), index, -1,
953 /* Try to scroll the font size clist to the selected item */
954 selection = GTK_CLIST(fontsel->size_clist)->selection;
957 index = GPOINTER_TO_INT (selection->data);
958 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), index, -1, 0.5, 0);
964 /* This is called when a family is selected in the list. */
966 gtk_font_selection_select_font (GtkWidget *w,
969 GdkEventButton *bevent,
972 GtkFontSelection *fontsel;
977 g_print("In select_font\n");
979 fontsel = GTK_FONT_SELECTION(data);
980 font_info = fontsel_info->font_info;
982 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
983 gtk_widget_grab_focus (w);
985 row = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_clist), row));
986 font = &font_info[row];
987 gtk_entry_set_text(GTK_ENTRY(fontsel->font_entry), font->family);
989 /* If it is already the current font, just return. */
990 if (fontsel->font_index == row)
993 fontsel->font_index = row;
994 gtk_font_selection_show_available_styles (fontsel);
995 gtk_font_selection_select_best_style (fontsel, TRUE);
1000 gtk_font_selection_on_clist_key_press (GtkWidget *clist,
1002 GtkFontSelection *fontsel)
1004 #ifdef FONTSEL_DEBUG
1005 g_print("In on_clist_key_press\n");
1007 if (event->keyval == GDK_Up)
1008 return gtk_font_selection_select_next (fontsel, clist, -1);
1009 else if (event->keyval == GDK_Down)
1010 return gtk_font_selection_select_next (fontsel, clist, 1);
1017 gtk_font_selection_select_next (GtkFontSelection *fontsel,
1022 gint current_row, row;
1024 selection = GTK_CLIST(clist)->selection;
1027 current_row = GPOINTER_TO_INT (selection->data);
1029 for (row = current_row + step;
1030 row >= 0 && row < GTK_CLIST(clist)->rows;
1033 /* If this is the style clist, make sure that the item is not a charset
1035 if (clist == fontsel->font_style_clist)
1036 if (GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(clist), row)) == -1)
1039 /* Now we've found the row to select. */
1040 if (gtk_clist_row_is_visible(GTK_CLIST(clist), row)
1041 != GTK_VISIBILITY_FULL)
1042 gtk_clist_moveto(GTK_CLIST(clist), row, -1, (step < 0) ? 0 : 1, 0);
1043 gtk_clist_select_row(GTK_CLIST(clist), row, 0);
1050 /* This fills the font style clist with all the possible style combinations
1051 for the current font family. */
1053 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
1057 gint style, tmpstyle, row;
1058 gint weight_index, slant_index, set_width_index, spacing_index;
1060 gchar *weight, *slant, *set_width, *spacing;
1061 gchar *charset = NULL;
1063 gchar buffer[XLFD_MAX_FIELD_LEN * 6 + 2];
1064 GdkColor *inactive_fg, *inactive_bg;
1065 gboolean show_charset;
1067 #ifdef FONTSEL_DEBUG
1068 g_print("In show_available_styles\n");
1070 font = &fontsel_info->font_info[fontsel->font_index];
1071 styles = &fontsel_info->font_styles[font->style_index];
1073 gtk_clist_freeze (GTK_CLIST(fontsel->font_style_clist));
1074 gtk_clist_clear (GTK_CLIST(fontsel->font_style_clist));
1076 /* First we mark all visible styles as not having been displayed yet,
1077 and check if every style has the same charset. If not then we will
1078 display the charset in the list before the styles. */
1079 show_charset = FALSE;
1081 for (style = 0; style < font->nstyles; style++)
1083 if (gtk_font_selection_style_visible(fontsel, font, style))
1085 styles[style].flags &= ~DISPLAYED;
1087 if (charset_index == -1)
1088 charset_index = styles[style].properties[CHARSET];
1089 else if (charset_index != styles[style].properties[CHARSET])
1090 show_charset = TRUE;
1093 styles[style].flags |= DISPLAYED;
1096 /* Step through the undisplayed styles, finding the next charset which
1097 hasn't been displayed yet. Then display the charset on one line, if
1098 necessary, and the visible styles indented beneath it. */
1099 inactive_fg = &fontsel->font_style_clist->style->fg[GTK_STATE_INSENSITIVE];
1100 inactive_bg = &fontsel->font_style_clist->style->bg[GTK_STATE_INSENSITIVE];
1102 for (style = 0; style < font->nstyles; style++)
1104 if (styles[style].flags & DISPLAYED) continue;
1108 charset_index = styles[style].properties[CHARSET];
1109 charset = fontsel_info->properties[CHARSET] [charset_index];
1110 row = gtk_clist_append(GTK_CLIST(fontsel->font_style_clist),
1112 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_style_clist), row,
1114 gtk_clist_set_foreground(GTK_CLIST(fontsel->font_style_clist),
1116 gtk_clist_set_background(GTK_CLIST(fontsel->font_style_clist),
1120 for (tmpstyle = style; tmpstyle < font->nstyles; tmpstyle++)
1122 if (styles[tmpstyle].flags & DISPLAYED
1123 || charset_index != styles[tmpstyle].properties[CHARSET])
1126 styles[tmpstyle].flags |= DISPLAYED;
1128 weight_index = styles[tmpstyle].properties[WEIGHT];
1129 slant_index = styles[tmpstyle].properties[SLANT];
1130 set_width_index = styles[tmpstyle].properties[SET_WIDTH];
1131 spacing_index = styles[tmpstyle].properties[SPACING];
1132 weight = fontsel_info->properties[WEIGHT] [weight_index];
1133 slant = fontsel_info->properties[SLANT] [slant_index];
1134 set_width = fontsel_info->properties[SET_WIDTH][set_width_index];
1135 spacing = fontsel_info->properties[SPACING] [spacing_index];
1137 /* Convert '(nil)' weights to 'regular', since it looks nicer. */
1138 if (!g_strcasecmp(weight, "(nil)")) weight = "regular";
1140 /* We don't show default values or (nil) in the other properties. */
1141 if (!g_strcasecmp(slant, "r")) slant = NULL;
1142 else if (!g_strcasecmp(slant, "(nil)")) slant = NULL;
1143 else if (!g_strcasecmp(slant, "i")) slant = "italic";
1144 else if (!g_strcasecmp(slant, "o")) slant = "oblique";
1145 else if (!g_strcasecmp(slant, "ri")) slant = "reverse italic";
1146 else if (!g_strcasecmp(slant, "ro")) slant = "reverse oblique";
1147 else if (!g_strcasecmp(slant, "ot")) slant = "other";
1149 if (!g_strcasecmp(set_width, "normal")) set_width = NULL;
1150 else if (!g_strcasecmp(set_width, "(nil)")) set_width = NULL;
1152 if (!g_strcasecmp(spacing, "p")) spacing = NULL;
1153 else if (!g_strcasecmp(spacing, "(nil)")) spacing = NULL;
1154 else if (!g_strcasecmp(spacing, "m")) spacing = "[M]";
1155 else if (!g_strcasecmp(spacing, "c")) spacing = "[C]";
1157 /* Add the strings together, making sure there is 1 space between
1159 strcpy(buffer, weight);
1162 strcat(buffer, " ");
1163 strcat(buffer, slant);
1167 strcat(buffer, " ");
1168 strcat(buffer, set_width);
1172 strcat(buffer, " ");
1173 strcat(buffer, spacing);
1177 row = gtk_clist_append(GTK_CLIST(fontsel->font_style_clist),
1180 gtk_clist_set_shift(GTK_CLIST(fontsel->font_style_clist), row, 0,
1182 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_style_clist), row,
1183 GINT_TO_POINTER (tmpstyle));
1187 gtk_clist_thaw (GTK_CLIST(fontsel->font_style_clist));
1191 /* This selects a style when the user selects a font. It just uses the first
1192 available style at present. I was thinking of trying to maintain the
1193 selected style, e.g. bold italic, when the user selects different fonts.
1194 However, the interface is so easy to use now I'm not sure it's worth it.
1195 Note: This will load a font. */
1197 gtk_font_selection_select_best_style(GtkFontSelection *fontsel,
1202 gint row, prop, style = -1, style_to_find;
1203 gboolean found = FALSE;
1205 #ifdef FONTSEL_DEBUG
1206 g_print("In select_best_style\n");
1208 font = &fontsel_info->font_info[fontsel->font_index];
1209 styles = &fontsel_info->font_styles[font->style_index];
1211 /* If use_first is set, we just find the first style in the list, not
1212 including charset items. */
1213 style_to_find = use_first ? -1 : gtk_font_selection_get_best_match (fontsel);
1215 for (row = 0; row < GTK_CLIST(fontsel->font_style_clist)->rows; row++)
1217 style = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_style_clist), row));
1218 if (style != -1 && (style_to_find == -1 || style_to_find == style))
1224 g_return_if_fail (found);
1226 fontsel->style = style;
1228 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1229 fontsel->property_values[prop] = styles[fontsel->style].properties[prop];
1231 gtk_clist_select_row(GTK_CLIST(fontsel->font_style_clist), row, 0);
1232 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_style_clist), row)
1233 != GTK_VISIBILITY_FULL)
1234 gtk_clist_moveto(GTK_CLIST(fontsel->font_style_clist), row, -1, 0.5, 0);
1235 gtk_font_selection_show_available_sizes (fontsel);
1236 gtk_font_selection_select_best_size (fontsel);
1240 /* This is called when a style is selected in the list. */
1242 gtk_font_selection_select_style (GtkWidget *w,
1245 GdkEventButton *bevent,
1248 GtkFontSelection *fontsel;
1249 FontInfo *font_info;
1255 #ifdef FONTSEL_DEBUG
1256 g_print("In select_style\n");
1258 fontsel = GTK_FONT_SELECTION(data);
1259 font_info = fontsel_info->font_info;
1260 font = &font_info[fontsel->font_index];
1261 styles = &fontsel_info->font_styles[font->style_index];
1263 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1264 gtk_widget_grab_focus (w);
1266 /* The style index is stored in the row data, so we just need to copy
1267 the style values into the fontsel and reload the font. */
1268 style = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(fontsel->font_style_clist), row));
1270 /* Don't allow selection of charset rows. */
1273 gtk_clist_unselect_row(GTK_CLIST(fontsel->font_style_clist), row, 0);
1277 gtk_clist_get_text(GTK_CLIST(fontsel->font_style_clist), row, 0, &text);
1278 gtk_entry_set_text(GTK_ENTRY(fontsel->font_style_entry), text);
1280 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1281 fontsel->property_values[prop] = styles[style].properties[prop];
1283 if (fontsel->style == style)
1286 fontsel->style = style;
1287 gtk_font_selection_show_available_sizes (fontsel);
1288 gtk_font_selection_select_best_size (fontsel);
1293 gtk_font_selection_toggle_scaled_bitmaps (GtkWidget *w,
1296 GtkFontSelection *fontsel;
1298 fontsel = GTK_FONT_SELECTION(data);
1300 fontsel->scale_bitmapped_fonts
1301 = GTK_TOGGLE_BUTTON(w)->active ? TRUE : FALSE;
1302 if (fontsel->font_index != -1)
1304 gtk_font_selection_show_available_sizes (fontsel);
1305 gtk_font_selection_select_best_size (fontsel);
1310 /* This shows all the available sizes in the size clist, according to the
1311 current metric and the current font & style. */
1313 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel)
1316 FontStyle *styles, *style;
1317 guint16 *standard_sizes, *bitmapped_sizes, bitmap_size;
1318 gint nstandard_sizes, nbitmapped_sizes;
1319 gchar buffer[16], *size;
1320 gfloat bitmap_size_float;
1323 #ifdef FONTSEL_DEBUG
1324 g_print("In show_available_sizes\n");
1326 font = &fontsel_info->font_info[fontsel->font_index];
1327 styles = &fontsel_info->font_styles[font->style_index];
1328 style = &styles[fontsel->style];
1330 standard_sizes = font_sizes;
1331 nstandard_sizes = sizeof(font_sizes) / sizeof(font_sizes[0]);
1332 if (fontsel->metric == POINTS_METRIC)
1334 bitmapped_sizes = &fontsel_info->point_sizes[style->point_sizes_index];
1335 nbitmapped_sizes = style->npoint_sizes;
1339 bitmapped_sizes = &fontsel_info->pixel_sizes[style->pixel_sizes_index];
1340 nbitmapped_sizes = style->npixel_sizes;
1343 if (!fontsel->scale_bitmapped_fonts && !(style->flags & SCALABLE_FONT))
1344 nstandard_sizes = 0;
1346 gtk_clist_freeze (GTK_CLIST(fontsel->size_clist));
1347 gtk_clist_clear (GTK_CLIST(fontsel->size_clist));
1349 /* Interleave the standard sizes with the bitmapped sizes so we get a list
1350 of ascending sizes. If the metric is points, we have to convert the
1351 decipoints to points. */
1352 while (nstandard_sizes || nbitmapped_sizes)
1355 if (fontsel->metric == POINTS_METRIC)
1357 if (*bitmapped_sizes % 10 != 0)
1359 bitmap_size = *bitmapped_sizes / 10;
1360 bitmap_size_float = *bitmapped_sizes / 10;
1364 bitmap_size = *bitmapped_sizes;
1365 bitmap_size_float = *bitmapped_sizes;
1368 if (can_match && nstandard_sizes && nbitmapped_sizes
1369 && *standard_sizes == bitmap_size)
1371 sprintf(buffer, "%i *", *standard_sizes);
1377 else if (nstandard_sizes
1378 && (!nbitmapped_sizes
1379 || (gfloat)*standard_sizes < bitmap_size_float))
1381 sprintf(buffer, "%i", *standard_sizes);
1387 if (fontsel->metric == POINTS_METRIC)
1389 if (*bitmapped_sizes % 10 == 0)
1390 sprintf(buffer, "%i *", *bitmapped_sizes / 10);
1392 sprintf(buffer, "%i.%i *", *bitmapped_sizes / 10,
1393 *bitmapped_sizes % 10);
1397 sprintf(buffer, "%i *", *bitmapped_sizes);
1403 gtk_clist_append(GTK_CLIST(fontsel->size_clist), &size);
1405 gtk_clist_thaw (GTK_CLIST(fontsel->size_clist));
1409 /* If the user hits return in the font size entry, we change to the new font
1412 gtk_font_selection_size_key_press (GtkWidget *w,
1416 GtkFontSelection *fontsel;
1418 gfloat new_size_float;
1421 #ifdef FONTSEL_DEBUG
1422 g_print("In size_key_press\n");
1424 fontsel = GTK_FONT_SELECTION(data);
1426 if (event->keyval == GDK_Return)
1428 text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1429 if (fontsel->metric == PIXELS_METRIC)
1431 new_size = atoi (text);
1437 new_size_float = atof (text) * 10;
1438 new_size = (gint) new_size_float;
1443 /* Remember that this size was set explicitly. */
1444 fontsel->selected_size = new_size;
1446 /* Check if the font size has changed, and return if it hasn't. */
1447 if (fontsel->size == new_size)
1450 fontsel->size = new_size;
1451 gtk_font_selection_select_best_size (fontsel);
1459 /* This tries to select the closest size to the current size, though it
1460 may have to change the size if only unscaled bitmaps are available.
1461 Note: this will load a font. */
1463 gtk_font_selection_select_best_size(GtkFontSelection *fontsel)
1466 FontStyle *styles, *style;
1468 gint row, best_row = 0, size, size_fraction, best_size = 0, nmatched;
1469 gboolean found = FALSE;
1473 #ifdef FONTSEL_DEBUG
1474 g_print("In select_best_size\n");
1476 font = &fontsel_info->font_info[fontsel->font_index];
1477 styles = &fontsel_info->font_styles[font->style_index];
1478 style = &styles[fontsel->style];
1480 /* Find the closest size available in the size clist. If the exact size is
1481 in the list set found to TRUE. */
1482 for (row = 0; row < GTK_CLIST(fontsel->size_clist)->rows; row++)
1484 gtk_clist_get_text(GTK_CLIST(fontsel->size_clist), row, 0, &text);
1485 nmatched = sscanf(text, "%i.%i", &size, &size_fraction);
1486 if (fontsel->metric == POINTS_METRIC)
1490 size += size_fraction;
1493 if (size == fontsel->selected_size)
1500 else if (best_size == 0
1501 || abs(size - fontsel->selected_size)
1502 < (abs(best_size - fontsel->selected_size)))
1509 /* If we aren't scaling bitmapped fonts and this is a bitmapped font, we
1510 need to use the closest size found. */
1511 if (!fontsel->scale_bitmapped_fonts && !(style->flags & SCALABLE_FONT))
1516 fontsel->size = best_size;
1517 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), best_row, -1, 0.5, 0);
1518 gtk_clist_select_row(GTK_CLIST(fontsel->size_clist), best_row, 0);
1522 fontsel->size = fontsel->selected_size;
1523 selection = GTK_CLIST(fontsel->size_clist)->selection;
1525 gtk_clist_unselect_row(GTK_CLIST(fontsel->size_clist),
1526 GPOINTER_TO_INT (selection->data), 0);
1527 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), best_row, -1, 0.5, 0);
1529 /* Show the size in the size entry. */
1530 if (fontsel->metric == PIXELS_METRIC)
1531 sprintf(buffer, "%i", fontsel->size);
1534 if (fontsel->size % 10 == 0)
1535 sprintf(buffer, "%i", fontsel->size / 10);
1537 sprintf(buffer, "%i.%i", fontsel->size / 10, fontsel->size % 10);
1539 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
1541 gtk_font_selection_load_font (fontsel);
1545 /* This is called when a size is selected in the list. */
1547 gtk_font_selection_select_size (GtkWidget *w,
1550 GdkEventButton *bevent,
1553 GtkFontSelection *fontsel;
1559 #ifdef FONTSEL_DEBUG
1560 g_print("In select_size\n");
1562 fontsel = GTK_FONT_SELECTION(data);
1564 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1565 gtk_widget_grab_focus (w);
1567 /* Copy the size from the clist to the size entry, but without the bitmapped
1569 gtk_clist_get_text(GTK_CLIST(fontsel->size_clist), row, 0, &text);
1571 while (i < 15 && (text[i] == '.' || (text[i] >= '0' && text[i] <= '9')))
1573 buffer[i] = text[i];
1577 gtk_entry_set_text(GTK_ENTRY(fontsel->size_entry), buffer);
1579 /* Check if the font size has changed, and return if it hasn't. */
1580 new_size = atoi(text);
1581 if (fontsel->metric == POINTS_METRIC)
1584 if (fontsel->size == new_size)
1587 /* If the size was selected by the user we set the selected_size. */
1588 fontsel->selected_size = new_size;
1590 fontsel->size = new_size;
1591 gtk_font_selection_load_font (fontsel);
1595 /* This is called when the pixels or points radio buttons are pressed. */
1597 gtk_font_selection_metric_callback (GtkWidget *w,
1600 GtkFontSelection *fontsel = GTK_FONT_SELECTION(data);
1602 #ifdef FONTSEL_DEBUG
1603 g_print("In metric_callback\n");
1605 if (GTK_TOGGLE_BUTTON(fontsel->pixels_button)->active)
1607 if (fontsel->metric == PIXELS_METRIC)
1609 fontsel->metric = PIXELS_METRIC;
1610 fontsel->size = (fontsel->size + 5) / 10;
1611 fontsel->selected_size = (fontsel->selected_size + 5) / 10;
1615 if (fontsel->metric == POINTS_METRIC)
1617 fontsel->metric = POINTS_METRIC;
1618 fontsel->size *= 10;
1619 fontsel->selected_size *= 10;
1621 if (fontsel->font_index != -1)
1623 gtk_font_selection_show_available_sizes (fontsel);
1624 gtk_font_selection_select_best_size (fontsel);
1629 /* This searches the given property table and returns the index of the given
1630 string, or 0, which is the wildcard '*' index, if it's not found. */
1632 gtk_font_selection_field_to_index (gchar **table,
1638 for (i = 0; i < ntable; i++)
1639 if (strcmp (field, table[i]) == 0)
1647 /* This attempts to load the current font, and returns TRUE if it succeeds. */
1649 gtk_font_selection_load_font (GtkFontSelection *fontsel)
1652 gchar *fontname, *label_text;
1655 gdk_font_unref (fontsel->font);
1656 fontsel->font = NULL;
1658 /* If no family has been selected yet, just return FALSE. */
1659 if (fontsel->font_index == -1)
1662 fontname = gtk_font_selection_get_font_name (fontsel);
1665 #ifdef FONTSEL_DEBUG
1666 g_print("Loading: %s\n", fontname);
1668 font = gdk_font_load (fontname);
1673 fontsel->font = font;
1674 /* Make sure the message label is empty, but don't change it unless
1675 it's necessary as it results in a resize of the whole window! */
1676 gtk_label_get(GTK_LABEL(fontsel->message_label), &label_text);
1677 if (strcmp(label_text, ""))
1678 gtk_label_set(GTK_LABEL(fontsel->message_label), "");
1679 gtk_font_selection_update_preview (fontsel);
1684 gtk_label_set(GTK_LABEL(fontsel->message_label),
1685 "The selected font is not available.");
1690 gtk_label_set(GTK_LABEL(fontsel->message_label),
1691 "The selected font is not a valid font.");
1698 /* This sets the font in the preview entry to the selected font, and tries to
1699 make sure that the preview entry is a reasonable size, i.e. so that the
1700 text can be seen with a bit of space to spare. But it tries to avoid
1701 resizing the entry every time the font changes.
1702 This also used to shrink the preview if the font size was decreased, but
1703 that made it awkward if the user wanted to resize the window themself. */
1705 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1707 GtkWidget *preview_entry;
1709 gint text_height, new_height;
1713 #ifdef FONTSEL_DEBUG
1714 g_print("In update_preview\n");
1716 style = gtk_style_new ();
1717 gdk_font_unref (style->font);
1718 style->font = fontsel->font;
1719 gdk_font_ref (style->font);
1721 preview_entry = fontsel->preview_entry;
1722 gtk_widget_set_style (preview_entry, style);
1723 gtk_style_unref(style);
1725 text_height = preview_entry->style->font->ascent
1726 + preview_entry->style->font->descent;
1727 /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1728 new_height = text_height + 20;
1729 if (new_height < INITIAL_PREVIEW_HEIGHT)
1730 new_height = INITIAL_PREVIEW_HEIGHT;
1731 if (new_height > MAX_PREVIEW_HEIGHT)
1732 new_height = MAX_PREVIEW_HEIGHT;
1734 if ((preview_entry->requisition.height < text_height + 10)
1735 || (preview_entry->requisition.height > text_height + 40))
1736 gtk_widget_set_usize(preview_entry, -1, new_height);
1738 /* This sets the preview text, if it hasn't been set already. */
1739 text = gtk_entry_get_text(GTK_ENTRY(fontsel->preview_entry));
1740 if (strlen(text) == 0)
1741 gtk_entry_set_text(GTK_ENTRY(fontsel->preview_entry), PREVIEW_TEXT);
1742 gtk_entry_set_position(GTK_ENTRY(fontsel->preview_entry), 0);
1744 /* If this is a 2-byte font display a message to say it may not be
1745 displayed properly. */
1746 xfs = GDK_FONT_XFONT(fontsel->font);
1747 if (xfs->min_byte1 != 0 || xfs->max_byte1 != 0)
1748 gtk_label_set(GTK_LABEL(fontsel->message_label),
1749 "This is a 2-byte font and may not be displayed correctly.");
1754 gtk_font_selection_switch_page (GtkWidget *w,
1755 GtkNotebookPage *page,
1759 GtkFontSelection *fontsel = GTK_FONT_SELECTION(data);
1761 /* This function strangely gets called when the window is destroyed,
1762 so we check here to see if the notebook is visible. */
1763 if (!GTK_WIDGET_VISIBLE(w))
1767 gtk_font_selection_filter_fonts(fontsel);
1768 else if (page_num == 1)
1769 gtk_font_selection_show_font_info(fontsel);
1774 gtk_font_selection_show_font_info (GtkFontSelection *fontsel)
1776 Atom font_atom, atom;
1780 gchar field_buffer[XLFD_MAX_FIELD_LEN];
1783 gboolean shown_actual_fields = FALSE;
1785 fontname = gtk_font_selection_get_font_name(fontsel);
1786 gtk_entry_set_text(GTK_ENTRY(fontsel->requested_font_name),
1787 fontname ? fontname : "");
1789 gtk_clist_freeze (GTK_CLIST(fontsel->info_clist));
1790 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1793 field = gtk_font_selection_get_xlfd_field (fontname, i, field_buffer);
1798 if (i == XLFD_SLANT)
1799 field = gtk_font_selection_expand_slant_code(field);
1800 else if (i == XLFD_SPACING)
1801 field = gtk_font_selection_expand_spacing_code(field);
1803 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 1,
1804 field ? field : "");
1809 font_atom = XInternAtom(GDK_DISPLAY(), "FONT", True);
1810 if (font_atom != None)
1812 status = XGetFontProperty(GDK_FONT_XFONT(fontsel->font), font_atom,
1816 name = XGetAtomName(GDK_DISPLAY(), atom);
1817 gtk_entry_set_text(GTK_ENTRY(fontsel->actual_font_name), name);
1819 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1821 field = gtk_font_selection_get_xlfd_field (name, i,
1823 if (i == XLFD_SLANT)
1824 field = gtk_font_selection_expand_slant_code(field);
1825 else if (i == XLFD_SPACING)
1826 field = gtk_font_selection_expand_spacing_code(field);
1827 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 2,
1828 field ? field : "");
1830 shown_actual_fields = TRUE;
1835 if (!shown_actual_fields)
1837 gtk_entry_set_text(GTK_ENTRY(fontsel->actual_font_name), "");
1838 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1840 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 2,
1841 fontname ? "(unknown)" : "");
1844 gtk_clist_thaw (GTK_CLIST(fontsel->info_clist));
1850 gtk_font_selection_expand_slant_code(gchar *slant)
1852 if (!g_strcasecmp(slant, "r")) return("roman");
1853 else if (!g_strcasecmp(slant, "i")) return("italic");
1854 else if (!g_strcasecmp(slant, "o")) return("oblique");
1855 else if (!g_strcasecmp(slant, "ri")) return("reverse italic");
1856 else if (!g_strcasecmp(slant, "ro")) return("reverse oblique");
1857 else if (!g_strcasecmp(slant, "ot")) return("other");
1862 gtk_font_selection_expand_spacing_code(gchar *spacing)
1864 if (!g_strcasecmp(spacing, "p")) return("proportional");
1865 else if (!g_strcasecmp(spacing, "m")) return("monospaced");
1866 else if (!g_strcasecmp(spacing, "c")) return("char cell");
1871 /*****************************************************************************
1872 * These functions all deal with the Filter page.
1873 *****************************************************************************/
1875 /* This is called when an item is selected in one of the filter clists.
1876 We make sure that the first row of the clist, i.e. the wildcard '*', is
1877 selected if and only if none of the other items are selected.
1878 We may need to be careful about triggering other signals. */
1880 gtk_font_selection_select_filter (GtkWidget *w,
1883 GdkEventButton *bevent,
1889 for (i = 1; i < GTK_CLIST(w)->rows; i++)
1890 gtk_clist_unselect_row(GTK_CLIST(w), i, 0);
1892 gtk_clist_unselect_row(GTK_CLIST(w), 0, 0);
1896 /* Here a filter item is being deselected. If there are now no items selected
1897 we select the first '*' item, unless that it is the item being deselected,
1898 in which case we select all of the other items. This makes it easy to
1899 select all items in the list except one or two. */
1901 gtk_font_selection_unselect_filter (GtkWidget *w,
1904 GdkEventButton *bevent,
1908 if (!GTK_CLIST(w)->selection)
1911 for (i = 1; i < GTK_CLIST(w)->rows; i++)
1912 gtk_clist_select_row(GTK_CLIST(w), i, 0);
1914 gtk_clist_select_row(GTK_CLIST(w), 0, 0);
1919 /* This is called when the main notebook page is selected. It checks if the
1920 filter has changed, an if so it creates the filter settings, and filters the
1921 fonts shown. If an empty filter (all '*'s) is applied, then filtering is
1924 gtk_font_selection_filter_fonts (GtkFontSelection *fontsel)
1928 gboolean empty_filter = TRUE, filter_changed = FALSE;
1929 gint prop, nselected, i, row, index;
1931 #ifdef FONTSEL_DEBUG
1932 g_print("In filter_fonts\n");
1935 /* Check if the filter has changed, and also if it is an empty filter,
1936 i.e. all '*'s are selected. */
1937 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
1939 clist = fontsel->filter_clists[prop];
1940 selection = GTK_CLIST(clist)->selection;
1941 nselected = g_list_length(selection);
1942 if (nselected != 1 || GPOINTER_TO_INT (selection->data) != 0)
1944 empty_filter = FALSE;
1946 if (fontsel->property_nfilters[prop] != nselected)
1947 filter_changed = TRUE;
1950 for (i = 0; i < nselected; i++)
1952 row = GPOINTER_TO_INT (selection->data);
1953 index = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (clist), row));
1954 if (fontsel->property_filters[prop][i] != index)
1955 filter_changed = TRUE;
1956 selection = selection->next;
1962 if (fontsel->property_nfilters[prop] != 0)
1963 filter_changed = TRUE;
1967 /* If the filter hasn't changed we just return. */
1968 if (!filter_changed)
1971 #ifdef FONTSEL_DEBUG
1972 g_print(" filter_fonts: filter has changed\n");
1975 /* Setting the toggle buttons state will trigger the callbacks to clear
1976 or apply the filter, unless the font list is already filtered, in
1977 which case we have to call apply_filter here. */
1980 gtk_widget_set_sensitive(fontsel->filter_button, FALSE);
1981 gtk_label_set(GTK_LABEL(fontsel->font_label), "Font:");
1982 gtk_font_selection_apply_filter(fontsel);
1986 gtk_widget_set_sensitive(fontsel->filter_button, TRUE);
1987 gtk_label_set(GTK_LABEL(fontsel->font_label), "Font: [Filtered]");
1988 gtk_font_selection_apply_filter(fontsel);
1993 /* This clears the filter, showing all fonts and styles again. */
1995 gtk_font_selection_apply_filter (GtkFontSelection *fontsel)
1997 FontInfo *font_info, *font;
2000 gint nfonts, prop, nselected, i, j, row, style, index;
2001 gchar font_buffer[XLFD_MAX_FIELD_LEN * 2 + 4];
2003 gboolean matched, matched_style;
2005 #ifdef FONTSEL_DEBUG
2006 g_print("In apply_filter\n");
2008 font_info = fontsel_info->font_info;
2009 nfonts = fontsel_info->nfonts;
2011 /* Free the old filter data and create the new arrays. */
2012 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2014 g_free(fontsel->property_filters[prop]);
2016 clist = fontsel->filter_clists[prop];
2017 selection = GTK_CLIST(clist)->selection;
2018 nselected = g_list_length(selection);
2019 if (nselected == 1 && GPOINTER_TO_INT (selection->data) == 0)
2021 fontsel->property_filters[prop] = NULL;
2022 fontsel->property_nfilters[prop] = 0;
2026 fontsel->property_filters[prop] = g_new(guint16, nselected);
2027 fontsel->property_nfilters[prop] = nselected;
2028 for (i = 0; i < nselected; i++)
2030 row = GPOINTER_TO_INT (selection->data);
2031 index = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (clist), row));
2032 fontsel->property_filters[prop][i] = index;
2033 selection = selection->next;
2038 /* Filter the list of fonts. */
2039 gtk_clist_freeze (GTK_CLIST(fontsel->font_clist));
2040 gtk_clist_clear (GTK_CLIST(fontsel->font_clist));
2041 for (i = 0; i < nfonts; i++)
2043 font = &font_info[i];
2045 /* Check if the foundry matches. */
2046 if (fontsel->property_nfilters[FOUNDRY] != 0)
2049 for (j = 0; j < fontsel->property_nfilters[FOUNDRY]; j++)
2051 if (font->foundry == fontsel->property_filters[FOUNDRY][j])
2061 /* Now check if the other properties are matched in at least one style.*/
2062 matched_style = FALSE;
2063 for (style = 0; style < font->nstyles; style++)
2065 if (gtk_font_selection_style_visible(fontsel, font, style))
2067 matched_style = TRUE;
2074 /* Insert the font in the clist. */
2075 if ((i > 0 && font->family == font_info[i-1].family)
2076 || (i < nfonts - 1 && font->family == font_info[i+1].family))
2078 sprintf(font_buffer, "%s (%s)", font->family,
2079 fontsel_info->properties[FOUNDRY][font->foundry]);
2080 font_item = font_buffer;
2081 row = gtk_clist_append(GTK_CLIST(fontsel->font_clist), &font_item);
2085 row = gtk_clist_append(GTK_CLIST(fontsel->font_clist),
2088 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_clist), row,
2089 GINT_TO_POINTER (i));
2091 gtk_clist_thaw (GTK_CLIST(fontsel->font_clist));
2093 /* Clear the current font and the style clist. */
2094 fontsel->font_index = -1;
2096 gdk_font_unref(fontsel->font);
2097 fontsel->font = NULL;
2098 gtk_entry_set_text(GTK_ENTRY(fontsel->font_entry), "");
2099 gtk_clist_clear (GTK_CLIST(fontsel->font_style_clist));
2100 gtk_entry_set_text(GTK_ENTRY(fontsel->font_style_entry), "");
2104 /* Returns TRUE if the style is not currently filtered out. */
2106 gtk_font_selection_style_visible(GtkFontSelection *fontsel,
2115 styles = &fontsel_info->font_styles[font->style_index];
2117 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2119 value = styles[style].properties[prop];
2121 if (fontsel->property_nfilters[prop] != 0)
2124 for (j = 0; j < fontsel->property_nfilters[prop]; j++)
2126 if (value == fontsel->property_filters[prop][j])
2140 /* This resets all the filter clists to the wildcard '*' options. */
2142 gtk_font_selection_reset_filter (GtkWidget *w,
2145 GtkFontSelection *fontsel;
2148 fontsel = GTK_FONT_SELECTION(data);
2150 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2151 gtk_clist_select_row(GTK_CLIST(fontsel->filter_clists[prop]), 0, 0);
2155 /* This clears the filter, showing all fonts and styles again. */
2157 gtk_font_selection_on_clear_filter (GtkWidget *w,
2160 GtkFontSelection *fontsel;
2162 fontsel = GTK_FONT_SELECTION(data);
2163 gtk_font_selection_clear_filter(fontsel);
2167 /* This clears the filter, showing all fonts and styles again. */
2169 gtk_font_selection_clear_filter (GtkFontSelection *fontsel)
2171 gboolean filtered = FALSE, found_style = FALSE;
2172 gint prop, row, style;
2174 #ifdef FONTSEL_DEBUG
2175 g_print("In clear_filter\n");
2177 /* Clear the filter data. */
2178 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2180 if (fontsel->property_filters[prop])
2182 g_free(fontsel->property_filters[prop]);
2183 fontsel->property_filters[prop] = NULL;
2184 fontsel->property_nfilters[prop] = 0;
2187 /* Select all the '*'s on the filter page. */
2188 gtk_font_selection_reset_filter(NULL, fontsel);
2190 /* Update the main notebook page. */
2191 gtk_widget_set_sensitive(fontsel->filter_button, FALSE);
2192 gtk_label_set(GTK_LABEL(fontsel->font_label), "Font:");
2194 /* If there is no filter at present just return. */
2198 gtk_font_selection_insert_fonts(fontsel);
2200 /* Now find the current font & style and select them again. */
2201 if (fontsel->font_index != -1)
2203 gtk_clist_select_row(GTK_CLIST(fontsel->font_clist),
2204 fontsel->font_index, 0);
2205 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_clist),
2206 fontsel->font_index) != GTK_VISIBILITY_FULL)
2207 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), fontsel->font_index,
2209 gtk_font_selection_show_available_styles (fontsel);
2211 for (row = 0; row < GTK_CLIST(fontsel->font_style_clist)->rows; row++)
2213 style = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(fontsel->font_style_clist), row));
2214 if (style == fontsel->style)
2223 gtk_clist_select_row(GTK_CLIST(fontsel->font_style_clist),
2225 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_style_clist),
2226 row) != GTK_VISIBILITY_FULL)
2227 gtk_clist_moveto(GTK_CLIST(fontsel->font_style_clist), row,
2234 /*****************************************************************************
2235 * These functions all deal with creating the main class arrays containing
2236 * the data about all available fonts.
2237 *****************************************************************************/
2239 gtk_font_selection_get_fonts (void)
2246 gint i, prop, style, size;
2247 gint npixel_sizes = 0, npoint_sizes = 0;
2249 FontStyle *current_style, *prev_style, *tmp_style;
2250 gboolean matched_style, found_size;
2251 gint pixels, points, res_x, res_y;
2252 gchar field_buffer[XLFD_MAX_FIELD_LEN];
2255 guint16 *pixel_sizes, *point_sizes, *tmp_sizes;
2257 fontsel_info = g_new (GtkFontSelInfo, 1);
2259 /* Get a maximum of MAX_FONTS fontnames from the X server.
2260 Use "-*" as the pattern rather than "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" since
2261 the latter may result in fonts being returned which don't actually exist.
2262 xlsfonts also uses "*" so I think it's OK. "-*" gets rid of aliases. */
2263 xfontnames = XListFonts (GDK_DISPLAY(), "-*", MAX_FONTS, &num_fonts);
2264 /* Output a warning if we actually get MAX_FONTS fonts. */
2265 if (num_fonts == MAX_FONTS)
2266 g_warning("MAX_FONTS exceeded. Some fonts may be missing.");
2268 /* The maximum size of all these tables is the number of font names
2269 returned. We realloc them later when we know exactly how many
2270 unique entries there are. */
2271 fontsel_info->font_info = g_new (FontInfo, num_fonts);
2272 fontsel_info->font_styles = g_new (FontStyle, num_fonts);
2273 fontsel_info->pixel_sizes = g_new (guint16, num_fonts);
2274 fontsel_info->point_sizes = g_new (guint16, num_fonts);
2276 fontnames = g_new (GSList*, num_fonts);
2278 /* Create the initial arrays for the property value strings, though they
2279 may be realloc'ed later. Put the wildcard '*' in the first elements. */
2280 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2282 fontsel_info->properties[prop] = g_new(gchar*, PROPERTY_ARRAY_INCREMENT);
2283 fontsel_info->space_allocated[prop] = PROPERTY_ARRAY_INCREMENT;
2284 fontsel_info->nproperties[prop] = 1;
2285 fontsel_info->properties[prop][0] = "*";
2289 /* Insert the font families into the main table, sorted by family and
2290 foundry (fonts with different foundries are placed in seaparate FontInfos.
2291 All fontnames in each family + foundry are placed into the fontnames
2293 fontsel_info->nfonts = 0;
2294 for (i = 0; i < num_fonts; i++)
2296 #ifdef FONTSEL_DEBUG
2297 g_print("%s\n", xfontnames[i]);
2299 if (gtk_font_selection_is_xlfd_font_name (xfontnames[i]))
2300 gtk_font_selection_insert_font (fontnames, &fontsel_info->nfonts, xfontnames[i]);
2303 #ifdef FONTSEL_DEBUG
2304 g_warning("Skipping invalid font: %s", xfontnames[i]);
2310 /* Since many font names will be in the same FontInfo not all of the
2311 allocated FontInfo table will be used, so we will now reallocate it
2312 with the real size. */
2313 fontsel_info->font_info = g_realloc(fontsel_info->font_info,
2314 sizeof(FontInfo) * fontsel_info->nfonts);
2317 /* Now we work out which choices of weight/slant etc. are valid for each
2319 fontsel_info->nstyles = 0;
2320 current_style = fontsel_info->font_styles;
2321 for (i = 0; i < fontsel_info->nfonts; i++)
2323 font = &fontsel_info->font_info[i];
2325 /* Use the next free position in the styles array. */
2326 font->style_index = fontsel_info->nstyles;
2328 /* Now step through each of the fontnames with this family, and create
2329 a style for each fontname. Each style contains the index into the
2330 weights/slants etc. arrays, and a number of pixel/point sizes. */
2332 temp_list = fontnames[i];
2335 fontname = temp_list->data;
2336 temp_list = temp_list->next;
2338 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2340 current_style->properties[prop]
2341 = gtk_font_selection_insert_field (fontname, prop);
2343 current_style->pixel_sizes_index = npixel_sizes;
2344 current_style->point_sizes_index = npoint_sizes;
2345 current_style->flags = 0;
2348 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_PIXELS,
2350 pixels = atoi(field);
2352 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_POINTS,
2354 points = atoi(field);
2356 field = gtk_font_selection_get_xlfd_field (fontname,
2359 res_x = atoi(field);
2361 field = gtk_font_selection_get_xlfd_field (fontname,
2364 res_y = atoi(field);
2366 if (pixels == 0 && points == 0)
2368 if (res_x == 0 && res_y == 0)
2369 flags = SCALABLE_FONT;
2372 flags = SCALABLE_BITMAP_FONT;
2373 fontsel_info->scaled_bitmaps_available = TRUE;
2377 flags = BITMAP_FONT;
2379 /* Now we check to make sure that the style is unique. If it isn't
2381 prev_style = fontsel_info->font_styles + font->style_index;
2382 matched_style = FALSE;
2383 while (prev_style < current_style)
2385 matched_style = TRUE;
2386 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2388 if (prev_style->properties[prop]
2389 != current_style->properties[prop])
2391 matched_style = FALSE;
2400 /* If we matched an existing style, we need to add the pixels &
2401 point sizes to the style. If not, we insert the pixel & point
2402 sizes into our new style. Note that we don't add sizes for
2406 prev_style->flags |= flags;
2407 if (flags == BITMAP_FONT)
2409 pixel_sizes = fontsel_info->pixel_sizes
2410 + prev_style->pixel_sizes_index;
2412 for (size = 0; size < prev_style->npixel_sizes; size++)
2414 if (pixels == *pixel_sizes)
2419 else if (pixels < *pixel_sizes)
2423 /* We need to move all the following pixel sizes up, and also
2424 update the indexes of any following styles. */
2427 for (tmp_sizes = fontsel_info->pixel_sizes + npixel_sizes;
2428 tmp_sizes > pixel_sizes; tmp_sizes--)
2429 *tmp_sizes = *(tmp_sizes - 1);
2431 *pixel_sizes = pixels;
2433 prev_style->npixel_sizes++;
2435 tmp_style = prev_style + 1;
2436 while (tmp_style < current_style)
2438 tmp_style->pixel_sizes_index++;
2443 point_sizes = fontsel_info->point_sizes
2444 + prev_style->point_sizes_index;
2446 for (size = 0; size < prev_style->npoint_sizes; size++)
2448 if (points == *point_sizes)
2453 else if (points < *point_sizes)
2457 /* We need to move all the following point sizes up, and also
2458 update the indexes of any following styles. */
2461 for (tmp_sizes = fontsel_info->point_sizes + npoint_sizes;
2462 tmp_sizes > point_sizes; tmp_sizes--)
2463 *tmp_sizes = *(tmp_sizes - 1);
2465 *point_sizes = points;
2467 prev_style->npoint_sizes++;
2469 tmp_style = prev_style + 1;
2470 while (tmp_style < current_style)
2472 tmp_style->point_sizes_index++;
2480 current_style->flags = flags;
2481 if (flags == BITMAP_FONT)
2483 fontsel_info->pixel_sizes[npixel_sizes++] = pixels;
2484 current_style->npixel_sizes = 1;
2485 fontsel_info->point_sizes[npoint_sizes++] = points;
2486 current_style->npoint_sizes = 1;
2489 fontsel_info->nstyles++;
2493 g_slist_free(fontnames[i]);
2495 /* Set nstyles to the real value, minus duplicated fontnames.
2496 Note that we aren't using all the allocated memory if fontnames are
2498 font->nstyles = style;
2501 /* Since some repeated styles may be skipped we won't have used all the
2502 allocated space, so we will now reallocate it with the real size. */
2503 fontsel_info->font_styles = g_realloc(fontsel_info->font_styles,
2504 sizeof(FontStyle) * fontsel_info->nstyles);
2505 fontsel_info->pixel_sizes = g_realloc(fontsel_info->pixel_sizes,
2506 sizeof(guint16) * npixel_sizes);
2507 fontsel_info->point_sizes = g_realloc(fontsel_info->point_sizes,
2508 sizeof(guint16) * npoint_sizes);
2510 XFreeFontNames (xfontnames);
2513 /* Debugging Output */
2514 /* This outputs all FontInfos. */
2515 #ifdef FONTSEL_DEBUG
2516 g_print("\n\n Font Family Weight Slant Set Width Spacing Charset\n\n");
2517 for (i = 0; i < fontsel_info->nfonts; i++)
2519 FontInfo *font = &fontsel_info->font_info[i];
2520 FontStyle *styles = fontsel_info->font_styles + font->style_index;
2521 for (style = 0; style < font->nstyles; style++)
2523 g_print("%5i %-16.16s ", i, font->family);
2524 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2526 fontsel_info->properties[prop][styles->properties[prop]]);
2529 if (styles->flags & BITMAP_FONT)
2530 g_print("Bitmapped font ");
2531 if (styles->flags & SCALABLE_FONT)
2532 g_print("Scalable font ");
2533 if (styles->flags & SCALABLE_BITMAP_FONT)
2534 g_print("Scalable-Bitmapped font ");
2537 if (styles->npixel_sizes)
2539 g_print(" Pixel sizes: ");
2540 tmp_sizes = fontsel_info->pixel_sizes + styles->pixel_sizes_index;
2541 for (size = 0; size < styles->npixel_sizes; size++)
2542 g_print("%i ", *tmp_sizes++);
2546 if (styles->npoint_sizes)
2548 g_print(" Point sizes: ");
2549 tmp_sizes = fontsel_info->point_sizes + styles->point_sizes_index;
2550 for (size = 0; size < styles->npoint_sizes; size++)
2551 g_print("%i ", *tmp_sizes++);
2559 /* This outputs all available properties. */
2560 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2562 g_print("Property: %s\n", xlfd_field_names[xlfd_index[prop]]);
2563 for (i = 0; i < fontsel_info->nproperties[prop]; i++)
2564 g_print(" %s\n", fontsel_info->properties[prop][i]);
2569 /* This inserts the given fontname into the FontInfo table.
2570 If a FontInfo already exists with the same family and foundry, then the
2571 fontname is added to the FontInfos list of fontnames, else a new FontInfo
2572 is created and inserted in alphabetical order in the table. */
2574 gtk_font_selection_insert_font (GSList *fontnames[],
2580 GSList *temp_fontname;
2582 gboolean family_exists = FALSE;
2586 gchar family_buffer[XLFD_MAX_FIELD_LEN];
2588 table = fontsel_info->font_info;
2590 /* insert a fontname into a table */
2591 family = gtk_font_selection_get_xlfd_field (fontname, XLFD_FAMILY,
2596 foundry = gtk_font_selection_insert_field (fontname, FOUNDRY);
2601 /* Do a binary search to determine if we have already encountered
2602 * a font with this family & foundry. */
2604 while (lower < upper)
2606 middle = (lower + upper) >> 1;
2608 cmp = strcmp (family, table[middle].family);
2609 /* If the family matches we sort by the foundry. */
2612 family_exists = TRUE;
2613 family = table[middle].family;
2614 cmp = strcmp(fontsel_info->properties[FOUNDRY][foundry],
2615 fontsel_info->properties[FOUNDRY][table[middle].foundry]);
2620 fontnames[middle] = g_slist_prepend (fontnames[middle],
2631 /* Add another entry to the table for this new font family */
2632 temp_info.family = family_exists ? family : g_strdup(family);
2633 temp_info.foundry = foundry;
2634 temp_fontname = g_slist_prepend (NULL, fontname);
2638 /* Quickly insert the entry into the table in sorted order
2639 * using a modification of insertion sort and the knowledge
2640 * that the entries proper position in the table was determined
2641 * above in the binary search and is contained in the "lower"
2645 upper = *ntable - 1;
2646 while (lower != upper)
2648 table[upper] = table[upper-1];
2649 fontnames[upper] = fontnames[upper-1];
2653 table[lower] = temp_info;
2654 fontnames[lower] = temp_fontname;
2658 /* This checks that the specified field of the given fontname is in the
2659 appropriate properties array. If not it is added. Thus eventually we get
2660 arrays of all possible weights/slants etc. It returns the array index. */
2662 gtk_font_selection_insert_field (gchar *fontname,
2665 gchar field_buffer[XLFD_MAX_FIELD_LEN];
2669 field = gtk_font_selection_get_xlfd_field (fontname, xlfd_index[prop],
2674 /* If the field is already in the array just return its index. */
2675 for (index = 0; index < fontsel_info->nproperties[prop]; index++)
2676 if (!strcmp(field, fontsel_info->properties[prop][index]))
2679 /* Make sure we have enough space to add the field. */
2680 if (fontsel_info->nproperties[prop] == fontsel_info->space_allocated[prop])
2682 fontsel_info->space_allocated[prop] += PROPERTY_ARRAY_INCREMENT;
2683 fontsel_info->properties[prop] = g_realloc(fontsel_info->properties[prop],
2685 * fontsel_info->space_allocated[prop]);
2688 /* Add the new field. */
2689 index = fontsel_info->nproperties[prop];
2690 fontsel_info->properties[prop][index] = g_strdup(field);
2691 fontsel_info->nproperties[prop]++;
2696 /*****************************************************************************
2697 * These functions are the main public interface for getting/setting the font.
2698 *****************************************************************************/
2701 gtk_font_selection_get_font (GtkFontSelection *fontsel)
2703 g_return_val_if_fail (fontsel != NULL, NULL);
2704 return fontsel->font;
2709 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
2712 gchar *family_str, *foundry_str;
2713 gchar *property_str[GTK_NUM_STYLE_PROPERTIES];
2716 g_return_val_if_fail (fontsel != NULL, NULL);
2717 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
2719 /* If no family has been selected return NULL. */
2720 if (fontsel->font_index == -1)
2723 font = &fontsel_info->font_info[fontsel->font_index];
2724 family_str = font->family;
2725 foundry_str = fontsel_info->properties[FOUNDRY][font->foundry];
2727 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2730 = fontsel_info->properties[prop][fontsel->property_values[prop]];
2731 if (strcmp (property_str[prop], "(nil)") == 0)
2732 property_str[prop] = "";
2735 return gtk_font_selection_create_xlfd (fontsel->size,
2739 property_str[WEIGHT],
2740 property_str[SLANT],
2741 property_str[SET_WIDTH],
2742 property_str[SPACING],
2743 property_str[CHARSET]);
2747 /* This returns the style with the best match to the current fontsel setting */
2749 gtk_font_selection_get_best_match(GtkFontSelection *fontsel)
2753 gint prop, style, best_style = 0, matched, best_matched = 0;
2755 font = &fontsel_info->font_info[fontsel->font_index];
2756 styles = &fontsel_info->font_styles[font->style_index];
2758 /* Find the style with the most matches. */
2759 for (style = 0; style < font->nstyles; style++)
2762 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2764 if (fontsel->property_values[prop] == styles[style].properties[prop])
2767 if (matched > best_matched)
2769 best_matched = matched;
2778 /* This sets the current font, selecting the appropriate clist rows.
2779 First we check the fontname is valid and try to find the font family
2780 - i.e. the name in the main list. If we can't find that, then just return.
2781 Next we try to set each of the properties according to the fontname.
2782 Finally we select the font family & style in the clists. */
2784 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
2785 const gchar *fontname)
2787 gchar *family, *field;
2788 gint index, prop, size;
2789 guint16 foundry, value;
2790 gchar family_buffer[XLFD_MAX_FIELD_LEN];
2791 gchar field_buffer[XLFD_MAX_FIELD_LEN];
2794 g_return_val_if_fail (fontsel != NULL, FALSE);
2795 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
2796 g_return_val_if_fail (fontname != NULL, FALSE);
2798 /* Check it is a valid fontname. */
2799 if (!gtk_font_selection_is_xlfd_font_name(fontname))
2802 family = gtk_font_selection_get_xlfd_field (fontname, XLFD_FAMILY,
2807 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_FOUNDRY,
2809 foundry = gtk_font_selection_field_to_index (fontsel_info->properties[FOUNDRY],
2810 fontsel_info->nproperties[FOUNDRY],
2813 index = gtk_font_selection_find_font(fontsel, family, foundry);
2817 /* Convert the property fields into indices and set them. */
2818 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2820 field = gtk_font_selection_get_xlfd_field (fontname, xlfd_index[prop],
2822 value = gtk_font_selection_field_to_index (fontsel_info->properties[prop],
2823 fontsel_info->nproperties[prop],
2825 fontsel->property_values[prop] = value;
2828 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_POINTS,
2835 fontsel->size = fontsel->selected_size = size;
2836 fontsel->metric = POINTS_METRIC;
2837 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->points_button),
2840 sprintf (buffer, "%i", size / 10);
2842 sprintf (buffer, "%i.%i", size / 10, size % 10);
2846 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_PIXELS,
2851 fontsel->size = fontsel->selected_size = size;
2852 fontsel->metric = PIXELS_METRIC;
2853 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->pixels_button),
2855 sprintf (buffer, "%i", size);
2857 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
2859 /* Clear any current filter. */
2860 gtk_font_selection_clear_filter(fontsel);
2862 /* Now find the best style match. */
2863 fontsel->font_index = index;
2864 gtk_clist_select_row(GTK_CLIST(fontsel->font_clist), index, 0);
2865 if (GTK_WIDGET_MAPPED (fontsel->font_clist))
2866 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), index, -1, 0.5, 0);
2868 fontsel->scroll_on_expose = TRUE;
2870 gtk_font_selection_show_available_styles (fontsel);
2871 /* This will load the font. */
2872 gtk_font_selection_select_best_style (fontsel, FALSE);
2878 /* Returns the index of the given family, or -1 if not found */
2880 gtk_font_selection_find_font (GtkFontSelection *fontsel,
2884 FontInfo *font_info;
2885 gint lower, upper, middle = -1, cmp, nfonts;
2887 font_info = fontsel_info->font_info;
2888 nfonts = fontsel_info->nfonts;
2892 /* Do a binary search to find the font family. */
2895 while (lower < upper)
2897 middle = (lower + upper) >> 1;
2899 cmp = strcmp (family, font_info[middle].family);
2901 cmp = strcmp(fontsel_info->properties[FOUNDRY][foundry],
2902 fontsel_info->properties[FOUNDRY][font_info[middle].foundry]);
2912 /* If we can't match family & foundry see if just the family matches */
2913 if (!strcmp (family, font_info[middle].family))
2920 /* This returns the text in the preview entry. You should copy the returned
2921 text if you need it. */
2923 gtk_font_selection_get_preview_text (GtkFontSelection *fontsel)
2925 return gtk_entry_get_text(GTK_ENTRY(fontsel->preview_entry));
2929 /* This sets the text in the preview entry. */
2931 gtk_font_selection_set_preview_text (GtkFontSelection *fontsel,
2934 gtk_entry_set_text(GTK_ENTRY(fontsel->preview_entry), text);
2938 /*****************************************************************************
2939 * These functions all deal with X Logical Font Description (XLFD) fontnames.
2940 * See the freely available documentation about this.
2941 *****************************************************************************/
2944 * Returns TRUE if the fontname is a valid XLFD.
2945 * (It just checks if the number of dashes is 14, and that each
2946 * field < XLFD_MAX_FIELD_LEN characters long - that's not in the XLFD but it
2947 * makes it easier for me).
2950 gtk_font_selection_is_xlfd_font_name (const gchar *fontname)
2957 if (*fontname++ == '-')
2959 if (field_len > XLFD_MAX_FIELD_LEN) return FALSE;
2967 return (i == 14) ? TRUE : FALSE;
2971 * This fills the buffer with the specified field from the X Logical Font
2972 * Description name, and returns it. If fontname is NULL or the field is
2973 * longer than XFLD_MAX_FIELD_LEN it returns NULL.
2974 * Note: For the charset field, we also return the encoding, e.g. 'iso8859-1'.
2977 gtk_font_selection_get_xlfd_field (const gchar *fontname,
2978 FontField field_num,
2981 const gchar *t1, *t2;
2982 gint countdown, len, num_dashes;
2987 /* we assume this is a valid fontname...that is, it has 14 fields */
2989 countdown = field_num;
2991 while (*t1 && (countdown >= 0))
2995 num_dashes = (field_num == XLFD_CHARSET) ? 2 : 1;
2996 for (t2 = t1; *t2; t2++)
2998 if (*t2 == '-' && --num_dashes == 0)
3004 /* Check we don't overflow the buffer */
3005 len = (long) t2 - (long) t1;
3006 if (len > XLFD_MAX_FIELD_LEN - 1)
3008 strncpy (buffer, t1, len);
3012 strcpy(buffer, "(nil)");
3018 * This returns a X Logical Font Description font name, given all the pieces.
3019 * Note: this retval must be freed by the caller.
3022 gtk_font_selection_create_xlfd (gint size,
3023 GtkFontMetricType metric,
3033 gchar *pixel_size = "*", *point_size = "*", *fontname;
3039 sprintf (buffer, "%d", (int) size);
3040 if (metric == PIXELS_METRIC)
3041 pixel_size = buffer;
3043 point_size = buffer;
3045 /* Note: be careful here - don't overrun the allocated memory. */
3046 length = strlen(foundry) + strlen(family) + strlen(weight) + strlen(slant)
3047 + strlen(set_width) + strlen(pixel_size) + strlen(point_size)
3048 + strlen(spacing) + strlen(charset)
3049 + 1 + 1 + 1 + 1 + 1 + 3 + 1 + 5 + 3
3050 + 1 /* for the terminating '\0'. */;
3052 fontname = g_new(gchar, length);
3053 /* **NOTE**: If you change this string please change length above! */
3054 sprintf(fontname, "-%s-%s-%s-%s-%s-*-%s-%s-*-*-%s-*-%s",
3055 foundry, family, weight, slant, set_width, pixel_size,
3056 point_size, spacing, charset);
3062 /*****************************************************************************
3063 * GtkFontSelectionDialog
3064 *****************************************************************************/
3067 gtk_font_selection_dialog_get_type (void)
3069 static guint font_selection_dialog_type = 0;
3071 if (!font_selection_dialog_type)
3073 GtkTypeInfo fontsel_diag_info =
3075 "GtkFontSelectionDialog",
3076 sizeof (GtkFontSelectionDialog),
3077 sizeof (GtkFontSelectionDialogClass),
3078 (GtkClassInitFunc) gtk_font_selection_dialog_class_init,
3079 (GtkObjectInitFunc) gtk_font_selection_dialog_init,
3080 /* reserved_1 */ NULL,
3081 /* reserved_2 */ NULL,
3082 (GtkClassInitFunc) NULL,
3085 font_selection_dialog_type = gtk_type_unique (gtk_window_get_type (), &fontsel_diag_info);
3088 return font_selection_dialog_type;
3092 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
3094 GtkObjectClass *object_class;
3096 object_class = (GtkObjectClass*) klass;
3098 font_selection_dialog_parent_class = gtk_type_class (gtk_window_get_type ());
3102 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
3104 fontseldiag->dialog_width = -1;
3105 fontseldiag->auto_resize = TRUE;
3107 gtk_widget_set_events(GTK_WIDGET(fontseldiag), GDK_STRUCTURE_MASK);
3108 gtk_signal_connect (GTK_OBJECT (fontseldiag), "configure_event",
3109 (GtkSignalFunc) gtk_font_selection_dialog_on_configure,
3112 gtk_container_border_width (GTK_CONTAINER (fontseldiag), 4);
3113 gtk_window_set_policy(GTK_WINDOW(fontseldiag), FALSE, TRUE, TRUE);
3115 fontseldiag->main_vbox = gtk_vbox_new (FALSE, 4);
3116 gtk_widget_show (fontseldiag->main_vbox);
3117 gtk_container_add (GTK_CONTAINER (fontseldiag), fontseldiag->main_vbox);
3119 fontseldiag->fontsel = gtk_font_selection_new();
3120 gtk_widget_show (fontseldiag->fontsel);
3121 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
3122 fontseldiag->fontsel, TRUE, TRUE, 0);
3124 /* Create the action area */
3125 fontseldiag->action_area = gtk_hbutton_box_new ();
3126 gtk_button_box_set_layout(GTK_BUTTON_BOX(fontseldiag->action_area),
3128 gtk_button_box_set_spacing(GTK_BUTTON_BOX(fontseldiag->action_area), 5);
3129 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
3130 fontseldiag->action_area, FALSE, FALSE, 0);
3131 gtk_widget_show (fontseldiag->action_area);
3133 fontseldiag->ok_button = gtk_button_new_with_label("OK");
3134 GTK_WIDGET_SET_FLAGS (fontseldiag->ok_button, GTK_CAN_DEFAULT);
3135 gtk_widget_show(fontseldiag->ok_button);
3136 gtk_box_pack_start (GTK_BOX (fontseldiag->action_area),
3137 fontseldiag->ok_button, TRUE, TRUE, 0);
3138 gtk_widget_grab_default (fontseldiag->ok_button);
3140 fontseldiag->apply_button = gtk_button_new_with_label("Apply");
3141 GTK_WIDGET_SET_FLAGS (fontseldiag->apply_button, GTK_CAN_DEFAULT);
3142 /*gtk_widget_show(fontseldiag->apply_button);*/
3143 gtk_box_pack_start (GTK_BOX(fontseldiag->action_area),
3144 fontseldiag->apply_button, TRUE, TRUE, 0);
3146 fontseldiag->cancel_button = gtk_button_new_with_label("Cancel");
3147 GTK_WIDGET_SET_FLAGS (fontseldiag->cancel_button, GTK_CAN_DEFAULT);
3148 gtk_widget_show(fontseldiag->cancel_button);
3149 gtk_box_pack_start (GTK_BOX(fontseldiag->action_area),
3150 fontseldiag->cancel_button, TRUE, TRUE, 0);
3156 gtk_font_selection_dialog_new (const gchar *title)
3158 GtkFontSelectionDialog *fontseldiag;
3160 fontseldiag = gtk_type_new (gtk_font_selection_dialog_get_type ());
3161 gtk_window_set_title (GTK_WINDOW (fontseldiag),
3162 title ? title : "Font Selection");
3164 return GTK_WIDGET (fontseldiag);
3168 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
3170 return gtk_font_selection_get_font_name(GTK_FONT_SELECTION(fsd->fontsel));
3174 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
3176 return gtk_font_selection_get_font(GTK_FONT_SELECTION(fsd->fontsel));
3180 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
3181 const gchar *fontname)
3183 return gtk_font_selection_set_font_name(GTK_FONT_SELECTION(fsd->fontsel),
3189 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
3191 return gtk_font_selection_get_preview_text(GTK_FONT_SELECTION(fsd->fontsel));
3195 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
3198 gtk_font_selection_set_preview_text(GTK_FONT_SELECTION(fsd->fontsel), text);
3202 /* This turns auto-shrink off if the user resizes the width of the dialog.
3203 It also turns it back on again if the user resizes it back to its normal
3206 gtk_font_selection_dialog_on_configure (GtkWidget *widget,
3207 GdkEventConfigure *event,
3208 GtkFontSelectionDialog *fsd)
3210 /* This sets the initial width. */
3211 if (fsd->dialog_width == -1)
3212 fsd->dialog_width = event->width;
3213 else if (fsd->auto_resize && fsd->dialog_width != event->width)
3215 fsd->auto_resize = FALSE;
3216 gtk_window_set_policy(GTK_WINDOW(fsd), FALSE, TRUE, FALSE);
3218 else if (!fsd->auto_resize && fsd->dialog_width == event->width)
3220 fsd->auto_resize = TRUE;
3221 gtk_window_set_policy(GTK_WINDOW(fsd), FALSE, TRUE, TRUE);