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