]> Pileus Git - ~andy/gtk/blob - gtk/gtkfontsel.c
Patch from Matthias Clasen to remove remove all instances of
[~andy/gtk] / gtk / gtkfontsel.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * Massively updated for Pango by Owen Taylor, May 2000
5  * GtkFontSelection widget for Gtk+, by Damon Chaplin, May 1998.
6  * Based on the GnomeFontSelector widget, by Elliot Lee, but major changes.
7  * The GnomeFontSelector was derived from app/text_tool.c in the GIMP.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 /*
26  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
27  * file for a list of people on the GTK+ Team.  See the ChangeLog
28  * files for a list of changes.  These files are distributed with
29  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
30  */
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <ctype.h>
36
37 #include "gdk/gdk.h"
38 #include "gdk/gdkkeysyms.h"
39
40 #include "gtkfontsel.h"
41
42 #include "gtkbutton.h"
43 #include "gtkclist.h"
44 #include "gtkentry.h"
45 #include "gtkframe.h"
46 #include "gtkhbbox.h"
47 #include "gtkhbox.h"
48 #include "gtklabel.h"
49 #include "gtkrc.h"
50 #include "gtksignal.h"
51 #include "gtkstock.h"
52 #include "gtktable.h"
53 #include "gtkvbox.h"
54 #include "gtkscrolledwindow.h"
55 #include "gtkintl.h"
56
57 /* This is the default text shown in the preview entry, though the user
58    can set it. Remember that some fonts only have capital letters. */
59 #define PREVIEW_TEXT "abcdefghijk ABCDEFGHIJK"
60
61 /* This is the initial and maximum height of the preview entry (it expands
62    when large font sizes are selected). Initial height is also the minimum. */
63 #define INITIAL_PREVIEW_HEIGHT 44
64 #define MAX_PREVIEW_HEIGHT 300
65
66 /* These are the sizes of the font, style & size clists. */
67 #define FONT_LIST_HEIGHT        136
68 #define FONT_LIST_WIDTH         190
69 #define FONT_STYLE_LIST_WIDTH   170
70 #define FONT_SIZE_LIST_WIDTH    60
71
72 /* These are what we use as the standard font sizes, for the size clist.
73  */
74 static const guint16 font_sizes[] = {
75   8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28,
76   32, 36, 40, 48, 56, 64, 72
77 };
78
79 enum {
80    PROP_0,
81    PROP_FONT_NAME,
82    PROP_FONT,
83    PROP_PREVIEW_TEXT
84 };
85
86 static void    gtk_font_selection_class_init         (GtkFontSelectionClass *klass);
87 static void    gtk_font_selection_set_property       (GObject         *object,
88                                                       guint            prop_id,
89                                                       const GValue    *value,
90                                                       GParamSpec      *pspec);
91 static void    gtk_font_selection_get_property       (GObject         *object,
92                                                       guint            prop_id,
93                                                       GValue          *value,
94                                                       GParamSpec      *pspec);
95 static void    gtk_font_selection_init               (GtkFontSelection      *fontsel);
96 static void    gtk_font_selection_finalize           (GObject               *object);
97
98 /* These are the callbacks & related functions. */
99 static void     gtk_font_selection_select_font           (GtkWidget        *w,
100                                                           gint              row,
101                                                           gint              column,
102                                                           GdkEventButton   *bevent,
103                                                           gpointer          data);
104 static void     gtk_font_selection_show_available_fonts  (GtkFontSelection *fs);
105
106 static void     gtk_font_selection_show_available_styles (GtkFontSelection *fs);
107 static void     gtk_font_selection_select_best_style     (GtkFontSelection *fs,
108                                                           gboolean          use_first);
109 static void     gtk_font_selection_select_style          (GtkWidget        *w,
110                                                           gint              row,
111                                                           gint              column,
112                                                           GdkEventButton   *bevent,
113                                                           gpointer          data);
114
115 static void     gtk_font_selection_select_best_size      (GtkFontSelection *fs);
116 static void     gtk_font_selection_show_available_sizes  (GtkFontSelection *fs);
117 static void     gtk_font_selection_size_activate         (GtkWidget        *w,
118                                                           gpointer          data);
119 static void     gtk_font_selection_select_size           (GtkWidget        *w,
120                                                           gint              row,
121                                                           gint              column,
122                                                           GdkEventButton   *bevent,
123                                                           gpointer          data);
124
125 static void     gtk_font_selection_scroll_on_map         (GtkWidget        *w,
126                                                           gpointer          data);
127
128 static void     gtk_font_selection_preview_changed       (GtkWidget        *entry,
129                                                           GtkFontSelection *fontsel);
130
131 /* Misc. utility functions. */
132 static void     gtk_font_selection_load_font         (GtkFontSelection *fs);
133 static void    gtk_font_selection_update_preview     (GtkFontSelection *fs);
134
135 /* FontSelectionDialog */
136 static void    gtk_font_selection_dialog_class_init  (GtkFontSelectionDialogClass *klass);
137 static void    gtk_font_selection_dialog_init        (GtkFontSelectionDialog *fontseldiag);
138
139 static gint    gtk_font_selection_dialog_on_configure (GtkWidget      *widget,
140                                                        GdkEventConfigure *event,
141                                                        GtkFontSelectionDialog *fsd);
142
143 static GtkWindowClass *font_selection_parent_class = NULL;
144 static GtkVBoxClass *font_selection_dialog_parent_class = NULL;
145
146 GtkType
147 gtk_font_selection_get_type ()
148 {
149   static GtkType font_selection_type = 0;
150   
151   if (!font_selection_type)
152     {
153       static const GtkTypeInfo fontsel_type_info =
154       {
155         "GtkFontSelection",
156         sizeof (GtkFontSelection),
157         sizeof (GtkFontSelectionClass),
158         (GtkClassInitFunc) gtk_font_selection_class_init,
159         (GtkObjectInitFunc) gtk_font_selection_init,
160         /* reserved_1 */ NULL,
161         /* reserved_2 */ NULL,
162         (GtkClassInitFunc) NULL,
163       };
164       
165       font_selection_type = gtk_type_unique (GTK_TYPE_VBOX,
166                                              &fontsel_type_info);
167     }
168   
169   return font_selection_type;
170 }
171
172 static void
173 gtk_font_selection_class_init (GtkFontSelectionClass *klass)
174 {
175   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
176   
177   font_selection_parent_class = gtk_type_class (GTK_TYPE_VBOX);
178   
179   gobject_class->set_property = gtk_font_selection_set_property;
180   gobject_class->get_property = gtk_font_selection_get_property;
181    
182   g_object_class_install_property (gobject_class,
183                                    PROP_FONT_NAME,
184                                    g_param_spec_string ("font_name",
185                                                         _("Font name"),
186                                                         _("The X string that represents this font."),
187                                                         NULL,
188                                                         G_PARAM_READWRITE));
189   g_object_class_install_property (gobject_class,
190                                    PROP_FONT,
191                                    g_param_spec_boxed ("font",
192                                                        _("Font"),
193                                                        _("The GdkFont that is currently selected."),
194                                                        GDK_TYPE_FONT,
195                                                        G_PARAM_READABLE));
196   g_object_class_install_property (gobject_class,
197                                    PROP_PREVIEW_TEXT,
198                                    g_param_spec_string ("preview_text",
199                                                         _("Preview text"),
200                                                         _("The text to display in order to demonstrate the selected font."),
201                                                         PREVIEW_TEXT,
202                                                         G_PARAM_READWRITE));
203   gobject_class->finalize = gtk_font_selection_finalize;
204 }
205
206 static void 
207 gtk_font_selection_set_property (GObject         *object,
208                                  guint            prop_id,
209                                  const GValue    *value,
210                                  GParamSpec      *pspec)
211 {
212   GtkFontSelection *fontsel;
213
214   fontsel = GTK_FONT_SELECTION (object);
215
216   switch (prop_id)
217     {
218     case PROP_FONT_NAME:
219       gtk_font_selection_set_font_name (fontsel, g_value_get_string (value));
220       break;
221     case PROP_PREVIEW_TEXT:
222       gtk_font_selection_set_preview_text (fontsel, g_value_get_string (value));
223       break;
224     default:
225       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
226       break;
227     }
228 }
229
230 static void gtk_font_selection_get_property (GObject         *object,
231                                              guint            prop_id,
232                                              GValue          *value,
233                                              GParamSpec      *pspec)
234 {
235   GtkFontSelection *fontsel;
236
237   fontsel = GTK_FONT_SELECTION (object);
238
239   switch (prop_id)
240     {
241     case PROP_FONT_NAME:
242       g_value_set_string (value, gtk_font_selection_get_font_name (fontsel));
243       break;
244     case PROP_FONT:
245       g_value_set_object (value, G_OBJECT (gtk_font_selection_get_font (fontsel)));
246       break;
247     case PROP_PREVIEW_TEXT:
248       g_value_set_string (value, gtk_font_selection_get_preview_text (fontsel));
249       break;
250     default:
251       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
252       break;
253     }
254 }
255
256
257 static void
258 gtk_font_selection_init (GtkFontSelection *fontsel)
259 {
260   GtkWidget *scrolled_win;
261   GtkWidget *text_frame;
262   GtkWidget *text_box;
263   GtkWidget *table, *label;
264
265   fontsel->font_desc = pango_font_description_from_string ("sans 12");
266   
267   /* Create the table of font, style & size. */
268   table = gtk_table_new (3, 3, FALSE);
269   gtk_widget_show (table);
270   gtk_table_set_col_spacings (GTK_TABLE (table), 8);
271   gtk_box_pack_start (GTK_BOX (fontsel), table, TRUE, TRUE, 0);
272
273   fontsel->font_entry = gtk_entry_new ();
274   gtk_entry_set_editable (GTK_ENTRY (fontsel->font_entry), FALSE);
275   gtk_widget_set_usize (fontsel->font_entry, 20, -1);
276   gtk_widget_show (fontsel->font_entry);
277   gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
278                     GTK_FILL, 0, 0, 0);
279   
280   fontsel->font_style_entry = gtk_entry_new ();
281   gtk_entry_set_editable (GTK_ENTRY (fontsel->font_style_entry), FALSE);
282   gtk_widget_set_usize (fontsel->font_style_entry, 20, -1);
283   gtk_widget_show (fontsel->font_style_entry);
284   gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
285                     GTK_FILL, 0, 0, 0);
286   
287   fontsel->size_entry = gtk_entry_new ();
288   gtk_widget_set_usize (fontsel->size_entry, 20, -1);
289   gtk_widget_show (fontsel->size_entry);
290   gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
291                     GTK_FILL, 0, 0, 0);
292   gtk_signal_connect (GTK_OBJECT (fontsel->size_entry), "activate",
293                       (GtkSignalFunc) gtk_font_selection_size_activate,
294                       fontsel);
295   
296   fontsel->font_label = gtk_label_new_with_mnemonic (_("_Family:"));
297   gtk_label_set_mnemonic_widget (GTK_LABEL (fontsel->font_label),
298                                  fontsel->font_entry);
299   gtk_misc_set_alignment (GTK_MISC (fontsel->font_label), 0.0, 0.5);
300   gtk_widget_show (fontsel->font_label);
301   gtk_table_attach (GTK_TABLE (table), fontsel->font_label, 0, 1, 0, 1,
302                     GTK_FILL, 0, 0, 0);  
303   label = gtk_label_new_with_mnemonic (_("_Style:"));
304   gtk_label_set_mnemonic_widget (GTK_LABEL (label),
305                                  fontsel->font_style_entry);
306   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
307   gtk_widget_show (label);
308   gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1,
309                     GTK_FILL, 0, 0, 0);
310   label = gtk_label_new_with_mnemonic (_("Si_ze:"));
311   gtk_label_set_mnemonic_widget (GTK_LABEL (label),
312                                  fontsel->size_entry);
313   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
314   gtk_widget_show (label);
315   gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
316                     GTK_FILL, 0, 0, 0);
317   
318   
319   /* Create the clists  */
320   fontsel->font_clist = gtk_clist_new (1);
321   gtk_clist_column_titles_hide (GTK_CLIST (fontsel->font_clist));
322   gtk_clist_set_column_auto_resize (GTK_CLIST (fontsel->font_clist), 0, TRUE);
323   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
324   gtk_widget_set_usize (scrolled_win, FONT_LIST_WIDTH, FONT_LIST_HEIGHT);
325   gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->font_clist);
326   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
327                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
328   gtk_widget_show (fontsel->font_clist);
329   gtk_widget_show (scrolled_win);
330
331   gtk_table_attach (GTK_TABLE (table), scrolled_win, 0, 1, 2, 3,
332                     GTK_EXPAND | GTK_FILL,
333                     GTK_EXPAND | GTK_FILL, 0, 0);
334   
335   fontsel->font_style_clist = gtk_clist_new (1);
336   gtk_clist_column_titles_hide (GTK_CLIST (fontsel->font_style_clist));
337   gtk_clist_set_column_auto_resize (GTK_CLIST (fontsel->font_style_clist),
338                                     0, TRUE);
339   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
340   gtk_widget_set_usize (scrolled_win, FONT_STYLE_LIST_WIDTH, -1);
341   gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->font_style_clist);
342   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
343                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
344   gtk_widget_show (fontsel->font_style_clist);
345   gtk_widget_show (scrolled_win);
346   gtk_table_attach (GTK_TABLE (table), scrolled_win, 1, 2, 2, 3,
347                     GTK_EXPAND | GTK_FILL,
348                     GTK_EXPAND | GTK_FILL, 0, 0);
349   
350   fontsel->size_clist = gtk_clist_new (1);
351   gtk_clist_column_titles_hide (GTK_CLIST (fontsel->size_clist));
352   gtk_clist_set_column_width (GTK_CLIST (fontsel->size_clist), 0, 20);
353   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
354   gtk_widget_set_usize (scrolled_win, FONT_SIZE_LIST_WIDTH, -1);
355   gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->size_clist);
356   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
357                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
358   gtk_widget_show (fontsel->size_clist);
359   gtk_widget_show (scrolled_win);
360   gtk_table_attach (GTK_TABLE (table), scrolled_win, 2, 3, 2, 3,
361                     GTK_FILL, GTK_FILL, 0, 0);
362   
363   /* Insert the fonts. If there exist fonts with the same family but
364      different foundries, then the foundry name is appended in brackets. */
365   gtk_font_selection_show_available_fonts (fontsel);
366   
367   gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "select_row",
368                       GTK_SIGNAL_FUNC (gtk_font_selection_select_font),
369                       fontsel);
370   GTK_WIDGET_SET_FLAGS (fontsel->font_clist, GTK_CAN_FOCUS);
371
372   gtk_signal_connect_after (GTK_OBJECT (fontsel->font_clist), "map",
373                             GTK_SIGNAL_FUNC (gtk_font_selection_scroll_on_map),
374                             fontsel);
375   
376   gtk_font_selection_show_available_styles (fontsel);
377   
378   gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist), "select_row",
379                       GTK_SIGNAL_FUNC (gtk_font_selection_select_style),
380                       fontsel);
381   GTK_WIDGET_SET_FLAGS (fontsel->font_style_clist, GTK_CAN_FOCUS);
382
383   gtk_font_selection_show_available_sizes (fontsel);
384   
385   gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "select_row",
386                       GTK_SIGNAL_FUNC (gtk_font_selection_select_size),
387                       fontsel);
388   GTK_WIDGET_SET_FLAGS (fontsel->size_clist, GTK_CAN_FOCUS);
389   
390   /* create the text entry widget */
391   text_frame = gtk_frame_new (_("Preview:"));
392   gtk_widget_show (text_frame);
393   gtk_frame_set_shadow_type (GTK_FRAME (text_frame), GTK_SHADOW_ETCHED_IN);
394   gtk_box_pack_start (GTK_BOX (fontsel), text_frame,
395                       FALSE, TRUE, 0);
396   
397   /* This is just used to get a 4-pixel space around the preview entry. */
398   text_box = gtk_hbox_new (FALSE, 0);
399   gtk_widget_show (text_box);
400   gtk_container_add (GTK_CONTAINER (text_frame), text_box);
401   gtk_container_set_border_width (GTK_CONTAINER (text_box), 4);
402   
403   fontsel->preview_entry = gtk_entry_new ();
404   gtk_widget_show (fontsel->preview_entry);
405   gtk_signal_connect (GTK_OBJECT (fontsel->preview_entry), "changed",
406                       (GtkSignalFunc) gtk_font_selection_preview_changed,
407                       fontsel);
408   gtk_widget_set_usize (fontsel->preview_entry, -1, INITIAL_PREVIEW_HEIGHT);
409   gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
410                       TRUE, TRUE, 0);
411
412   gtk_font_selection_update_preview (fontsel);
413 }
414
415 GtkWidget *
416 gtk_font_selection_new ()
417 {
418   GtkFontSelection *fontsel;
419   
420   fontsel = gtk_type_new (GTK_TYPE_FONT_SELECTION);
421   
422   return GTK_WIDGET (fontsel);
423 }
424
425 static void
426 gtk_font_selection_finalize (GObject *object)
427 {
428   GtkFontSelection *fontsel;
429   
430   g_return_if_fail (GTK_IS_FONT_SELECTION (object));
431   
432   fontsel = GTK_FONT_SELECTION (object);
433
434   pango_font_description_free (fontsel->font_desc);
435
436   if (fontsel->font)
437     gdk_font_unref (fontsel->font);
438   
439   if (G_OBJECT_CLASS (font_selection_parent_class)->finalize)
440     (* G_OBJECT_CLASS (font_selection_parent_class)->finalize) (object);
441 }
442
443 static void
444 gtk_font_selection_preview_changed (GtkWidget        *entry,
445                                     GtkFontSelection *fontsel)
446 {
447   g_object_notify (G_OBJECT (fontsel), "preview_text");
448 }
449
450 /* This is called when the clist is mapped. Here we scroll to the current
451    font if necessary. */
452 static void
453 gtk_font_selection_scroll_on_map (GtkWidget             *widget,
454                                   gpointer               data)
455 {
456   GtkFontSelection *fontsel;
457   GList *selection;
458   gint index;
459   
460 #ifdef FONTSEL_DEBUG
461   g_message ("In expose_list\n");
462 #endif
463   fontsel = GTK_FONT_SELECTION (data);
464   
465   /* Try to scroll the font family clist to the selected item */
466   selection = GTK_CLIST (fontsel->font_clist)->selection;
467   if (selection)
468     {
469       index = GPOINTER_TO_INT (selection->data);
470       if (gtk_clist_row_is_visible (GTK_CLIST (fontsel->font_clist), index)
471           != GTK_VISIBILITY_FULL)
472         gtk_clist_moveto (GTK_CLIST (fontsel->font_clist), index, -1, 0.5, 0);
473     }
474       
475   /* Try to scroll the font style clist to the selected item */
476   selection = GTK_CLIST (fontsel->font_style_clist)->selection;
477   if (selection)
478     {
479       index = GPOINTER_TO_INT (selection->data);
480       if (gtk_clist_row_is_visible (GTK_CLIST (fontsel->font_style_clist), index)
481           != GTK_VISIBILITY_FULL)
482         gtk_clist_moveto (GTK_CLIST (fontsel->font_style_clist), index, -1,
483                          0.5, 0);
484     }
485       
486   /* Try to scroll the font size clist to the selected item */
487   selection = GTK_CLIST (fontsel->size_clist)->selection;
488   if (selection)
489     {
490       index = GPOINTER_TO_INT (selection->data);
491       if (gtk_clist_row_is_visible (GTK_CLIST (fontsel->size_clist), index)
492           != GTK_VISIBILITY_FULL)
493       gtk_clist_moveto (GTK_CLIST (fontsel->size_clist), index, -1, 0.5, 0);
494     }
495 }
496
497 /* This is called when a family is selected in the list. */
498 static void
499 gtk_font_selection_select_font (GtkWidget      *w,
500                                 gint            row,
501                                 gint            column,
502                                 GdkEventButton *bevent,
503                                 gpointer        data)
504 {
505   GtkFontSelection *fontsel;
506   gchar *family_name;
507   gint index;
508   
509   fontsel = GTK_FONT_SELECTION (data);
510
511   if (GTK_CLIST (fontsel->font_clist)->selection)
512     {
513       index = GPOINTER_TO_INT (GTK_CLIST (fontsel->font_clist)->selection->data);
514
515       if (gtk_clist_get_text (GTK_CLIST (fontsel->font_clist), index, 0, &family_name) &&
516           strcasecmp (fontsel->font_desc->family_name, family_name) != 0)
517         {
518           g_free (fontsel->font_desc->family_name);
519           fontsel->font_desc->family_name  = g_strdup (family_name);
520
521           gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), family_name);
522           
523           gtk_font_selection_show_available_styles (fontsel);
524           gtk_font_selection_select_best_style (fontsel, TRUE);
525         }
526     }
527 }
528
529 static int
530 cmp_strings (const void *a, const void *b)
531 {
532   return strcasecmp (*(const char **)a, *(const char **)b);
533 }
534
535 static void
536 gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
537 {
538   gchar **families;
539   int n_families, i;
540
541   pango_context_list_families (gtk_widget_get_pango_context (GTK_WIDGET (fontsel)),
542                                &families, &n_families);
543   qsort (families, n_families, sizeof (char *), cmp_strings);
544
545   gtk_clist_freeze (GTK_CLIST (fontsel->font_clist));
546   gtk_clist_clear (GTK_CLIST (fontsel->font_clist));
547
548   for (i=0; i<n_families; i++)
549     {
550       gtk_clist_append (GTK_CLIST (fontsel->font_clist), &families[i]);
551
552       if (!strcasecmp (families[i], fontsel->font_desc->family_name))
553         {
554           gtk_clist_select_row (GTK_CLIST (fontsel->font_clist), i, 0);
555           gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), families[i]);
556         }
557     }
558   
559   gtk_clist_thaw (GTK_CLIST (fontsel->font_clist));
560
561   pango_font_map_free_families (families, n_families);
562 }
563
564 static int
565 compare_font_descriptions (const PangoFontDescription *a, const PangoFontDescription *b)
566 {
567   int val = strcasecmp (a->family_name, b->family_name);
568   if (val != 0)
569     return val;
570
571   if (a->weight != b->weight)
572     return a->weight - b->weight;
573
574   if (a->style != b->style)
575     return a->style - b->style;
576   
577   if (a->stretch != b->stretch)
578     return a->stretch - b->stretch;
579
580   if (a->variant != b->variant)
581     return a->variant - b->variant;
582
583   return 0;
584 }
585
586 static int
587 font_description_sort_func (const void *a, const void *b)
588 {
589   return compare_font_descriptions (*(PangoFontDescription **)a, *(PangoFontDescription **)b);
590 }
591
592 /* This fills the font style clist with all the possible style combinations
593    for the current font family. */
594 static void
595 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
596 {
597   PangoFontDescription **descs;
598   int n_descs, i;
599   gint match_row = -1;
600   gchar *str;
601   
602   pango_context_list_fonts (gtk_widget_get_pango_context (GTK_WIDGET (fontsel)),
603                             fontsel->font_desc->family_name, &descs, &n_descs);
604   qsort (descs, n_descs, sizeof (PangoFontDescription *), font_description_sort_func);
605
606   gtk_clist_freeze (GTK_CLIST (fontsel->font_style_clist));
607   gtk_clist_clear (GTK_CLIST (fontsel->font_style_clist));
608
609   for (i=0; i<n_descs; i++)
610     {
611       PangoFontDescription tmp_desc;
612
613       tmp_desc = *descs[i];
614       tmp_desc.family_name = NULL;
615       tmp_desc.size = 0;
616
617       str = pango_font_description_to_string (&tmp_desc);
618       gtk_clist_append (GTK_CLIST (fontsel->font_style_clist), &str);
619
620       if (descs[i]->weight == fontsel->font_desc->weight &&
621           descs[i]->style == fontsel->font_desc->style &&
622           descs[i]->stretch == fontsel->font_desc->stretch &&
623           descs[i]->variant == fontsel->font_desc->variant)
624         match_row = i;
625       
626       g_free (str);
627     }
628
629   gtk_clist_select_row (GTK_CLIST (fontsel->font_style_clist), match_row, 0);
630   if (match_row >= 0)
631     {
632       gtk_clist_get_text (GTK_CLIST (fontsel->font_style_clist), match_row, 0, &str);
633       gtk_entry_set_text (GTK_ENTRY (fontsel->font_style_entry), str);
634     }
635   
636   gtk_clist_thaw (GTK_CLIST (fontsel->font_style_clist));
637
638   pango_font_descriptions_free (descs, n_descs);
639 }
640
641
642 /* This selects a style when the user selects a font. It just uses the first
643    available style at present. I was thinking of trying to maintain the
644    selected style, e.g. bold italic, when the user selects different fonts.
645    However, the interface is so easy to use now I'm not sure it's worth it.
646    Note: This will load a font. */
647 static void
648 gtk_font_selection_select_best_style (GtkFontSelection *fontsel,
649                                       gboolean          use_first)
650 {
651   gint best_row = 0;
652   
653   gtk_clist_select_row (GTK_CLIST (fontsel->font_style_clist), best_row, 0);
654   if (gtk_clist_row_is_visible (GTK_CLIST (fontsel->font_style_clist), best_row)
655       != GTK_VISIBILITY_FULL)
656     gtk_clist_moveto (GTK_CLIST (fontsel->font_style_clist), best_row, -1,
657                       0.5, 0);
658   gtk_font_selection_show_available_sizes (fontsel);
659   gtk_font_selection_select_best_size (fontsel);
660 }
661
662
663 /* This is called when a style is selected in the list. */
664 static void
665 gtk_font_selection_select_style (GtkWidget      *w,
666                                  gint           row,
667                                  gint           column,
668                                  GdkEventButton *bevent,
669                                  gpointer        data)
670 {
671   GtkFontSelection *fontsel = GTK_FONT_SELECTION (data);
672   PangoFontDescription *tmp_desc;
673   gchar *text;
674   gint index;
675   
676   if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
677     gtk_widget_grab_focus (w);
678   
679   if (GTK_CLIST (fontsel->font_style_clist)->selection)
680     {
681       index = GPOINTER_TO_INT (GTK_CLIST (fontsel->font_style_clist)->selection->data);
682
683       if (gtk_clist_get_text (GTK_CLIST (fontsel->font_style_clist), index, 0, &text))
684         {
685           tmp_desc = pango_font_description_from_string (text);
686           
687           fontsel->font_desc->style = tmp_desc->style;
688           fontsel->font_desc->variant = tmp_desc->variant;
689           fontsel->font_desc->weight = tmp_desc->weight;
690           fontsel->font_desc->stretch = tmp_desc->stretch;
691           
692           pango_font_description_free (tmp_desc);
693         }
694     }
695
696   gtk_font_selection_show_available_sizes (fontsel);
697   gtk_font_selection_select_best_size (fontsel);
698 }
699
700 static void
701 gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel)
702 {
703   gint i;
704   gchar buffer[128];
705   gchar *size;
706
707   /* Insert the standard font sizes */
708   gtk_clist_freeze (GTK_CLIST (fontsel->size_clist));
709   gtk_clist_clear (GTK_CLIST (fontsel->size_clist));
710
711   for (i = 0; i < G_N_ELEMENTS (font_sizes); i++)
712     {
713       sprintf (buffer, "%i", font_sizes[i]);
714       size = buffer;
715       gtk_clist_append (GTK_CLIST (fontsel->size_clist), &size);
716       if (font_sizes[i] * PANGO_SCALE == fontsel->font_desc->size)
717         gtk_clist_select_row (GTK_CLIST (fontsel->size_clist), i, 0);
718     }
719   gtk_clist_thaw (GTK_CLIST (fontsel->size_clist));
720
721   sprintf (buffer, "%i", fontsel->font_desc->size / PANGO_SCALE);
722   gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
723 }
724
725 static void
726 gtk_font_selection_select_best_size (GtkFontSelection *fontsel)
727 {
728   gtk_font_selection_load_font (fontsel);  
729 }
730
731 /* If the user hits return in the font size entry, we change to the new font
732    size. */
733 static void
734 gtk_font_selection_size_activate (GtkWidget   *w,
735                                   gpointer     data)
736 {
737   GtkFontSelection *fontsel;
738   gint new_size;
739   gchar *text;
740   
741   fontsel = GTK_FONT_SELECTION (data);
742
743   text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
744   new_size = atoi (text) * PANGO_SCALE;
745   
746   if (fontsel->font_desc->size != new_size)
747     {
748       fontsel->font_desc->size = new_size;
749       gtk_font_selection_load_font (fontsel);
750     }
751 }
752
753 /* This is called when a size is selected in the list. */
754 static void
755 gtk_font_selection_select_size (GtkWidget      *w,
756                                 gint            row,
757                                 gint            column,
758                                 GdkEventButton *bevent,
759                                 gpointer        data)
760 {
761   GtkFontSelection *fontsel;
762   gint new_size;
763   gchar *text;
764   
765   fontsel = GTK_FONT_SELECTION (data);
766   
767   if (bevent && !GTK_WIDGET_HAS_FOCUS (w))
768     gtk_widget_grab_focus (w);
769   
770   gtk_clist_get_text (GTK_CLIST (fontsel->size_clist), row, 0, &text);
771   new_size = atoi (text) * PANGO_SCALE;
772   
773   if (fontsel->font_desc->size != new_size)
774     {
775       /* If the size was selected by the user we set the selected_size. */
776       fontsel->font_desc->size = new_size;
777
778       gtk_font_selection_load_font (fontsel);
779     }
780 }
781
782 static void
783 gtk_font_selection_load_font (GtkFontSelection *fontsel)
784 {
785   if (fontsel->font)
786     gdk_font_unref (fontsel->font);
787   fontsel->font = NULL;
788
789   gtk_font_selection_update_preview (fontsel);
790 }
791
792 /* This sets the font in the preview entry to the selected font, and tries to
793    make sure that the preview entry is a reasonable size, i.e. so that the
794    text can be seen with a bit of space to spare. But it tries to avoid
795    resizing the entry every time the font changes.
796    This also used to shrink the preview if the font size was decreased, but
797    that made it awkward if the user wanted to resize the window themself. */
798 static void
799 gtk_font_selection_update_preview (GtkFontSelection *fontsel)
800 {
801   GtkRcStyle *rc_style;
802   gint new_height;
803   GtkRequisition old_requisition;
804   GtkWidget *preview_entry = fontsel->preview_entry;
805   gchar *text;
806
807   gtk_widget_get_child_requisition (preview_entry, &old_requisition);
808   
809   rc_style = gtk_rc_style_new ();
810   rc_style->font_desc = pango_font_description_copy (fontsel->font_desc);
811   gtk_widget_modify_style (preview_entry, rc_style);
812   gtk_rc_style_unref (rc_style);
813
814   gtk_widget_size_request (preview_entry, NULL);
815   
816   /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
817   new_height = CLAMP (preview_entry->requisition.height, INITIAL_PREVIEW_HEIGHT, MAX_PREVIEW_HEIGHT);
818
819   if (new_height > old_requisition.height || new_height < old_requisition.height - 30)
820     gtk_widget_set_usize (preview_entry, -1, new_height);
821   
822   /* This sets the preview text, if it hasn't been set already. */
823   text = gtk_entry_get_text (GTK_ENTRY (preview_entry));
824   if (strlen (text) == 0)
825     gtk_entry_set_text (GTK_ENTRY (preview_entry), PREVIEW_TEXT);
826   gtk_entry_set_position (GTK_ENTRY (preview_entry), 0);
827 }
828
829 /*****************************************************************************
830  * These functions are the main public interface for getting/setting the font.
831  *****************************************************************************/
832
833 GdkFont*
834 gtk_font_selection_get_font (GtkFontSelection *fontsel)
835 {
836   if (!fontsel->font)
837     fontsel->font = gdk_font_from_description (fontsel->font_desc);
838   
839   return fontsel->font;
840 }
841
842
843 gchar *
844 gtk_font_selection_get_font_name (GtkFontSelection *fontsel)
845 {
846   return pango_font_description_to_string (fontsel->font_desc);
847 }
848
849
850 /* This sets the current font, selecting the appropriate clist rows.
851    First we check the fontname is valid and try to find the font family
852    - i.e. the name in the main list. If we can't find that, then just return.
853    Next we try to set each of the properties according to the fontname.
854    Finally we select the font family & style in the clists. */
855 gboolean
856 gtk_font_selection_set_font_name (GtkFontSelection *fontsel,
857                                   const gchar      *fontname)
858 {
859   PangoFontDescription *new_desc;
860   PangoFontDescription **descs;
861   int n_descs, i;
862   gboolean found = FALSE;
863
864   g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), FALSE);
865   
866   new_desc = pango_font_description_from_string (fontname);
867
868   /* Check to make sure that this is in the list of allowed fonts */
869
870   pango_context_list_fonts (gtk_widget_get_pango_context (GTK_WIDGET (fontsel)),
871                             new_desc->family_name, &descs, &n_descs);
872
873   for (i=0; i<n_descs; i++)
874     {
875       if (descs[i]->weight == new_desc->weight &&
876           descs[i]->style == new_desc->style &&
877           descs[i]->stretch == new_desc->stretch &&
878           descs[i]->variant == new_desc->variant)
879         {
880           found = TRUE;
881           break;
882         }
883     }
884
885   pango_font_descriptions_free (descs, n_descs);
886
887   if (!found)
888     return FALSE;
889
890   pango_font_description_free (fontsel->font_desc);
891   fontsel->font_desc = new_desc;
892
893   g_object_notify (G_OBJECT (fontsel), "font_name");
894   g_object_notify (G_OBJECT (fontsel), "font");
895   return TRUE;
896 }
897
898
899 /* This returns the text in the preview entry. You should copy the returned
900    text if you need it. */
901 gchar*
902 gtk_font_selection_get_preview_text  (GtkFontSelection *fontsel)
903 {
904   return gtk_entry_get_text (GTK_ENTRY (fontsel->preview_entry));
905 }
906
907
908 /* This sets the text in the preview entry. */
909 void
910 gtk_font_selection_set_preview_text  (GtkFontSelection *fontsel,
911                                       const gchar         *text)
912 {
913   gtk_entry_set_text (GTK_ENTRY (fontsel->preview_entry), text);
914 }
915
916 /*****************************************************************************
917  * GtkFontSelectionDialog
918  *****************************************************************************/
919
920 GtkType
921 gtk_font_selection_dialog_get_type (void)
922 {
923   static guint font_selection_dialog_type = 0;
924   
925   if (!font_selection_dialog_type)
926     {
927       GtkTypeInfo fontsel_diag_info =
928       {
929         "GtkFontSelectionDialog",
930         sizeof (GtkFontSelectionDialog),
931         sizeof (GtkFontSelectionDialogClass),
932         (GtkClassInitFunc) gtk_font_selection_dialog_class_init,
933         (GtkObjectInitFunc) gtk_font_selection_dialog_init,
934         /* reserved_1 */ NULL,
935         /* reserved_2 */ NULL,
936         (GtkClassInitFunc) NULL,
937       };
938       
939       font_selection_dialog_type = gtk_type_unique (GTK_TYPE_DIALOG,
940                                                     &fontsel_diag_info);
941     }
942   
943   return font_selection_dialog_type;
944 }
945
946 static void
947 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
948 {
949   GtkObjectClass *object_class;
950   
951   object_class = (GtkObjectClass*) klass;
952   
953   font_selection_dialog_parent_class = gtk_type_class (GTK_TYPE_DIALOG);
954 }
955
956 static void
957 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
958 {
959   GtkDialog *dialog;
960
961   dialog = GTK_DIALOG (fontseldiag);
962   
963   fontseldiag->dialog_width = -1;
964   fontseldiag->auto_resize = TRUE;
965   
966   gtk_widget_set_events (GTK_WIDGET (fontseldiag), GDK_STRUCTURE_MASK);
967   gtk_signal_connect (GTK_OBJECT (fontseldiag), "configure_event",
968                       (GtkSignalFunc) gtk_font_selection_dialog_on_configure,
969                       fontseldiag);
970   
971   gtk_container_set_border_width (GTK_CONTAINER (fontseldiag), 4);
972   gtk_window_set_policy (GTK_WINDOW (fontseldiag), FALSE, TRUE, TRUE);
973   
974   fontseldiag->main_vbox = dialog->vbox;
975   
976   fontseldiag->fontsel = gtk_font_selection_new ();
977   gtk_container_set_border_width (GTK_CONTAINER (fontseldiag->fontsel), 4);
978   gtk_widget_show (fontseldiag->fontsel);
979   gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
980                       fontseldiag->fontsel, TRUE, TRUE, 0);
981   
982   /* Create the action area */
983   fontseldiag->action_area = dialog->action_area;
984   
985   fontseldiag->ok_button = gtk_dialog_add_button (dialog,
986                                                   GTK_STOCK_OK,
987                                                   GTK_RESPONSE_OK);
988   gtk_widget_grab_default (fontseldiag->ok_button);
989   
990   fontseldiag->apply_button = gtk_dialog_add_button (dialog,
991                                                      GTK_STOCK_APPLY,
992                                                      GTK_RESPONSE_APPLY);
993   gtk_widget_hide (fontseldiag->apply_button);
994
995   
996   fontseldiag->cancel_button = gtk_dialog_add_button (dialog,
997                                                       GTK_STOCK_CANCEL,
998                                                       GTK_RESPONSE_CANCEL);
999
1000   gtk_window_set_title (GTK_WINDOW (fontseldiag),
1001                         _("Font Selection"));
1002
1003 }
1004
1005 GtkWidget*
1006 gtk_font_selection_dialog_new (const gchar *title)
1007 {
1008   GtkFontSelectionDialog *fontseldiag;
1009   
1010   fontseldiag = gtk_type_new (GTK_TYPE_FONT_SELECTION_DIALOG);
1011
1012   if (title)
1013     gtk_window_set_title (GTK_WINDOW (fontseldiag), title);
1014   
1015   return GTK_WIDGET (fontseldiag);
1016 }
1017
1018 gchar*
1019 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
1020 {
1021   return gtk_font_selection_get_font_name (GTK_FONT_SELECTION (fsd->fontsel));
1022 }
1023
1024 GdkFont*
1025 gtk_font_selection_dialog_get_font (GtkFontSelectionDialog *fsd)
1026 {
1027   return gtk_font_selection_get_font (GTK_FONT_SELECTION (fsd->fontsel));
1028 }
1029
1030 gboolean
1031 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
1032                                          const gchar      *fontname)
1033 {
1034   return gtk_font_selection_set_font_name (GTK_FONT_SELECTION (fsd->fontsel), fontname);
1035 }
1036
1037 gchar*
1038 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
1039 {
1040   return gtk_font_selection_get_preview_text (GTK_FONT_SELECTION (fsd->fontsel));
1041 }
1042
1043 void
1044 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
1045                                             const gchar            *text)
1046 {
1047   gtk_font_selection_set_preview_text (GTK_FONT_SELECTION (fsd->fontsel), text);
1048 }
1049
1050
1051 /* This turns auto-shrink off if the user resizes the width of the dialog.
1052    It also turns it back on again if the user resizes it back to its normal
1053    width. */
1054 static gint
1055 gtk_font_selection_dialog_on_configure (GtkWidget              *widget,
1056                                         GdkEventConfigure      *event,
1057                                         GtkFontSelectionDialog *fsd)
1058 {
1059   /* This sets the initial width. */
1060   if (fsd->dialog_width == -1)
1061     fsd->dialog_width = event->width;
1062   else if (fsd->auto_resize && fsd->dialog_width != event->width)
1063     {
1064       fsd->auto_resize = FALSE;
1065       gtk_window_set_policy (GTK_WINDOW (fsd), FALSE, TRUE, FALSE);
1066     }
1067   else if (!fsd->auto_resize && fsd->dialog_width == event->width)
1068     {
1069       fsd->auto_resize = TRUE;
1070       gtk_window_set_policy (GTK_WINDOW (fsd), FALSE, TRUE, TRUE);
1071     }
1072   
1073   return FALSE;
1074 }