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 (GtkArgSetFunc) NULL,
403 (GtkArgGetFunc) NULL,
406 font_selection_type = gtk_type_unique (gtk_notebook_get_type(),
410 return font_selection_type;
414 gtk_font_selection_class_init(GtkFontSelectionClass *klass)
416 GtkObjectClass *object_class;
418 object_class = (GtkObjectClass *) klass;
420 font_selection_parent_class = gtk_type_class (gtk_notebook_get_type ());
422 object_class->destroy = gtk_font_selection_destroy;
424 gtk_font_selection_get_fonts ();
428 gtk_font_selection_init(GtkFontSelection *fontsel)
430 GtkWidget *text_frame;
432 GtkWidget *table, *label, *hbox, *hbox2, *clist, *button, *vbox, *alignment;
434 gchar *titles[] = { "Font Property", "Requested Value", "Actual Value" };
439 gchar *property, *text;
442 /* Initialize the GtkFontSelection struct. We do this here in case any
443 callbacks are triggered while creating the interface. */
444 fontsel->font = NULL;
445 fontsel->font_index = -1;
447 fontsel->metric = INITIAL_METRIC;
448 fontsel->size = INITIAL_FONT_SIZE;
449 fontsel->selected_size = INITIAL_FONT_SIZE;
450 fontsel->scale_bitmapped_fonts = FALSE;
452 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
454 fontsel->property_filters[prop] = NULL;
455 fontsel->property_nfilters[prop] = 0;
458 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
459 fontsel->property_values[prop] = 0;
461 fontsel->scroll_on_expose = TRUE;
463 /* Create the main notebook page. */
464 fontsel->main_vbox = gtk_vbox_new (FALSE, 4);
465 gtk_widget_show (fontsel->main_vbox);
466 gtk_container_border_width (GTK_CONTAINER (fontsel->main_vbox), 6);
467 label = gtk_label_new("Font");
468 gtk_widget_set_usize (label, 120, -1);
469 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
470 fontsel->main_vbox, label);
472 /* Create the table of font, style & size. */
473 table = gtk_table_new (3, 3, FALSE);
474 gtk_widget_show (table);
475 gtk_table_set_col_spacings(GTK_TABLE(table), 8);
476 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), table, TRUE, TRUE, 0);
478 fontsel->font_label = gtk_label_new("Font:");
479 gtk_misc_set_alignment (GTK_MISC (fontsel->font_label), 0.0, 0.5);
480 gtk_widget_show (fontsel->font_label);
481 gtk_table_attach (GTK_TABLE (table), fontsel->font_label, 0, 1, 0, 1,
483 label = gtk_label_new("Font Style:");
484 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
485 gtk_widget_show (label);
486 gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1,
488 label = gtk_label_new("Size:");
489 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
490 gtk_widget_show (label);
491 gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
494 fontsel->font_entry = gtk_entry_new();
495 gtk_entry_set_editable(GTK_ENTRY(fontsel->font_entry), FALSE);
496 gtk_widget_set_usize (fontsel->font_entry, 20, -1);
497 gtk_widget_show (fontsel->font_entry);
498 gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
500 fontsel->font_style_entry = gtk_entry_new();
501 gtk_entry_set_editable(GTK_ENTRY(fontsel->font_style_entry), FALSE);
502 gtk_widget_set_usize (fontsel->font_style_entry, 20, -1);
503 gtk_widget_show (fontsel->font_style_entry);
504 gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
506 fontsel->size_entry = gtk_entry_new();
507 gtk_widget_set_usize (fontsel->size_entry, 20, -1);
508 gtk_widget_show (fontsel->size_entry);
509 gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
511 gtk_signal_connect (GTK_OBJECT (fontsel->size_entry), "key_press_event",
512 (GtkSignalFunc) gtk_font_selection_size_key_press,
515 /* Create the clists */
516 fontsel->font_clist = gtk_clist_new(1);
517 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->font_clist));
518 gtk_clist_set_column_width (GTK_CLIST(fontsel->font_clist), 0, 300);
519 gtk_clist_set_policy(GTK_CLIST(fontsel->font_clist), GTK_POLICY_ALWAYS,
520 GTK_POLICY_AUTOMATIC);
521 gtk_widget_set_usize (fontsel->font_clist, FONT_LIST_WIDTH,
523 gtk_widget_show(fontsel->font_clist);
524 gtk_table_attach (GTK_TABLE (table), fontsel->font_clist, 0, 1, 2, 3,
525 GTK_EXPAND | GTK_FILL,
526 GTK_EXPAND | GTK_FILL, 0, 0);
528 fontsel->font_style_clist = gtk_clist_new(1);
529 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->font_style_clist));
530 gtk_clist_set_column_width (GTK_CLIST(fontsel->font_style_clist), 0, 300);
531 gtk_clist_set_policy(GTK_CLIST(fontsel->font_style_clist), GTK_POLICY_ALWAYS,
532 GTK_POLICY_AUTOMATIC);
533 gtk_widget_set_usize (fontsel->font_style_clist, FONT_STYLE_LIST_WIDTH, -1);
534 gtk_widget_show(fontsel->font_style_clist);
535 gtk_table_attach (GTK_TABLE (table), fontsel->font_style_clist, 1, 2, 2, 3,
536 GTK_EXPAND | GTK_FILL,
537 GTK_EXPAND | GTK_FILL, 0, 0);
539 fontsel->size_clist = gtk_clist_new(1);
540 gtk_clist_column_titles_hide (GTK_CLIST(fontsel->size_clist));
541 gtk_clist_set_policy(GTK_CLIST(fontsel->size_clist), GTK_POLICY_ALWAYS,
542 GTK_POLICY_AUTOMATIC);
543 gtk_widget_set_usize (fontsel->size_clist, FONT_SIZE_LIST_WIDTH, -1);
544 gtk_widget_show(fontsel->size_clist);
545 gtk_table_attach (GTK_TABLE (table), fontsel->size_clist, 2, 3, 2, 3,
546 GTK_FILL, GTK_FILL, 0, 0);
549 /* Insert the fonts. If there exist fonts with the same family but
550 different foundries, then the foundry name is appended in brackets. */
551 gtk_font_selection_insert_fonts(fontsel);
553 gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "select_row",
554 GTK_SIGNAL_FUNC(gtk_font_selection_select_font),
556 GTK_WIDGET_SET_FLAGS (fontsel->font_clist, GTK_CAN_FOCUS);
557 gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "key_press_event",
558 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
560 gtk_signal_connect_after (GTK_OBJECT (fontsel->font_clist), "expose_event",
561 GTK_SIGNAL_FUNC(gtk_font_selection_expose_list),
564 gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist), "select_row",
565 GTK_SIGNAL_FUNC(gtk_font_selection_select_style),
567 GTK_WIDGET_SET_FLAGS (fontsel->font_style_clist, GTK_CAN_FOCUS);
568 gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist),
570 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
573 /* Insert the standard font sizes */
574 gtk_clist_freeze (GTK_CLIST(fontsel->size_clist));
575 size_to_match = INITIAL_FONT_SIZE;
576 if (INITIAL_METRIC == POINTS_METRIC)
577 size_to_match = size_to_match / 10;
578 for (i = 0; i < sizeof(font_sizes) / sizeof(font_sizes[0]); i++)
580 sprintf(buffer, "%i", font_sizes[i]);
582 gtk_clist_append(GTK_CLIST(fontsel->size_clist), &size);
583 if (font_sizes[i] == size_to_match)
585 gtk_clist_select_row(GTK_CLIST(fontsel->size_clist), i, 0);
586 gtk_entry_set_text(GTK_ENTRY(fontsel->size_entry), buffer);
589 gtk_clist_thaw (GTK_CLIST(fontsel->size_clist));
591 gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "select_row",
592 GTK_SIGNAL_FUNC(gtk_font_selection_select_size),
594 GTK_WIDGET_SET_FLAGS (fontsel->size_clist, GTK_CAN_FOCUS);
595 gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "key_press_event",
596 GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
600 /* create the Filter, Scale Bitmaps & Metric buttons */
601 hbox = gtk_hbox_new(FALSE, 8);
602 gtk_widget_show (hbox);
603 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), hbox, FALSE, TRUE, 0);
605 fontsel->filter_button = gtk_button_new_with_label(" Clear Filter ");
606 gtk_widget_show(fontsel->filter_button);
607 gtk_box_pack_start (GTK_BOX (hbox), fontsel->filter_button, FALSE, FALSE, 0);
608 gtk_widget_set_sensitive (fontsel->filter_button, FALSE);
609 gtk_signal_connect (GTK_OBJECT (fontsel->filter_button), "clicked",
610 GTK_SIGNAL_FUNC(gtk_font_selection_on_clear_filter),
613 fontsel->scaled_bitmaps_button
614 = gtk_check_button_new_with_label("Allow scaled bitmap fonts");
615 gtk_widget_show(fontsel->scaled_bitmaps_button);
616 gtk_box_pack_start (GTK_BOX (hbox), fontsel->scaled_bitmaps_button,
618 if (!fontsel_info->scaled_bitmaps_available)
619 gtk_widget_set_sensitive (fontsel->scaled_bitmaps_button, FALSE);
620 gtk_signal_connect (GTK_OBJECT (fontsel->scaled_bitmaps_button), "clicked",
621 GTK_SIGNAL_FUNC(gtk_font_selection_toggle_scaled_bitmaps),
625 hbox2 = gtk_hbox_new(FALSE, 0);
626 gtk_widget_show (hbox2);
627 gtk_box_pack_end (GTK_BOX (hbox), hbox2, FALSE, FALSE, 0);
629 label = gtk_label_new("Metric:");
630 gtk_widget_show (label);
631 gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 8);
633 fontsel->points_button = gtk_radio_button_new_with_label(NULL, "Points");
634 gtk_widget_show (fontsel->points_button);
635 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->points_button, FALSE, TRUE, 0);
636 if (INITIAL_METRIC == POINTS_METRIC)
637 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->points_button),
640 fontsel->pixels_button = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(fontsel->points_button), "Pixels");
641 gtk_widget_show (fontsel->pixels_button);
642 gtk_box_pack_start (GTK_BOX (hbox2), fontsel->pixels_button, FALSE, TRUE, 0);
643 if (INITIAL_METRIC == PIXELS_METRIC)
644 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->pixels_button),
647 gtk_signal_connect(GTK_OBJECT(fontsel->points_button), "toggled",
648 (GtkSignalFunc) gtk_font_selection_metric_callback,
650 gtk_signal_connect(GTK_OBJECT(fontsel->pixels_button), "toggled",
651 (GtkSignalFunc) gtk_font_selection_metric_callback,
655 /* create the text entry widget */
656 text_frame = gtk_frame_new ("Preview:");
657 gtk_widget_show (text_frame);
658 gtk_frame_set_shadow_type(GTK_FRAME(text_frame), GTK_SHADOW_ETCHED_IN);
659 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), text_frame,
662 /* This is just used to get a 4-pixel space around the preview entry. */
663 text_box = gtk_hbox_new (FALSE, 0);
664 gtk_widget_show (text_box);
665 gtk_container_add (GTK_CONTAINER (text_frame), text_box);
666 gtk_container_border_width (GTK_CONTAINER (text_box), 4);
668 fontsel->preview_entry = gtk_entry_new ();
669 gtk_widget_show (fontsel->preview_entry);
670 gtk_widget_set_usize (fontsel->preview_entry, -1, INITIAL_PREVIEW_HEIGHT);
671 gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
674 /* Create the message area */
675 fontsel->message_label = gtk_label_new("");
676 gtk_widget_show (fontsel->message_label);
677 gtk_box_pack_start (GTK_BOX (fontsel->main_vbox), fontsel->message_label,
681 /* Create the font info page */
682 fontsel->info_vbox = gtk_vbox_new (FALSE, 4);
683 gtk_widget_show (fontsel->info_vbox);
684 gtk_container_border_width (GTK_CONTAINER (fontsel->info_vbox), 2);
685 label = gtk_label_new("Font Information");
686 gtk_widget_set_usize (label, 120, -1);
687 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
688 fontsel->info_vbox, label);
690 fontsel->info_clist = gtk_clist_new_with_titles(3, titles);
691 gtk_widget_set_usize (fontsel->info_clist, 390, 150);
692 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 0, 130);
693 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 1, 130);
694 gtk_clist_set_column_width(GTK_CLIST(fontsel->info_clist), 2, 130);
695 gtk_clist_column_titles_passive(GTK_CLIST(fontsel->info_clist));
696 gtk_clist_set_policy(GTK_CLIST(fontsel->info_clist), GTK_POLICY_AUTOMATIC,
697 GTK_POLICY_AUTOMATIC);
698 gtk_widget_show(fontsel->info_clist);
699 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), fontsel->info_clist,
702 /* Insert the property names */
703 gtk_clist_freeze (GTK_CLIST(fontsel->info_clist));
706 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
708 row_text[0] = xlfd_field_names[i];
709 gtk_clist_append(GTK_CLIST(fontsel->info_clist), row_text);
710 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 0, 0, 4);
711 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 1, 0, 4);
712 gtk_clist_set_shift(GTK_CLIST(fontsel->info_clist), i, 2, 0, 4);
714 gtk_clist_thaw (GTK_CLIST(fontsel->info_clist));
716 label = gtk_label_new("Requested Font Name:");
717 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
718 gtk_widget_show (label);
719 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, TRUE, 0);
721 fontsel->requested_font_name = gtk_entry_new();
722 gtk_entry_set_editable(GTK_ENTRY(fontsel->requested_font_name), FALSE);
723 gtk_widget_show (fontsel->requested_font_name);
724 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox),
725 fontsel->requested_font_name, FALSE, TRUE, 0);
727 label = gtk_label_new("Actual Font Name:");
728 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
729 gtk_widget_show (label);
730 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, TRUE, 0);
732 fontsel->actual_font_name = gtk_entry_new();
733 gtk_entry_set_editable(GTK_ENTRY(fontsel->actual_font_name), FALSE);
734 gtk_widget_show (fontsel->actual_font_name);
735 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox),
736 fontsel->actual_font_name, FALSE, TRUE, 0);
738 sprintf(buffer, "%i fonts available with a total of %i styles.",
739 fontsel_info->nfonts, fontsel_info->nstyles);
740 label = gtk_label_new(buffer);
741 gtk_widget_show (label);
742 gtk_box_pack_start (GTK_BOX (fontsel->info_vbox), label, FALSE, FALSE, 0);
744 gtk_signal_connect (GTK_OBJECT (fontsel), "switch_page",
745 GTK_SIGNAL_FUNC(gtk_font_selection_switch_page),
749 /* Create the Filter page. */
750 fontsel->filter_vbox = gtk_vbox_new (FALSE, 4);
751 gtk_widget_show (fontsel->filter_vbox);
752 gtk_container_border_width (GTK_CONTAINER (fontsel->filter_vbox), 2);
753 label = gtk_label_new("Filter");
754 gtk_widget_set_usize (label, 120, -1);
755 gtk_notebook_append_page (GTK_NOTEBOOK (fontsel),
756 fontsel->filter_vbox, label);
758 table = gtk_table_new (4, 3, FALSE);
759 gtk_table_set_col_spacings(GTK_TABLE(table), 2);
760 gtk_widget_show (table);
761 gtk_box_pack_start (GTK_BOX (fontsel->filter_vbox), table, TRUE, TRUE, 0);
763 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
765 gint left = filter_positions[prop][0];
766 gint top = filter_positions[prop][1];
768 label = gtk_label_new(xlfd_field_names[xlfd_index[prop]]);
769 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 1.0);
770 gtk_misc_set_padding (GTK_MISC (label), 0, 2);
771 gtk_widget_show(label);
772 gtk_table_attach (GTK_TABLE (table), label, left, left + 1,
773 top, top + 1, GTK_FILL, GTK_FILL, 0, 0);
775 clist = gtk_clist_new(1);
776 gtk_widget_set_usize (clist, 100, filter_heights[prop]);
777 gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_MULTIPLE);
778 gtk_clist_column_titles_hide(GTK_CLIST(clist));
779 gtk_clist_set_policy(GTK_CLIST(clist), GTK_POLICY_AUTOMATIC,
780 GTK_POLICY_AUTOMATIC);
781 gtk_widget_show(clist);
783 /* For the bottom-right cell we add the 'Clear Filter' button. */
784 if (top == 2 && left == 2)
786 vbox = gtk_vbox_new(FALSE, 0);
787 gtk_widget_show(vbox);
788 gtk_table_attach (GTK_TABLE (table), vbox, left, left + 1,
789 top + 1, top + 2, GTK_FILL, GTK_FILL, 0, 0);
791 gtk_box_pack_start (GTK_BOX (vbox), clist, TRUE, TRUE, 0);
793 alignment = gtk_alignment_new(0.5, 0.0, 0.8, 0.0);
794 gtk_widget_show(alignment);
795 gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, TRUE, 4);
797 button = gtk_button_new_with_label("Clear Filter");
798 gtk_widget_show(button);
799 gtk_container_add(GTK_CONTAINER(alignment), button);
800 gtk_signal_connect (GTK_OBJECT (button), "clicked",
801 GTK_SIGNAL_FUNC(gtk_font_selection_reset_filter),
805 gtk_table_attach (GTK_TABLE (table), clist,
806 left, left + 1, top + 1, top + 2,
807 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
809 gtk_signal_connect (GTK_OBJECT (clist), "select_row",
810 GTK_SIGNAL_FUNC(gtk_font_selection_select_filter),
812 gtk_signal_connect (GTK_OBJECT (clist), "unselect_row",
813 GTK_SIGNAL_FUNC(gtk_font_selection_unselect_filter),
816 /* Insert the property names, expanded, and in sorted order.
817 But we make sure that the wildcard '*' is first. */
818 gtk_clist_freeze (GTK_CLIST(clist));
820 gtk_clist_append(GTK_CLIST(clist), &property);
822 for (i = 1; i < fontsel_info->nproperties[prop]; i++) {
823 property = fontsel_info->properties[prop][i];
825 property = gtk_font_selection_expand_slant_code(property);
826 else if (prop == SPACING)
827 property = gtk_font_selection_expand_spacing_code(property);
830 for (row = 1; row < GTK_CLIST(clist)->rows; row++)
832 gtk_clist_get_text(GTK_CLIST(clist), row, 0, &text);
833 if (strcmp(property, text) < 0)
836 gtk_clist_insert(GTK_CLIST(clist), row, &property);
841 row = gtk_clist_append(GTK_CLIST(clist), &property);
842 gtk_clist_set_row_data(GTK_CLIST(clist), row, GINT_TO_POINTER (i));
844 gtk_clist_select_row(GTK_CLIST(clist), 0, 0);
845 gtk_clist_thaw (GTK_CLIST(clist));
846 fontsel->filter_clists[prop] = clist;
851 gtk_font_selection_new()
853 GtkFontSelection *fontsel;
855 fontsel = gtk_type_new (gtk_font_selection_get_type ());
857 return GTK_WIDGET (fontsel);
861 gtk_font_selection_destroy (GtkObject *object)
863 GtkFontSelection *fontsel;
865 g_return_if_fail (object != NULL);
866 g_return_if_fail (GTK_IS_FONT_SELECTION (object));
868 fontsel = GTK_FONT_SELECTION (object);
870 /* All we have to do is unref the font, if we have one. */
872 gdk_font_unref (fontsel->font);
874 if (GTK_OBJECT_CLASS (font_selection_parent_class)->destroy)
875 (* GTK_OBJECT_CLASS (font_selection_parent_class)->destroy) (object);
879 /* This inserts all the fonts into the family clist. */
881 gtk_font_selection_insert_fonts (GtkFontSelection *fontsel)
883 FontInfo *font_info, *font;
884 gchar font_buffer[XLFD_MAX_FIELD_LEN * 2 + 4];
888 font_info = fontsel_info->font_info;
889 nfonts = fontsel_info->nfonts;
891 gtk_clist_freeze (GTK_CLIST(fontsel->font_clist));
892 gtk_clist_clear (GTK_CLIST(fontsel->font_clist));
893 for (i = 0; i < nfonts; i++)
895 font = &font_info[i];
896 if ((i > 0 && font->family == font_info[i-1].family)
897 || (i < nfonts - 1 && font->family == font_info[i+1].family))
899 sprintf(font_buffer, "%s (%s)", font->family,
900 fontsel_info->properties[FOUNDRY][font->foundry]);
901 font_item = font_buffer;
902 row = gtk_clist_append(GTK_CLIST(fontsel->font_clist), &font_item);
905 row = gtk_clist_append(GTK_CLIST(fontsel->font_clist), &font->family);
906 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_clist), row, GINT_TO_POINTER (i));
908 gtk_clist_thaw (GTK_CLIST(fontsel->font_clist));
912 /* This is called when the clist is exposed. Here we scroll to the current
913 font if necessary. */
915 gtk_font_selection_expose_list (GtkWidget *widget,
916 GdkEventExpose *event,
919 GtkFontSelection *fontsel;
925 g_print("In expose_list\n");
927 fontsel = GTK_FONT_SELECTION(data);
929 if (fontsel->scroll_on_expose)
931 fontsel->scroll_on_expose = FALSE;
933 font_info = fontsel_info->font_info;
935 /* Try to scroll the font family clist to the selected item */
936 selection = GTK_CLIST(fontsel->font_clist)->selection;
939 index = GPOINTER_TO_INT (selection->data);
940 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), index, -1, 0.5, 0);
943 /* Try to scroll the font style clist to the selected item */
944 selection = GTK_CLIST(fontsel->font_style_clist)->selection;
947 index = GPOINTER_TO_INT (selection->data);
948 gtk_clist_moveto(GTK_CLIST(fontsel->font_style_clist), index, -1,
952 /* Try to scroll the font size clist to the selected item */
953 selection = GTK_CLIST(fontsel->size_clist)->selection;
956 index = GPOINTER_TO_INT (selection->data);
957 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), index, -1, 0.5, 0);
963 /* This is called when a family is selected in the list. */
965 gtk_font_selection_select_font (GtkWidget *w,
968 GdkEventButton *bevent,
971 GtkFontSelection *fontsel;
976 g_print("In select_font\n");
978 fontsel = GTK_FONT_SELECTION(data);
979 font_info = fontsel_info->font_info;
981 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
982 gtk_widget_grab_focus (w);
984 row = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_clist), row));
985 font = &font_info[row];
986 gtk_entry_set_text(GTK_ENTRY(fontsel->font_entry), font->family);
988 /* If it is already the current font, just return. */
989 if (fontsel->font_index == row)
992 fontsel->font_index = row;
993 gtk_font_selection_show_available_styles (fontsel);
994 gtk_font_selection_select_best_style (fontsel, TRUE);
999 gtk_font_selection_on_clist_key_press (GtkWidget *clist,
1001 GtkFontSelection *fontsel)
1003 #ifdef FONTSEL_DEBUG
1004 g_print("In on_clist_key_press\n");
1006 if (event->keyval == GDK_Up)
1007 return gtk_font_selection_select_next (fontsel, clist, -1);
1008 else if (event->keyval == GDK_Down)
1009 return gtk_font_selection_select_next (fontsel, clist, 1);
1016 gtk_font_selection_select_next (GtkFontSelection *fontsel,
1021 gint current_row, row;
1023 selection = GTK_CLIST(clist)->selection;
1026 current_row = GPOINTER_TO_INT (selection->data);
1028 for (row = current_row + step;
1029 row >= 0 && row < GTK_CLIST(clist)->rows;
1032 /* If this is the style clist, make sure that the item is not a charset
1034 if (clist == fontsel->font_style_clist)
1035 if (GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(clist), row)) == -1)
1038 /* Now we've found the row to select. */
1039 if (gtk_clist_row_is_visible(GTK_CLIST(clist), row)
1040 != GTK_VISIBILITY_FULL)
1041 gtk_clist_moveto(GTK_CLIST(clist), row, -1, (step < 0) ? 0 : 1, 0);
1042 gtk_clist_select_row(GTK_CLIST(clist), row, 0);
1049 /* This fills the font style clist with all the possible style combinations
1050 for the current font family. */
1052 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
1056 gint style, tmpstyle, row;
1057 gint weight_index, slant_index, set_width_index, spacing_index;
1059 gchar *weight, *slant, *set_width, *spacing;
1060 gchar *charset = NULL;
1062 gchar buffer[XLFD_MAX_FIELD_LEN * 6 + 2];
1063 GdkColor *inactive_fg, *inactive_bg;
1064 gboolean show_charset;
1066 #ifdef FONTSEL_DEBUG
1067 g_print("In show_available_styles\n");
1069 font = &fontsel_info->font_info[fontsel->font_index];
1070 styles = &fontsel_info->font_styles[font->style_index];
1072 gtk_clist_freeze (GTK_CLIST(fontsel->font_style_clist));
1073 gtk_clist_clear (GTK_CLIST(fontsel->font_style_clist));
1075 /* First we mark all visible styles as not having been displayed yet,
1076 and check if every style has the same charset. If not then we will
1077 display the charset in the list before the styles. */
1078 show_charset = FALSE;
1080 for (style = 0; style < font->nstyles; style++)
1082 if (gtk_font_selection_style_visible(fontsel, font, style))
1084 styles[style].flags &= ~DISPLAYED;
1086 if (charset_index == -1)
1087 charset_index = styles[style].properties[CHARSET];
1088 else if (charset_index != styles[style].properties[CHARSET])
1089 show_charset = TRUE;
1092 styles[style].flags |= DISPLAYED;
1095 /* Step through the undisplayed styles, finding the next charset which
1096 hasn't been displayed yet. Then display the charset on one line, if
1097 necessary, and the visible styles indented beneath it. */
1098 inactive_fg = &fontsel->font_style_clist->style->fg[GTK_STATE_INSENSITIVE];
1099 inactive_bg = &fontsel->font_style_clist->style->bg[GTK_STATE_INSENSITIVE];
1101 for (style = 0; style < font->nstyles; style++)
1103 if (styles[style].flags & DISPLAYED) continue;
1107 charset_index = styles[style].properties[CHARSET];
1108 charset = fontsel_info->properties[CHARSET] [charset_index];
1109 row = gtk_clist_append(GTK_CLIST(fontsel->font_style_clist),
1111 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_style_clist), row,
1113 gtk_clist_set_foreground(GTK_CLIST(fontsel->font_style_clist),
1115 gtk_clist_set_background(GTK_CLIST(fontsel->font_style_clist),
1119 for (tmpstyle = style; tmpstyle < font->nstyles; tmpstyle++)
1121 if (styles[tmpstyle].flags & DISPLAYED
1122 || charset_index != styles[tmpstyle].properties[CHARSET])
1125 styles[tmpstyle].flags |= DISPLAYED;
1127 weight_index = styles[tmpstyle].properties[WEIGHT];
1128 slant_index = styles[tmpstyle].properties[SLANT];
1129 set_width_index = styles[tmpstyle].properties[SET_WIDTH];
1130 spacing_index = styles[tmpstyle].properties[SPACING];
1131 weight = fontsel_info->properties[WEIGHT] [weight_index];
1132 slant = fontsel_info->properties[SLANT] [slant_index];
1133 set_width = fontsel_info->properties[SET_WIDTH][set_width_index];
1134 spacing = fontsel_info->properties[SPACING] [spacing_index];
1136 /* Convert '(nil)' weights to 'regular', since it looks nicer. */
1137 if (!g_strcasecmp(weight, "(nil)")) weight = "regular";
1139 /* We don't show default values or (nil) in the other properties. */
1140 if (!g_strcasecmp(slant, "r")) slant = NULL;
1141 else if (!g_strcasecmp(slant, "(nil)")) slant = NULL;
1142 else if (!g_strcasecmp(slant, "i")) slant = "italic";
1143 else if (!g_strcasecmp(slant, "o")) slant = "oblique";
1144 else if (!g_strcasecmp(slant, "ri")) slant = "reverse italic";
1145 else if (!g_strcasecmp(slant, "ro")) slant = "reverse oblique";
1146 else if (!g_strcasecmp(slant, "ot")) slant = "other";
1148 if (!g_strcasecmp(set_width, "normal")) set_width = NULL;
1149 else if (!g_strcasecmp(set_width, "(nil)")) set_width = NULL;
1151 if (!g_strcasecmp(spacing, "p")) spacing = NULL;
1152 else if (!g_strcasecmp(spacing, "(nil)")) spacing = NULL;
1153 else if (!g_strcasecmp(spacing, "m")) spacing = "[M]";
1154 else if (!g_strcasecmp(spacing, "c")) spacing = "[C]";
1156 /* Add the strings together, making sure there is 1 space between
1158 strcpy(buffer, weight);
1161 strcat(buffer, " ");
1162 strcat(buffer, slant);
1166 strcat(buffer, " ");
1167 strcat(buffer, set_width);
1171 strcat(buffer, " ");
1172 strcat(buffer, spacing);
1176 row = gtk_clist_append(GTK_CLIST(fontsel->font_style_clist),
1179 gtk_clist_set_shift(GTK_CLIST(fontsel->font_style_clist), row, 0,
1181 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_style_clist), row,
1182 GINT_TO_POINTER (tmpstyle));
1186 gtk_clist_thaw (GTK_CLIST(fontsel->font_style_clist));
1190 /* This selects a style when the user selects a font. It just uses the first
1191 available style at present. I was thinking of trying to maintain the
1192 selected style, e.g. bold italic, when the user selects different fonts.
1193 However, the interface is so easy to use now I'm not sure it's worth it.
1194 Note: This will load a font. */
1196 gtk_font_selection_select_best_style(GtkFontSelection *fontsel,
1201 gint row, prop, style = -1, style_to_find;
1202 gboolean found = FALSE;
1204 #ifdef FONTSEL_DEBUG
1205 g_print("In select_best_style\n");
1207 font = &fontsel_info->font_info[fontsel->font_index];
1208 styles = &fontsel_info->font_styles[font->style_index];
1210 /* If use_first is set, we just find the first style in the list, not
1211 including charset items. */
1212 style_to_find = use_first ? -1 : gtk_font_selection_get_best_match (fontsel);
1214 for (row = 0; row < GTK_CLIST(fontsel->font_style_clist)->rows; row++)
1216 style = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (fontsel->font_style_clist), row));
1217 if (style != -1 && (style_to_find == -1 || style_to_find == style))
1223 g_return_if_fail (found);
1225 fontsel->style = style;
1227 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1228 fontsel->property_values[prop] = styles[fontsel->style].properties[prop];
1230 gtk_clist_select_row(GTK_CLIST(fontsel->font_style_clist), row, 0);
1231 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_style_clist), row)
1232 != GTK_VISIBILITY_FULL)
1233 gtk_clist_moveto(GTK_CLIST(fontsel->font_style_clist), row, -1, 0.5, 0);
1234 gtk_font_selection_show_available_sizes (fontsel);
1235 gtk_font_selection_select_best_size (fontsel);
1239 /* This is called when a style is selected in the list. */
1241 gtk_font_selection_select_style (GtkWidget *w,
1244 GdkEventButton *bevent,
1247 GtkFontSelection *fontsel;
1248 FontInfo *font_info;
1254 #ifdef FONTSEL_DEBUG
1255 g_print("In select_style\n");
1257 fontsel = GTK_FONT_SELECTION(data);
1258 font_info = fontsel_info->font_info;
1259 font = &font_info[fontsel->font_index];
1260 styles = &fontsel_info->font_styles[font->style_index];
1262 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1263 gtk_widget_grab_focus (w);
1265 /* The style index is stored in the row data, so we just need to copy
1266 the style values into the fontsel and reload the font. */
1267 style = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(fontsel->font_style_clist), row));
1269 /* Don't allow selection of charset rows. */
1272 gtk_clist_unselect_row(GTK_CLIST(fontsel->font_style_clist), row, 0);
1276 gtk_clist_get_text(GTK_CLIST(fontsel->font_style_clist), row, 0, &text);
1277 gtk_entry_set_text(GTK_ENTRY(fontsel->font_style_entry), text);
1279 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
1280 fontsel->property_values[prop] = styles[style].properties[prop];
1282 if (fontsel->style == style)
1285 fontsel->style = style;
1286 gtk_font_selection_show_available_sizes (fontsel);
1287 gtk_font_selection_select_best_size (fontsel);
1292 gtk_font_selection_toggle_scaled_bitmaps (GtkWidget *w,
1295 GtkFontSelection *fontsel;
1297 fontsel = GTK_FONT_SELECTION(data);
1299 fontsel->scale_bitmapped_fonts
1300 = GTK_TOGGLE_BUTTON(w)->active ? TRUE : FALSE;
1301 if (fontsel->font_index != -1)
1303 gtk_font_selection_show_available_sizes (fontsel);
1304 gtk_font_selection_select_best_size (fontsel);
1309 /* This shows all the available sizes in the size clist, according to the
1310 current metric and the current font & style. */
1312 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel)
1315 FontStyle *styles, *style;
1316 guint16 *standard_sizes, *bitmapped_sizes, bitmap_size;
1317 gint nstandard_sizes, nbitmapped_sizes;
1318 gchar buffer[16], *size;
1319 gfloat bitmap_size_float;
1322 #ifdef FONTSEL_DEBUG
1323 g_print("In show_available_sizes\n");
1325 font = &fontsel_info->font_info[fontsel->font_index];
1326 styles = &fontsel_info->font_styles[font->style_index];
1327 style = &styles[fontsel->style];
1329 standard_sizes = font_sizes;
1330 nstandard_sizes = sizeof(font_sizes) / sizeof(font_sizes[0]);
1331 if (fontsel->metric == POINTS_METRIC)
1333 bitmapped_sizes = &fontsel_info->point_sizes[style->point_sizes_index];
1334 nbitmapped_sizes = style->npoint_sizes;
1338 bitmapped_sizes = &fontsel_info->pixel_sizes[style->pixel_sizes_index];
1339 nbitmapped_sizes = style->npixel_sizes;
1342 if (!fontsel->scale_bitmapped_fonts && !(style->flags & SCALABLE_FONT))
1343 nstandard_sizes = 0;
1345 gtk_clist_freeze (GTK_CLIST(fontsel->size_clist));
1346 gtk_clist_clear (GTK_CLIST(fontsel->size_clist));
1348 /* Interleave the standard sizes with the bitmapped sizes so we get a list
1349 of ascending sizes. If the metric is points, we have to convert the
1350 decipoints to points. */
1351 while (nstandard_sizes || nbitmapped_sizes)
1354 if (fontsel->metric == POINTS_METRIC)
1356 if (*bitmapped_sizes % 10 != 0)
1358 bitmap_size = *bitmapped_sizes / 10;
1359 bitmap_size_float = *bitmapped_sizes / 10;
1363 bitmap_size = *bitmapped_sizes;
1364 bitmap_size_float = *bitmapped_sizes;
1367 if (can_match && nstandard_sizes && nbitmapped_sizes
1368 && *standard_sizes == bitmap_size)
1370 sprintf(buffer, "%i *", *standard_sizes);
1376 else if (nstandard_sizes
1377 && (!nbitmapped_sizes
1378 || (gfloat)*standard_sizes < bitmap_size_float))
1380 sprintf(buffer, "%i", *standard_sizes);
1386 if (fontsel->metric == POINTS_METRIC)
1388 if (*bitmapped_sizes % 10 == 0)
1389 sprintf(buffer, "%i *", *bitmapped_sizes / 10);
1391 sprintf(buffer, "%i.%i *", *bitmapped_sizes / 10,
1392 *bitmapped_sizes % 10);
1396 sprintf(buffer, "%i *", *bitmapped_sizes);
1402 gtk_clist_append(GTK_CLIST(fontsel->size_clist), &size);
1404 gtk_clist_thaw (GTK_CLIST(fontsel->size_clist));
1408 /* If the user hits return in the font size entry, we change to the new font
1411 gtk_font_selection_size_key_press (GtkWidget *w,
1415 GtkFontSelection *fontsel;
1417 gfloat new_size_float;
1420 #ifdef FONTSEL_DEBUG
1421 g_print("In size_key_press\n");
1423 fontsel = GTK_FONT_SELECTION(data);
1425 if (event->keyval == GDK_Return)
1427 text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1428 if (fontsel->metric == PIXELS_METRIC)
1430 new_size = atoi (text);
1436 new_size_float = atof (text) * 10;
1437 new_size = (gint) new_size_float;
1442 /* Remember that this size was set explicitly. */
1443 fontsel->selected_size = new_size;
1445 /* Check if the font size has changed, and return if it hasn't. */
1446 if (fontsel->size == new_size)
1449 fontsel->size = new_size;
1450 gtk_font_selection_select_best_size (fontsel);
1458 /* This tries to select the closest size to the current size, though it
1459 may have to change the size if only unscaled bitmaps are available.
1460 Note: this will load a font. */
1462 gtk_font_selection_select_best_size(GtkFontSelection *fontsel)
1465 FontStyle *styles, *style;
1467 gint row, best_row = 0, size, size_fraction, best_size = 0, nmatched;
1468 gboolean found = FALSE;
1472 #ifdef FONTSEL_DEBUG
1473 g_print("In select_best_size\n");
1475 font = &fontsel_info->font_info[fontsel->font_index];
1476 styles = &fontsel_info->font_styles[font->style_index];
1477 style = &styles[fontsel->style];
1479 /* Find the closest size available in the size clist. If the exact size is
1480 in the list set found to TRUE. */
1481 for (row = 0; row < GTK_CLIST(fontsel->size_clist)->rows; row++)
1483 gtk_clist_get_text(GTK_CLIST(fontsel->size_clist), row, 0, &text);
1484 nmatched = sscanf(text, "%i.%i", &size, &size_fraction);
1485 if (fontsel->metric == POINTS_METRIC)
1489 size += size_fraction;
1492 if (size == fontsel->selected_size)
1499 else if (best_size == 0
1500 || abs(size - fontsel->selected_size)
1501 < (abs(best_size - fontsel->selected_size)))
1508 /* If we aren't scaling bitmapped fonts and this is a bitmapped font, we
1509 need to use the closest size found. */
1510 if (!fontsel->scale_bitmapped_fonts && !(style->flags & SCALABLE_FONT))
1515 fontsel->size = best_size;
1516 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), best_row, -1, 0.5, 0);
1517 gtk_clist_select_row(GTK_CLIST(fontsel->size_clist), best_row, 0);
1521 fontsel->size = fontsel->selected_size;
1522 selection = GTK_CLIST(fontsel->size_clist)->selection;
1524 gtk_clist_unselect_row(GTK_CLIST(fontsel->size_clist),
1525 GPOINTER_TO_INT (selection->data), 0);
1526 gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), best_row, -1, 0.5, 0);
1528 /* Show the size in the size entry. */
1529 if (fontsel->metric == PIXELS_METRIC)
1530 sprintf(buffer, "%i", fontsel->size);
1533 if (fontsel->size % 10 == 0)
1534 sprintf(buffer, "%i", fontsel->size / 10);
1536 sprintf(buffer, "%i.%i", fontsel->size / 10, fontsel->size % 10);
1538 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
1540 gtk_font_selection_load_font (fontsel);
1544 /* This is called when a size is selected in the list. */
1546 gtk_font_selection_select_size (GtkWidget *w,
1549 GdkEventButton *bevent,
1552 GtkFontSelection *fontsel;
1558 #ifdef FONTSEL_DEBUG
1559 g_print("In select_size\n");
1561 fontsel = GTK_FONT_SELECTION(data);
1563 if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
1564 gtk_widget_grab_focus (w);
1566 /* Copy the size from the clist to the size entry, but without the bitmapped
1568 gtk_clist_get_text(GTK_CLIST(fontsel->size_clist), row, 0, &text);
1570 while (i < 15 && (text[i] == '.' || (text[i] >= '0' && text[i] <= '9')))
1572 buffer[i] = text[i];
1576 gtk_entry_set_text(GTK_ENTRY(fontsel->size_entry), buffer);
1578 /* Check if the font size has changed, and return if it hasn't. */
1579 new_size = atoi(text);
1580 if (fontsel->metric == POINTS_METRIC)
1583 if (fontsel->size == new_size)
1586 /* If the size was selected by the user we set the selected_size. */
1587 fontsel->selected_size = new_size;
1589 fontsel->size = new_size;
1590 gtk_font_selection_load_font (fontsel);
1594 /* This is called when the pixels or points radio buttons are pressed. */
1596 gtk_font_selection_metric_callback (GtkWidget *w,
1599 GtkFontSelection *fontsel = GTK_FONT_SELECTION(data);
1601 #ifdef FONTSEL_DEBUG
1602 g_print("In metric_callback\n");
1604 if (GTK_TOGGLE_BUTTON(fontsel->pixels_button)->active)
1606 if (fontsel->metric == PIXELS_METRIC)
1608 fontsel->metric = PIXELS_METRIC;
1609 fontsel->size = (fontsel->size + 5) / 10;
1610 fontsel->selected_size = (fontsel->selected_size + 5) / 10;
1614 if (fontsel->metric == POINTS_METRIC)
1616 fontsel->metric = POINTS_METRIC;
1617 fontsel->size *= 10;
1618 fontsel->selected_size *= 10;
1620 if (fontsel->font_index != -1)
1622 gtk_font_selection_show_available_sizes (fontsel);
1623 gtk_font_selection_select_best_size (fontsel);
1628 /* This searches the given property table and returns the index of the given
1629 string, or 0, which is the wildcard '*' index, if it's not found. */
1631 gtk_font_selection_field_to_index (gchar **table,
1637 for (i = 0; i < ntable; i++)
1638 if (strcmp (field, table[i]) == 0)
1646 /* This attempts to load the current font, and returns TRUE if it succeeds. */
1648 gtk_font_selection_load_font (GtkFontSelection *fontsel)
1651 gchar *fontname, *label_text;
1654 gdk_font_unref (fontsel->font);
1655 fontsel->font = NULL;
1657 /* If no family has been selected yet, just return FALSE. */
1658 if (fontsel->font_index == -1)
1661 fontname = gtk_font_selection_get_font_name (fontsel);
1664 #ifdef FONTSEL_DEBUG
1665 g_print("Loading: %s\n", fontname);
1667 font = gdk_font_load (fontname);
1672 fontsel->font = font;
1673 /* Make sure the message label is empty, but don't change it unless
1674 it's necessary as it results in a resize of the whole window! */
1675 gtk_label_get(GTK_LABEL(fontsel->message_label), &label_text);
1676 if (strcmp(label_text, ""))
1677 gtk_label_set(GTK_LABEL(fontsel->message_label), "");
1678 gtk_font_selection_update_preview (fontsel);
1683 gtk_label_set(GTK_LABEL(fontsel->message_label),
1684 "The selected font is not available.");
1689 gtk_label_set(GTK_LABEL(fontsel->message_label),
1690 "The selected font is not a valid font.");
1697 /* This sets the font in the preview entry to the selected font, and tries to
1698 make sure that the preview entry is a reasonable size, i.e. so that the
1699 text can be seen with a bit of space to spare. But it tries to avoid
1700 resizing the entry every time the font changes.
1701 This also used to shrink the preview if the font size was decreased, but
1702 that made it awkward if the user wanted to resize the window themself. */
1704 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1706 GtkWidget *preview_entry;
1708 gint text_height, new_height;
1712 #ifdef FONTSEL_DEBUG
1713 g_print("In update_preview\n");
1715 style = gtk_style_new ();
1716 gdk_font_unref (style->font);
1717 style->font = fontsel->font;
1718 gdk_font_ref (style->font);
1720 preview_entry = fontsel->preview_entry;
1721 gtk_widget_set_style (preview_entry, style);
1722 gtk_style_unref(style);
1724 text_height = preview_entry->style->font->ascent
1725 + preview_entry->style->font->descent;
1726 /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1727 new_height = text_height + 20;
1728 if (new_height < INITIAL_PREVIEW_HEIGHT)
1729 new_height = INITIAL_PREVIEW_HEIGHT;
1730 if (new_height > MAX_PREVIEW_HEIGHT)
1731 new_height = MAX_PREVIEW_HEIGHT;
1733 if ((preview_entry->requisition.height < text_height + 10)
1734 || (preview_entry->requisition.height > text_height + 40))
1735 gtk_widget_set_usize(preview_entry, -1, new_height);
1737 /* This sets the preview text, if it hasn't been set already. */
1738 text = gtk_entry_get_text(GTK_ENTRY(fontsel->preview_entry));
1739 if (strlen(text) == 0)
1740 gtk_entry_set_text(GTK_ENTRY(fontsel->preview_entry), PREVIEW_TEXT);
1741 gtk_entry_set_position(GTK_ENTRY(fontsel->preview_entry), 0);
1743 /* If this is a 2-byte font display a message to say it may not be
1744 displayed properly. */
1745 xfs = GDK_FONT_XFONT(fontsel->font);
1746 if (xfs->min_byte1 != 0 || xfs->max_byte1 != 0)
1747 gtk_label_set(GTK_LABEL(fontsel->message_label),
1748 "This is a 2-byte font and may not be displayed correctly.");
1753 gtk_font_selection_switch_page (GtkWidget *w,
1754 GtkNotebookPage *page,
1758 GtkFontSelection *fontsel = GTK_FONT_SELECTION(data);
1760 /* This function strangely gets called when the window is destroyed,
1761 so we check here to see if the notebook is visible. */
1762 if (!GTK_WIDGET_VISIBLE(w))
1766 gtk_font_selection_filter_fonts(fontsel);
1767 else if (page_num == 1)
1768 gtk_font_selection_show_font_info(fontsel);
1773 gtk_font_selection_show_font_info (GtkFontSelection *fontsel)
1775 Atom font_atom, atom;
1779 gchar field_buffer[XLFD_MAX_FIELD_LEN];
1782 gboolean shown_actual_fields = FALSE;
1784 fontname = gtk_font_selection_get_font_name(fontsel);
1785 gtk_entry_set_text(GTK_ENTRY(fontsel->requested_font_name),
1786 fontname ? fontname : "");
1788 gtk_clist_freeze (GTK_CLIST(fontsel->info_clist));
1789 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1792 field = gtk_font_selection_get_xlfd_field (fontname, i, field_buffer);
1797 if (i == XLFD_SLANT)
1798 field = gtk_font_selection_expand_slant_code(field);
1799 else if (i == XLFD_SPACING)
1800 field = gtk_font_selection_expand_spacing_code(field);
1802 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 1,
1803 field ? field : "");
1808 font_atom = XInternAtom(GDK_DISPLAY(), "FONT", True);
1809 if (font_atom != None)
1811 status = XGetFontProperty(GDK_FONT_XFONT(fontsel->font), font_atom,
1815 name = XGetAtomName(GDK_DISPLAY(), atom);
1816 gtk_entry_set_text(GTK_ENTRY(fontsel->actual_font_name), name);
1818 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1820 field = gtk_font_selection_get_xlfd_field (name, i,
1822 if (i == XLFD_SLANT)
1823 field = gtk_font_selection_expand_slant_code(field);
1824 else if (i == XLFD_SPACING)
1825 field = gtk_font_selection_expand_spacing_code(field);
1826 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 2,
1827 field ? field : "");
1829 shown_actual_fields = TRUE;
1834 if (!shown_actual_fields)
1836 gtk_entry_set_text(GTK_ENTRY(fontsel->actual_font_name), "");
1837 for (i = 0; i < GTK_XLFD_NUM_FIELDS; i++)
1839 gtk_clist_set_text(GTK_CLIST(fontsel->info_clist), i, 2,
1840 fontname ? "(unknown)" : "");
1843 gtk_clist_thaw (GTK_CLIST(fontsel->info_clist));
1849 gtk_font_selection_expand_slant_code(gchar *slant)
1851 if (!g_strcasecmp(slant, "r")) return("roman");
1852 else if (!g_strcasecmp(slant, "i")) return("italic");
1853 else if (!g_strcasecmp(slant, "o")) return("oblique");
1854 else if (!g_strcasecmp(slant, "ri")) return("reverse italic");
1855 else if (!g_strcasecmp(slant, "ro")) return("reverse oblique");
1856 else if (!g_strcasecmp(slant, "ot")) return("other");
1861 gtk_font_selection_expand_spacing_code(gchar *spacing)
1863 if (!g_strcasecmp(spacing, "p")) return("proportional");
1864 else if (!g_strcasecmp(spacing, "m")) return("monospaced");
1865 else if (!g_strcasecmp(spacing, "c")) return("char cell");
1870 /*****************************************************************************
1871 * These functions all deal with the Filter page.
1872 *****************************************************************************/
1874 /* This is called when an item is selected in one of the filter clists.
1875 We make sure that the first row of the clist, i.e. the wildcard '*', is
1876 selected if and only if none of the other items are selected.
1877 We may need to be careful about triggering other signals. */
1879 gtk_font_selection_select_filter (GtkWidget *w,
1882 GdkEventButton *bevent,
1888 for (i = 1; i < GTK_CLIST(w)->rows; i++)
1889 gtk_clist_unselect_row(GTK_CLIST(w), i, 0);
1891 gtk_clist_unselect_row(GTK_CLIST(w), 0, 0);
1895 /* Here a filter item is being deselected. If there are now no items selected
1896 we select the first '*' item, unless that it is the item being deselected,
1897 in which case we select all of the other items. This makes it easy to
1898 select all items in the list except one or two. */
1900 gtk_font_selection_unselect_filter (GtkWidget *w,
1903 GdkEventButton *bevent,
1907 if (!GTK_CLIST(w)->selection)
1910 for (i = 1; i < GTK_CLIST(w)->rows; i++)
1911 gtk_clist_select_row(GTK_CLIST(w), i, 0);
1913 gtk_clist_select_row(GTK_CLIST(w), 0, 0);
1918 /* This is called when the main notebook page is selected. It checks if the
1919 filter has changed, an if so it creates the filter settings, and filters the
1920 fonts shown. If an empty filter (all '*'s) is applied, then filtering is
1923 gtk_font_selection_filter_fonts (GtkFontSelection *fontsel)
1927 gboolean empty_filter = TRUE, filter_changed = FALSE;
1928 gint prop, nselected, i, row, index;
1930 #ifdef FONTSEL_DEBUG
1931 g_print("In filter_fonts\n");
1934 /* Check if the filter has changed, and also if it is an empty filter,
1935 i.e. all '*'s are selected. */
1936 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
1938 clist = fontsel->filter_clists[prop];
1939 selection = GTK_CLIST(clist)->selection;
1940 nselected = g_list_length(selection);
1941 if (nselected != 1 || GPOINTER_TO_INT (selection->data) != 0)
1943 empty_filter = FALSE;
1945 if (fontsel->property_nfilters[prop] != nselected)
1946 filter_changed = TRUE;
1949 for (i = 0; i < nselected; i++)
1951 row = GPOINTER_TO_INT (selection->data);
1952 index = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (clist), row));
1953 if (fontsel->property_filters[prop][i] != index)
1954 filter_changed = TRUE;
1955 selection = selection->next;
1961 if (fontsel->property_nfilters[prop] != 0)
1962 filter_changed = TRUE;
1966 /* If the filter hasn't changed we just return. */
1967 if (!filter_changed)
1970 #ifdef FONTSEL_DEBUG
1971 g_print(" filter_fonts: filter has changed\n");
1974 /* Setting the toggle buttons state will trigger the callbacks to clear
1975 or apply the filter, unless the font list is already filtered, in
1976 which case we have to call apply_filter here. */
1979 gtk_widget_set_sensitive(fontsel->filter_button, FALSE);
1980 gtk_label_set(GTK_LABEL(fontsel->font_label), "Font:");
1981 gtk_font_selection_apply_filter(fontsel);
1985 gtk_widget_set_sensitive(fontsel->filter_button, TRUE);
1986 gtk_label_set(GTK_LABEL(fontsel->font_label), "Font: [Filtered]");
1987 gtk_font_selection_apply_filter(fontsel);
1992 /* This clears the filter, showing all fonts and styles again. */
1994 gtk_font_selection_apply_filter (GtkFontSelection *fontsel)
1996 FontInfo *font_info, *font;
1999 gint nfonts, prop, nselected, i, j, row, style, index;
2000 gchar font_buffer[XLFD_MAX_FIELD_LEN * 2 + 4];
2002 gboolean matched, matched_style;
2004 #ifdef FONTSEL_DEBUG
2005 g_print("In apply_filter\n");
2007 font_info = fontsel_info->font_info;
2008 nfonts = fontsel_info->nfonts;
2010 /* Free the old filter data and create the new arrays. */
2011 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2013 g_free(fontsel->property_filters[prop]);
2015 clist = fontsel->filter_clists[prop];
2016 selection = GTK_CLIST(clist)->selection;
2017 nselected = g_list_length(selection);
2018 if (nselected == 1 && GPOINTER_TO_INT (selection->data) == 0)
2020 fontsel->property_filters[prop] = NULL;
2021 fontsel->property_nfilters[prop] = 0;
2025 fontsel->property_filters[prop] = g_new(guint16, nselected);
2026 fontsel->property_nfilters[prop] = nselected;
2027 for (i = 0; i < nselected; i++)
2029 row = GPOINTER_TO_INT (selection->data);
2030 index = GPOINTER_TO_INT (gtk_clist_get_row_data (GTK_CLIST (clist), row));
2031 fontsel->property_filters[prop][i] = index;
2032 selection = selection->next;
2037 /* Filter the list of fonts. */
2038 gtk_clist_freeze (GTK_CLIST(fontsel->font_clist));
2039 gtk_clist_clear (GTK_CLIST(fontsel->font_clist));
2040 for (i = 0; i < nfonts; i++)
2042 font = &font_info[i];
2044 /* Check if the foundry matches. */
2045 if (fontsel->property_nfilters[FOUNDRY] != 0)
2048 for (j = 0; j < fontsel->property_nfilters[FOUNDRY]; j++)
2050 if (font->foundry == fontsel->property_filters[FOUNDRY][j])
2060 /* Now check if the other properties are matched in at least one style.*/
2061 matched_style = FALSE;
2062 for (style = 0; style < font->nstyles; style++)
2064 if (gtk_font_selection_style_visible(fontsel, font, style))
2066 matched_style = TRUE;
2073 /* Insert the font in the clist. */
2074 if ((i > 0 && font->family == font_info[i-1].family)
2075 || (i < nfonts - 1 && font->family == font_info[i+1].family))
2077 sprintf(font_buffer, "%s (%s)", font->family,
2078 fontsel_info->properties[FOUNDRY][font->foundry]);
2079 font_item = font_buffer;
2080 row = gtk_clist_append(GTK_CLIST(fontsel->font_clist), &font_item);
2084 row = gtk_clist_append(GTK_CLIST(fontsel->font_clist),
2087 gtk_clist_set_row_data(GTK_CLIST(fontsel->font_clist), row,
2088 GINT_TO_POINTER (i));
2090 gtk_clist_thaw (GTK_CLIST(fontsel->font_clist));
2092 /* Clear the current font and the style clist. */
2093 fontsel->font_index = -1;
2095 gdk_font_unref(fontsel->font);
2096 fontsel->font = NULL;
2097 gtk_entry_set_text(GTK_ENTRY(fontsel->font_entry), "");
2098 gtk_clist_clear (GTK_CLIST(fontsel->font_style_clist));
2099 gtk_entry_set_text(GTK_ENTRY(fontsel->font_style_entry), "");
2103 /* Returns TRUE if the style is not currently filtered out. */
2105 gtk_font_selection_style_visible(GtkFontSelection *fontsel,
2114 styles = &fontsel_info->font_styles[font->style_index];
2116 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2118 value = styles[style].properties[prop];
2120 if (fontsel->property_nfilters[prop] != 0)
2123 for (j = 0; j < fontsel->property_nfilters[prop]; j++)
2125 if (value == fontsel->property_filters[prop][j])
2139 /* This resets all the filter clists to the wildcard '*' options. */
2141 gtk_font_selection_reset_filter (GtkWidget *w,
2144 GtkFontSelection *fontsel;
2147 fontsel = GTK_FONT_SELECTION(data);
2149 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2150 gtk_clist_select_row(GTK_CLIST(fontsel->filter_clists[prop]), 0, 0);
2154 /* This clears the filter, showing all fonts and styles again. */
2156 gtk_font_selection_on_clear_filter (GtkWidget *w,
2159 GtkFontSelection *fontsel;
2161 fontsel = GTK_FONT_SELECTION(data);
2162 gtk_font_selection_clear_filter(fontsel);
2166 /* This clears the filter, showing all fonts and styles again. */
2168 gtk_font_selection_clear_filter (GtkFontSelection *fontsel)
2170 gboolean filtered = FALSE, found_style = FALSE;
2171 gint prop, row, style;
2173 #ifdef FONTSEL_DEBUG
2174 g_print("In clear_filter\n");
2176 /* Clear the filter data. */
2177 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2179 if (fontsel->property_filters[prop])
2181 g_free(fontsel->property_filters[prop]);
2182 fontsel->property_filters[prop] = NULL;
2183 fontsel->property_nfilters[prop] = 0;
2186 /* Select all the '*'s on the filter page. */
2187 gtk_font_selection_reset_filter(NULL, fontsel);
2189 /* Update the main notebook page. */
2190 gtk_widget_set_sensitive(fontsel->filter_button, FALSE);
2191 gtk_label_set(GTK_LABEL(fontsel->font_label), "Font:");
2193 /* If there is no filter at present just return. */
2197 gtk_font_selection_insert_fonts(fontsel);
2199 /* Now find the current font & style and select them again. */
2200 if (fontsel->font_index != -1)
2202 gtk_clist_select_row(GTK_CLIST(fontsel->font_clist),
2203 fontsel->font_index, 0);
2204 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_clist),
2205 fontsel->font_index) != GTK_VISIBILITY_FULL)
2206 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), fontsel->font_index,
2208 gtk_font_selection_show_available_styles (fontsel);
2210 for (row = 0; row < GTK_CLIST(fontsel->font_style_clist)->rows; row++)
2212 style = GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(fontsel->font_style_clist), row));
2213 if (style == fontsel->style)
2222 gtk_clist_select_row(GTK_CLIST(fontsel->font_style_clist),
2224 if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_style_clist),
2225 row) != GTK_VISIBILITY_FULL)
2226 gtk_clist_moveto(GTK_CLIST(fontsel->font_style_clist), row,
2233 /*****************************************************************************
2234 * These functions all deal with creating the main class arrays containing
2235 * the data about all available fonts.
2236 *****************************************************************************/
2238 gtk_font_selection_get_fonts (void)
2245 gint i, prop, style, size;
2246 gint npixel_sizes = 0, npoint_sizes = 0;
2248 FontStyle *current_style, *prev_style, *tmp_style;
2249 gboolean matched_style, found_size;
2250 gint pixels, points, res_x, res_y;
2251 gchar field_buffer[XLFD_MAX_FIELD_LEN];
2254 guint16 *pixel_sizes, *point_sizes, *tmp_sizes;
2256 fontsel_info = g_new (GtkFontSelInfo, 1);
2258 /* Get a maximum of MAX_FONTS fontnames from the X server.
2259 Use "-*" as the pattern rather than "-*-*-*-*-*-*-*-*-*-*-*-*-*-*" since
2260 the latter may result in fonts being returned which don't actually exist.
2261 xlsfonts also uses "*" so I think it's OK. "-*" gets rid of aliases. */
2262 xfontnames = XListFonts (GDK_DISPLAY(), "-*", MAX_FONTS, &num_fonts);
2263 /* Output a warning if we actually get MAX_FONTS fonts. */
2264 if (num_fonts == MAX_FONTS)
2265 g_warning("MAX_FONTS exceeded. Some fonts may be missing.");
2267 /* The maximum size of all these tables is the number of font names
2268 returned. We realloc them later when we know exactly how many
2269 unique entries there are. */
2270 fontsel_info->font_info = g_new (FontInfo, num_fonts);
2271 fontsel_info->font_styles = g_new (FontStyle, num_fonts);
2272 fontsel_info->pixel_sizes = g_new (guint16, num_fonts);
2273 fontsel_info->point_sizes = g_new (guint16, num_fonts);
2275 fontnames = g_new (GSList*, num_fonts);
2277 /* Create the initial arrays for the property value strings, though they
2278 may be realloc'ed later. Put the wildcard '*' in the first elements. */
2279 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2281 fontsel_info->properties[prop] = g_new(gchar*, PROPERTY_ARRAY_INCREMENT);
2282 fontsel_info->space_allocated[prop] = PROPERTY_ARRAY_INCREMENT;
2283 fontsel_info->nproperties[prop] = 1;
2284 fontsel_info->properties[prop][0] = "*";
2288 /* Insert the font families into the main table, sorted by family and
2289 foundry (fonts with different foundries are placed in seaparate FontInfos.
2290 All fontnames in each family + foundry are placed into the fontnames
2292 fontsel_info->nfonts = 0;
2293 for (i = 0; i < num_fonts; i++)
2295 #ifdef FONTSEL_DEBUG
2296 g_print("%s\n", xfontnames[i]);
2298 if (gtk_font_selection_is_xlfd_font_name (xfontnames[i]))
2299 gtk_font_selection_insert_font (fontnames, &fontsel_info->nfonts, xfontnames[i]);
2302 #ifdef FONTSEL_DEBUG
2303 g_warning("Skipping invalid font: %s", xfontnames[i]);
2309 /* Since many font names will be in the same FontInfo not all of the
2310 allocated FontInfo table will be used, so we will now reallocate it
2311 with the real size. */
2312 fontsel_info->font_info = g_realloc(fontsel_info->font_info,
2313 sizeof(FontInfo) * fontsel_info->nfonts);
2316 /* Now we work out which choices of weight/slant etc. are valid for each
2318 fontsel_info->nstyles = 0;
2319 current_style = fontsel_info->font_styles;
2320 for (i = 0; i < fontsel_info->nfonts; i++)
2322 font = &fontsel_info->font_info[i];
2324 /* Use the next free position in the styles array. */
2325 font->style_index = fontsel_info->nstyles;
2327 /* Now step through each of the fontnames with this family, and create
2328 a style for each fontname. Each style contains the index into the
2329 weights/slants etc. arrays, and a number of pixel/point sizes. */
2331 temp_list = fontnames[i];
2334 fontname = temp_list->data;
2335 temp_list = temp_list->next;
2337 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2339 current_style->properties[prop]
2340 = gtk_font_selection_insert_field (fontname, prop);
2342 current_style->pixel_sizes_index = npixel_sizes;
2343 current_style->point_sizes_index = npoint_sizes;
2344 current_style->flags = 0;
2347 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_PIXELS,
2349 pixels = atoi(field);
2351 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_POINTS,
2353 points = atoi(field);
2355 field = gtk_font_selection_get_xlfd_field (fontname,
2358 res_x = atoi(field);
2360 field = gtk_font_selection_get_xlfd_field (fontname,
2363 res_y = atoi(field);
2365 if (pixels == 0 && points == 0)
2366 if (res_x == 0 && res_y == 0)
2367 flags = SCALABLE_FONT;
2370 flags = SCALABLE_BITMAP_FONT;
2371 fontsel_info->scaled_bitmaps_available = TRUE;
2374 flags = BITMAP_FONT;
2376 /* Now we check to make sure that the style is unique. If it isn't
2378 prev_style = fontsel_info->font_styles + font->style_index;
2379 matched_style = FALSE;
2380 while (prev_style < current_style)
2382 matched_style = TRUE;
2383 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2385 if (prev_style->properties[prop]
2386 != current_style->properties[prop])
2388 matched_style = FALSE;
2397 /* If we matched an existing style, we need to add the pixels &
2398 point sizes to the style. If not, we insert the pixel & point
2399 sizes into our new style. Note that we don't add sizes for
2403 prev_style->flags |= flags;
2404 if (flags == BITMAP_FONT)
2406 pixel_sizes = fontsel_info->pixel_sizes
2407 + prev_style->pixel_sizes_index;
2409 for (size = 0; size < prev_style->npixel_sizes; size++)
2411 if (pixels == *pixel_sizes)
2416 else if (pixels < *pixel_sizes)
2420 /* We need to move all the following pixel sizes up, and also
2421 update the indexes of any following styles. */
2424 for (tmp_sizes = fontsel_info->pixel_sizes + npixel_sizes;
2425 tmp_sizes > pixel_sizes; tmp_sizes--)
2426 *tmp_sizes = *(tmp_sizes - 1);
2428 *pixel_sizes = pixels;
2430 prev_style->npixel_sizes++;
2432 tmp_style = prev_style + 1;
2433 while (tmp_style < current_style)
2435 tmp_style->pixel_sizes_index++;
2440 point_sizes = fontsel_info->point_sizes
2441 + prev_style->point_sizes_index;
2443 for (size = 0; size < prev_style->npoint_sizes; size++)
2445 if (points == *point_sizes)
2450 else if (points < *point_sizes)
2454 /* We need to move all the following point sizes up, and also
2455 update the indexes of any following styles. */
2458 for (tmp_sizes = fontsel_info->point_sizes + npoint_sizes;
2459 tmp_sizes > point_sizes; tmp_sizes--)
2460 *tmp_sizes = *(tmp_sizes - 1);
2462 *point_sizes = points;
2464 prev_style->npoint_sizes++;
2466 tmp_style = prev_style + 1;
2467 while (tmp_style < current_style)
2469 tmp_style->point_sizes_index++;
2477 current_style->flags = flags;
2478 if (flags == BITMAP_FONT)
2480 fontsel_info->pixel_sizes[npixel_sizes++] = pixels;
2481 current_style->npixel_sizes = 1;
2482 fontsel_info->point_sizes[npoint_sizes++] = points;
2483 current_style->npoint_sizes = 1;
2486 fontsel_info->nstyles++;
2490 g_slist_free(fontnames[i]);
2492 /* Set nstyles to the real value, minus duplicated fontnames.
2493 Note that we aren't using all the allocated memory if fontnames are
2495 font->nstyles = style;
2498 /* Since some repeated styles may be skipped we won't have used all the
2499 allocated space, so we will now reallocate it with the real size. */
2500 fontsel_info->font_styles = g_realloc(fontsel_info->font_styles,
2501 sizeof(FontStyle) * fontsel_info->nstyles);
2502 fontsel_info->pixel_sizes = g_realloc(fontsel_info->pixel_sizes,
2503 sizeof(guint16) * npixel_sizes);
2504 fontsel_info->point_sizes = g_realloc(fontsel_info->point_sizes,
2505 sizeof(guint16) * npoint_sizes);
2507 XFreeFontNames (xfontnames);
2510 /* Debugging Output */
2511 /* This outputs all FontInfos. */
2512 #ifdef FONTSEL_DEBUG
2513 g_print("\n\n Font Family Weight Slant Set Width Spacing Charset\n\n");
2514 for (i = 0; i < fontsel_info->nfonts; i++)
2516 FontInfo *font = &fontsel_info->font_info[i];
2517 FontStyle *styles = fontsel_info->font_styles + font->style_index;
2518 for (style = 0; style < font->nstyles; style++)
2520 g_print("%5i %-16.16s ", i, font->family);
2521 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2523 fontsel_info->properties[prop][styles->properties[prop]]);
2526 if (styles->flags & BITMAP_FONT)
2527 g_print("Bitmapped font ");
2528 if (styles->flags & SCALABLE_FONT)
2529 g_print("Scalable font ");
2530 if (styles->flags & SCALABLE_BITMAP_FONT)
2531 g_print("Scalable-Bitmapped font ");
2534 if (styles->npixel_sizes)
2536 g_print(" Pixel sizes: ");
2537 tmp_sizes = fontsel_info->pixel_sizes + styles->pixel_sizes_index;
2538 for (size = 0; size < styles->npixel_sizes; size++)
2539 g_print("%i ", *tmp_sizes++);
2543 if (styles->npoint_sizes)
2545 g_print(" Point sizes: ");
2546 tmp_sizes = fontsel_info->point_sizes + styles->point_sizes_index;
2547 for (size = 0; size < styles->npoint_sizes; size++)
2548 g_print("%i ", *tmp_sizes++);
2556 /* This outputs all available properties. */
2557 for (prop = 0; prop < GTK_NUM_FONT_PROPERTIES; prop++)
2559 g_print("Property: %s\n", xlfd_field_names[xlfd_index[prop]]);
2560 for (i = 0; i < fontsel_info->nproperties[prop]; i++)
2561 g_print(" %s\n", fontsel_info->properties[prop][i]);
2566 /* This inserts the given fontname into the FontInfo table.
2567 If a FontInfo already exists with the same family and foundry, then the
2568 fontname is added to the FontInfos list of fontnames, else a new FontInfo
2569 is created and inserted in alphabetical order in the table. */
2571 gtk_font_selection_insert_font (GSList *fontnames[],
2577 GSList *temp_fontname;
2579 gboolean family_exists = FALSE;
2583 gchar family_buffer[XLFD_MAX_FIELD_LEN];
2585 table = fontsel_info->font_info;
2587 /* insert a fontname into a table */
2588 family = gtk_font_selection_get_xlfd_field (fontname, XLFD_FAMILY,
2593 foundry = gtk_font_selection_insert_field (fontname, FOUNDRY);
2598 /* Do a binary search to determine if we have already encountered
2599 * a font with this family & foundry. */
2601 while (lower < upper)
2603 middle = (lower + upper) >> 1;
2605 cmp = strcmp (family, table[middle].family);
2606 /* If the family matches we sort by the foundry. */
2609 family_exists = TRUE;
2610 family = table[middle].family;
2611 cmp = strcmp(fontsel_info->properties[FOUNDRY][foundry],
2612 fontsel_info->properties[FOUNDRY][table[middle].foundry]);
2617 fontnames[middle] = g_slist_prepend (fontnames[middle],
2628 /* Add another entry to the table for this new font family */
2629 temp_info.family = family_exists ? family : g_strdup(family);
2630 temp_info.foundry = foundry;
2631 temp_fontname = g_slist_prepend (NULL, fontname);
2635 /* Quickly insert the entry into the table in sorted order
2636 * using a modification of insertion sort and the knowledge
2637 * that the entries proper position in the table was determined
2638 * above in the binary search and is contained in the "lower"
2642 upper = *ntable - 1;
2643 while (lower != upper)
2645 table[upper] = table[upper-1];
2646 fontnames[upper] = fontnames[upper-1];
2650 table[lower] = temp_info;
2651 fontnames[lower] = temp_fontname;
2655 /* This checks that the specified field of the given fontname is in the
2656 appropriate properties array. If not it is added. Thus eventually we get
2657 arrays of all possible weights/slants etc. It returns the array index. */
2659 gtk_font_selection_insert_field (gchar *fontname,
2662 gchar field_buffer[XLFD_MAX_FIELD_LEN];
2666 field = gtk_font_selection_get_xlfd_field (fontname, xlfd_index[prop],
2671 /* If the field is already in the array just return its index. */
2672 for (index = 0; index < fontsel_info->nproperties[prop]; index++)
2673 if (!strcmp(field, fontsel_info->properties[prop][index]))
2676 /* Make sure we have enough space to add the field. */
2677 if (fontsel_info->nproperties[prop] == fontsel_info->space_allocated[prop])
2679 fontsel_info->space_allocated[prop] += PROPERTY_ARRAY_INCREMENT;
2680 fontsel_info->properties[prop] = g_realloc(fontsel_info->properties[prop],
2682 * fontsel_info->space_allocated[prop]);
2685 /* Add the new field. */
2686 index = fontsel_info->nproperties[prop];
2687 fontsel_info->properties[prop][index] = g_strdup(field);
2688 fontsel_info->nproperties[prop]++;
2693 /*****************************************************************************
2694 * These functions are the main public interface for getting/setting the font.
2695 *****************************************************************************/
2698 gtk_font_selection_get_font (GtkFontSelection *fontsel)
2700 g_return_val_if_fail (fontsel != NULL, NULL);
2701 return fontsel->font;
2706 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
2709 gchar *family_str, *foundry_str;
2710 gchar *property_str[GTK_NUM_STYLE_PROPERTIES];
2713 g_return_val_if_fail (fontsel != NULL, NULL);
2714 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
2716 /* If no family has been selected return NULL. */
2717 if (fontsel->font_index == -1)
2720 font = &fontsel_info->font_info[fontsel->font_index];
2721 family_str = font->family;
2722 foundry_str = fontsel_info->properties[FOUNDRY][font->foundry];
2724 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2727 = fontsel_info->properties[prop][fontsel->property_values[prop]];
2728 if (strcmp (property_str[prop], "(nil)") == 0)
2729 property_str[prop] = "";
2732 return gtk_font_selection_create_xlfd (fontsel->size,
2736 property_str[WEIGHT],
2737 property_str[SLANT],
2738 property_str[SET_WIDTH],
2739 property_str[SPACING],
2740 property_str[CHARSET]);
2744 /* This returns the style with the best match to the current fontsel setting */
2746 gtk_font_selection_get_best_match(GtkFontSelection *fontsel)
2750 gint prop, style, best_style = 0, matched, best_matched = 0;
2752 font = &fontsel_info->font_info[fontsel->font_index];
2753 styles = &fontsel_info->font_styles[font->style_index];
2755 /* Find the style with the most matches. */
2756 for (style = 0; style < font->nstyles; style++)
2759 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2761 if (fontsel->property_values[prop] == styles[style].properties[prop])
2764 if (matched > best_matched)
2766 best_matched = matched;
2775 /* This sets the current font, selecting the appropriate clist rows.
2776 First we check the fontname is valid and try to find the font family
2777 - i.e. the name in the main list. If we can't find that, then just return.
2778 Next we try to set each of the properties according to the fontname.
2779 Finally we select the font family & style in the clists. */
2781 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
2782 const gchar *fontname)
2784 gchar *family, *field;
2785 gint index, prop, size;
2786 guint16 foundry, value;
2787 gchar family_buffer[XLFD_MAX_FIELD_LEN];
2788 gchar field_buffer[XLFD_MAX_FIELD_LEN];
2791 g_return_val_if_fail (fontsel != NULL, FALSE);
2792 g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
2793 g_return_val_if_fail (fontname != NULL, FALSE);
2795 /* Check it is a valid fontname. */
2796 if (!gtk_font_selection_is_xlfd_font_name(fontname))
2799 family = gtk_font_selection_get_xlfd_field (fontname, XLFD_FAMILY,
2804 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_FOUNDRY,
2806 foundry = gtk_font_selection_field_to_index (fontsel_info->properties[FOUNDRY],
2807 fontsel_info->nproperties[FOUNDRY],
2810 index = gtk_font_selection_find_font(fontsel, family, foundry);
2814 /* Convert the property fields into indices and set them. */
2815 for (prop = 0; prop < GTK_NUM_STYLE_PROPERTIES; prop++)
2817 field = gtk_font_selection_get_xlfd_field (fontname, xlfd_index[prop],
2819 value = gtk_font_selection_field_to_index (fontsel_info->properties[prop],
2820 fontsel_info->nproperties[prop],
2822 fontsel->property_values[prop] = value;
2825 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_POINTS,
2832 fontsel->size = fontsel->selected_size = size;
2833 fontsel->metric = POINTS_METRIC;
2834 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->points_button),
2837 sprintf (buffer, "%i", size / 10);
2839 sprintf (buffer, "%i.%i", size / 10, size % 10);
2843 field = gtk_font_selection_get_xlfd_field (fontname, XLFD_PIXELS,
2848 fontsel->size = fontsel->selected_size = size;
2849 fontsel->metric = PIXELS_METRIC;
2850 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(fontsel->pixels_button),
2852 sprintf (buffer, "%i", size);
2854 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
2856 /* Clear any current filter. */
2857 gtk_font_selection_clear_filter(fontsel);
2859 /* Now find the best style match. */
2860 fontsel->font_index = index;
2861 gtk_clist_select_row(GTK_CLIST(fontsel->font_clist), index, 0);
2862 if (GTK_WIDGET_MAPPED (fontsel->font_clist))
2863 gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), index, -1, 0.5, 0);
2865 fontsel->scroll_on_expose = TRUE;
2867 gtk_font_selection_show_available_styles (fontsel);
2868 /* This will load the font. */
2869 gtk_font_selection_select_best_style (fontsel, FALSE);
2875 /* Returns the index of the given family, or -1 if not found */
2877 gtk_font_selection_find_font (GtkFontSelection *fontsel,
2881 FontInfo *font_info;
2882 gint lower, upper, middle = -1, cmp, nfonts;
2884 font_info = fontsel_info->font_info;
2885 nfonts = fontsel_info->nfonts;
2889 /* Do a binary search to find the font family. */
2892 while (lower < upper)
2894 middle = (lower + upper) >> 1;
2896 cmp = strcmp (family, font_info[middle].family);
2898 cmp = strcmp(fontsel_info->properties[FOUNDRY][foundry],
2899 fontsel_info->properties[FOUNDRY][font_info[middle].foundry]);
2909 /* If we can't match family & foundry see if just the family matches */
2910 if (!strcmp (family, font_info[middle].family))
2917 /* This returns the text in the preview entry. You should copy the returned
2918 text if you need it. */
2920 gtk_font_selection_get_preview_text (GtkFontSelection *fontsel)
2922 return gtk_entry_get_text(GTK_ENTRY(fontsel->preview_entry));
2926 /* This sets the text in the preview entry. */
2928 gtk_font_selection_set_preview_text (GtkFontSelection *fontsel,
2931 gtk_entry_set_text(GTK_ENTRY(fontsel->preview_entry), text);
2935 /*****************************************************************************
2936 * These functions all deal with X Logical Font Description (XLFD) fontnames.
2937 * See the freely available documentation about this.
2938 *****************************************************************************/
2941 * Returns TRUE if the fontname is a valid XLFD.
2942 * (It just checks if the number of dashes is 14, and that each
2943 * field < XLFD_MAX_FIELD_LEN characters long - that's not in the XLFD but it
2944 * makes it easier for me).
2947 gtk_font_selection_is_xlfd_font_name (const gchar *fontname)
2954 if (*fontname++ == '-')
2956 if (field_len > XLFD_MAX_FIELD_LEN) return FALSE;
2964 return (i == 14) ? TRUE : FALSE;
2968 * This fills the buffer with the specified field from the X Logical Font
2969 * Description name, and returns it. If fontname is NULL or the field is
2970 * longer than XFLD_MAX_FIELD_LEN it returns NULL.
2971 * Note: For the charset field, we also return the encoding, e.g. 'iso8859-1'.
2974 gtk_font_selection_get_xlfd_field (const gchar *fontname,
2975 FontField field_num,
2978 const gchar *t1, *t2;
2979 gint countdown, len, num_dashes;
2984 /* we assume this is a valid fontname...that is, it has 14 fields */
2986 countdown = field_num;
2988 while (*t1 && (countdown >= 0))
2992 num_dashes = (field_num == XLFD_CHARSET) ? 2 : 1;
2993 for (t2 = t1; *t2; t2++)
2995 if (*t2 == '-' && --num_dashes == 0)
3001 /* Check we don't overflow the buffer */
3002 len = (long) t2 - (long) t1;
3003 if (len > XLFD_MAX_FIELD_LEN - 1)
3005 strncpy (buffer, t1, len);
3009 strcpy(buffer, "(nil)");
3015 * This returns a X Logical Font Description font name, given all the pieces.
3016 * Note: this retval must be freed by the caller.
3019 gtk_font_selection_create_xlfd (gint size,
3020 GtkFontMetricType metric,
3030 gchar *pixel_size = "*", *point_size = "*", *fontname;
3036 sprintf (buffer, "%d", (int) size);
3037 if (metric == PIXELS_METRIC)
3038 pixel_size = buffer;
3040 point_size = buffer;
3042 /* Note: be careful here - don't overrun the allocated memory. */
3043 length = strlen(foundry) + strlen(family) + strlen(weight) + strlen(slant)
3044 + strlen(set_width) + strlen(pixel_size) + strlen(point_size)
3045 + strlen(spacing) + strlen(charset)
3046 + 1 + 1 + 1 + 1 + 1 + 3 + 1 + 5 + 3
3047 + 1 /* for the terminating '\0'. */;
3049 fontname = g_new(gchar, length);
3050 /* **NOTE**: If you change this string please change length above! */
3051 sprintf(fontname, "-%s-%s-%s-%s-%s-*-%s-%s-*-*-%s-*-%s",
3052 foundry, family, weight, slant, set_width, pixel_size,
3053 point_size, spacing, charset);
3059 /*****************************************************************************
3060 * GtkFontSelectionDialog
3061 *****************************************************************************/
3064 gtk_font_selection_dialog_get_type (void)
3066 static guint font_selection_dialog_type = 0;
3068 if (!font_selection_dialog_type)
3070 GtkTypeInfo fontsel_diag_info =
3072 "GtkFontSelectionDialog",
3073 sizeof (GtkFontSelectionDialog),
3074 sizeof (GtkFontSelectionDialogClass),
3075 (GtkClassInitFunc) gtk_font_selection_dialog_class_init,
3076 (GtkObjectInitFunc) gtk_font_selection_dialog_init,
3077 (GtkArgSetFunc) NULL,
3078 (GtkArgGetFunc) NULL,
3081 font_selection_dialog_type = gtk_type_unique (gtk_window_get_type (), &fontsel_diag_info);
3084 return font_selection_dialog_type;
3088 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
3090 GtkObjectClass *object_class;
3092 object_class = (GtkObjectClass*) klass;
3094 font_selection_dialog_parent_class = gtk_type_class (gtk_window_get_type ());
3098 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
3100 fontseldiag->dialog_width = -1;
3101 fontseldiag->auto_resize = TRUE;
3103 gtk_widget_set_events(GTK_WIDGET(fontseldiag), GDK_STRUCTURE_MASK);
3104 gtk_signal_connect (GTK_OBJECT (fontseldiag), "configure_event",
3105 (GtkSignalFunc) gtk_font_selection_dialog_on_configure,
3108 gtk_container_border_width (GTK_CONTAINER (fontseldiag), 4);
3109 gtk_window_set_policy(GTK_WINDOW(fontseldiag), FALSE, TRUE, TRUE);
3111 fontseldiag->main_vbox = gtk_vbox_new (FALSE, 4);
3112 gtk_widget_show (fontseldiag->main_vbox);
3113 gtk_container_add (GTK_CONTAINER (fontseldiag), fontseldiag->main_vbox);
3115 fontseldiag->fontsel = gtk_font_selection_new();
3116 gtk_widget_show (fontseldiag->fontsel);
3117 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
3118 fontseldiag->fontsel, TRUE, TRUE, 0);
3120 /* Create the action area */
3121 fontseldiag->action_area = gtk_hbutton_box_new ();
3122 gtk_button_box_set_layout(GTK_BUTTON_BOX(fontseldiag->action_area),
3124 gtk_button_box_set_spacing(GTK_BUTTON_BOX(fontseldiag->action_area), 5);
3125 gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
3126 fontseldiag->action_area, FALSE, FALSE, 0);
3127 gtk_widget_show (fontseldiag->action_area);
3129 fontseldiag->ok_button = gtk_button_new_with_label("OK");
3130 GTK_WIDGET_SET_FLAGS (fontseldiag->ok_button, GTK_CAN_DEFAULT);
3131 gtk_widget_show(fontseldiag->ok_button);
3132 gtk_box_pack_start (GTK_BOX (fontseldiag->action_area),
3133 fontseldiag->ok_button, TRUE, TRUE, 0);
3134 gtk_widget_grab_default (fontseldiag->ok_button);
3136 fontseldiag->apply_button = gtk_button_new_with_label("Apply");
3137 GTK_WIDGET_SET_FLAGS (fontseldiag->apply_button, GTK_CAN_DEFAULT);
3138 /*gtk_widget_show(fontseldiag->apply_button);*/
3139 gtk_box_pack_start (GTK_BOX(fontseldiag->action_area),
3140 fontseldiag->apply_button, TRUE, TRUE, 0);
3142 fontseldiag->cancel_button = gtk_button_new_with_label("Cancel");
3143 GTK_WIDGET_SET_FLAGS (fontseldiag->cancel_button, GTK_CAN_DEFAULT);
3144 gtk_widget_show(fontseldiag->cancel_button);
3145 gtk_box_pack_start (GTK_BOX(fontseldiag->action_area),
3146 fontseldiag->cancel_button, TRUE, TRUE, 0);
3152 gtk_font_selection_dialog_new (const gchar *title)
3154 GtkFontSelectionDialog *fontseldiag;
3156 fontseldiag = gtk_type_new (gtk_font_selection_dialog_get_type ());
3157 gtk_window_set_title (GTK_WINDOW (fontseldiag),
3158 title ? title : "Font Selection");
3160 return GTK_WIDGET (fontseldiag);
3164 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
3166 return gtk_font_selection_get_font_name(GTK_FONT_SELECTION(fsd->fontsel));
3170 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
3172 return gtk_font_selection_get_font(GTK_FONT_SELECTION(fsd->fontsel));
3176 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
3177 const gchar *fontname)
3179 return gtk_font_selection_set_font_name(GTK_FONT_SELECTION(fsd->fontsel),
3185 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
3187 return gtk_font_selection_get_preview_text(GTK_FONT_SELECTION(fsd->fontsel));
3191 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
3194 gtk_font_selection_set_preview_text(GTK_FONT_SELECTION(fsd->fontsel), text);
3198 /* This turns auto-shrink off if the user resizes the width of the dialog.
3199 It also turns it back on again if the user resizes it back to its normal
3202 gtk_font_selection_dialog_on_configure (GtkWidget *widget,
3203 GdkEventConfigure *event,
3204 GtkFontSelectionDialog *fsd)
3206 /* This sets the initial width. */
3207 if (fsd->dialog_width == -1)
3208 fsd->dialog_width = event->width;
3209 else if (fsd->auto_resize && fsd->dialog_width != event->width)
3211 fsd->auto_resize = FALSE;
3212 gtk_window_set_policy(GTK_WINDOW(fsd), FALSE, TRUE, FALSE);
3214 else if (!fsd->auto_resize && fsd->dialog_width == event->width)
3216 fsd->auto_resize = TRUE;
3217 gtk_window_set_policy(GTK_WINDOW(fsd), FALSE, TRUE, TRUE);