]> Pileus Git - ~andy/gtk/blob - gtk/gtkfontsel.c
applied patch from Andreas Persenius <ndap@swipnet.se> that updates the
[~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 "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->font_desc = pango_font_description_from_string ("sans 12");
182   
183   /* Create the table of font, style & size. */
184   table = gtk_table_new (3, 3, FALSE);
185   gtk_widget_show (table);
186   gtk_table_set_col_spacings(GTK_TABLE(table), 8);
187   gtk_box_pack_start (GTK_BOX (fontsel), table, TRUE, TRUE, 0);
188   
189   fontsel->font_label = gtk_label_new(_("Family:"));
190   gtk_misc_set_alignment (GTK_MISC (fontsel->font_label), 0.0, 0.5);
191   gtk_widget_show (fontsel->font_label);
192   gtk_table_attach (GTK_TABLE (table), fontsel->font_label, 0, 1, 0, 1,
193                     GTK_FILL, 0, 0, 0);
194   label = gtk_label_new(_("Style:"));
195   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
196   gtk_widget_show (label);
197   gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1,
198                     GTK_FILL, 0, 0, 0);
199   label = gtk_label_new(_("Size:"));
200   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
201   gtk_widget_show (label);
202   gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
203                     GTK_FILL, 0, 0, 0);
204   
205   fontsel->font_entry = gtk_entry_new ();
206   gtk_entry_set_editable(GTK_ENTRY(fontsel->font_entry), FALSE);
207   gtk_widget_set_usize (fontsel->font_entry, 20, -1);
208   gtk_widget_show (fontsel->font_entry);
209   gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
210                     GTK_FILL, 0, 0, 0);
211   
212   fontsel->font_style_entry = gtk_entry_new ();
213   gtk_entry_set_editable (GTK_ENTRY(fontsel->font_style_entry), FALSE);
214   gtk_widget_set_usize (fontsel->font_style_entry, 20, -1);
215   gtk_widget_show (fontsel->font_style_entry);
216   gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
217                     GTK_FILL, 0, 0, 0);
218   
219   fontsel->size_entry = gtk_entry_new ();
220   gtk_widget_set_usize (fontsel->size_entry, 20, -1);
221   gtk_widget_show (fontsel->size_entry);
222   gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
223                     GTK_FILL, 0, 0, 0);
224   gtk_signal_connect (GTK_OBJECT (fontsel->size_entry), "key_press_event",
225                       (GtkSignalFunc) gtk_font_selection_size_key_press,
226                       fontsel);
227   
228   /* Create the clists  */
229   fontsel->font_clist = gtk_clist_new (1);
230   gtk_clist_column_titles_hide (GTK_CLIST (fontsel->font_clist));
231   gtk_clist_set_column_auto_resize (GTK_CLIST (fontsel->font_clist), 0, TRUE);
232   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
233   gtk_widget_set_usize (scrolled_win, FONT_LIST_WIDTH, FONT_LIST_HEIGHT);
234   gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->font_clist);
235   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
236                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
237   gtk_widget_show(fontsel->font_clist);
238   gtk_widget_show(scrolled_win);
239
240   gtk_table_attach (GTK_TABLE (table), scrolled_win, 0, 1, 2, 3,
241                     GTK_EXPAND | GTK_FILL,
242                     GTK_EXPAND | GTK_FILL, 0, 0);
243   
244   fontsel->font_style_clist = gtk_clist_new (1);
245   gtk_clist_column_titles_hide (GTK_CLIST (fontsel->font_style_clist));
246   gtk_clist_set_column_auto_resize (GTK_CLIST (fontsel->font_style_clist),
247                                     0, TRUE);
248   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
249   gtk_widget_set_usize (scrolled_win, FONT_STYLE_LIST_WIDTH, -1);
250   gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->font_style_clist);
251   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
252                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
253   gtk_widget_show(fontsel->font_style_clist);
254   gtk_widget_show(scrolled_win);
255   gtk_table_attach (GTK_TABLE (table), scrolled_win, 1, 2, 2, 3,
256                     GTK_EXPAND | GTK_FILL,
257                     GTK_EXPAND | GTK_FILL, 0, 0);
258   
259   fontsel->size_clist = gtk_clist_new (1);
260   gtk_clist_column_titles_hide (GTK_CLIST(fontsel->size_clist));
261   gtk_clist_set_column_width (GTK_CLIST(fontsel->size_clist), 0, 20);
262   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
263   gtk_widget_set_usize (scrolled_win, FONT_SIZE_LIST_WIDTH, -1);
264   gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->size_clist);
265   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
266                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
267   gtk_widget_show (fontsel->size_clist);
268   gtk_widget_show (scrolled_win);
269   gtk_table_attach (GTK_TABLE (table), scrolled_win, 2, 3, 2, 3,
270                     GTK_FILL, GTK_FILL, 0, 0);
271   
272   /* Insert the fonts. If there exist fonts with the same family but
273      different foundries, then the foundry name is appended in brackets. */
274   gtk_font_selection_show_available_fonts(fontsel);
275   
276   gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "select_row",
277                       GTK_SIGNAL_FUNC(gtk_font_selection_select_font),
278                       fontsel);
279   GTK_WIDGET_SET_FLAGS (fontsel->font_clist, GTK_CAN_FOCUS);
280   gtk_signal_connect (GTK_OBJECT (fontsel->font_clist), "key_press_event",
281                       GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
282                       fontsel);
283   gtk_signal_connect_after (GTK_OBJECT (fontsel->font_clist), "expose_event",
284                             GTK_SIGNAL_FUNC(gtk_font_selection_expose_list),
285                             fontsel);
286   
287   gtk_font_selection_show_available_styles (fontsel);
288   
289   gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist), "select_row",
290                       GTK_SIGNAL_FUNC(gtk_font_selection_select_style),
291                       fontsel);
292   GTK_WIDGET_SET_FLAGS (fontsel->font_style_clist, GTK_CAN_FOCUS);
293   gtk_signal_connect (GTK_OBJECT (fontsel->font_style_clist),
294                       "key_press_event",
295                       GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
296                       fontsel);
297
298   gtk_font_selection_show_available_sizes (fontsel);
299   
300   gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "select_row",
301                       GTK_SIGNAL_FUNC(gtk_font_selection_select_size),
302                       fontsel);
303   GTK_WIDGET_SET_FLAGS (fontsel->size_clist, GTK_CAN_FOCUS);
304   gtk_signal_connect (GTK_OBJECT (fontsel->size_clist), "key_press_event",
305                       GTK_SIGNAL_FUNC(gtk_font_selection_on_clist_key_press),
306                       fontsel);
307   
308   /* create the text entry widget */
309   text_frame = gtk_frame_new (_("Preview:"));
310   gtk_widget_show (text_frame);
311   gtk_frame_set_shadow_type(GTK_FRAME(text_frame), GTK_SHADOW_ETCHED_IN);
312   gtk_box_pack_start (GTK_BOX (fontsel), text_frame,
313                       FALSE, TRUE, 0);
314   
315   /* This is just used to get a 4-pixel space around the preview entry. */
316   text_box = gtk_hbox_new (FALSE, 0);
317   gtk_widget_show (text_box);
318   gtk_container_add (GTK_CONTAINER (text_frame), text_box);
319   gtk_container_set_border_width (GTK_CONTAINER (text_box), 4);
320   
321   fontsel->preview_entry = gtk_entry_new ();
322   gtk_widget_show (fontsel->preview_entry);
323   gtk_widget_set_usize (fontsel->preview_entry, -1, INITIAL_PREVIEW_HEIGHT);
324   gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
325                       TRUE, TRUE, 0);
326
327   gtk_font_selection_update_preview (fontsel);
328 }
329
330 GtkWidget *
331 gtk_font_selection_new()
332 {
333   GtkFontSelection *fontsel;
334   
335   fontsel = gtk_type_new (GTK_TYPE_FONT_SELECTION);
336   
337   return GTK_WIDGET (fontsel);
338 }
339
340 static void
341 gtk_font_selection_finalize (GObject *object)
342 {
343   GtkFontSelection *fontsel;
344   
345   g_return_if_fail (object != NULL);
346   g_return_if_fail (GTK_IS_FONT_SELECTION (object));
347   
348   fontsel = GTK_FONT_SELECTION (object);
349
350   pango_font_description_free (fontsel->font_desc);
351
352   if (fontsel->font)
353     gdk_font_unref (fontsel->font);
354   
355   if (G_OBJECT_CLASS (font_selection_parent_class)->finalize)
356     (* G_OBJECT_CLASS (font_selection_parent_class)->finalize) (object);
357 }
358
359
360 /* This is called when the clist is exposed. Here we scroll to the current
361    font if necessary. */
362 static void
363 gtk_font_selection_expose_list (GtkWidget               *widget,
364                                 GdkEventExpose          *event,
365                                 gpointer                 data)
366 {
367   GtkFontSelection *fontsel;
368   GList *selection;
369   gint index;
370   
371 #ifdef FONTSEL_DEBUG
372   g_message("In expose_list\n");
373 #endif
374   fontsel = GTK_FONT_SELECTION(data);
375   
376   /* Try to scroll the font family clist to the selected item */
377   selection = GTK_CLIST(fontsel->font_clist)->selection;
378   if (selection)
379     {
380       index = GPOINTER_TO_INT (selection->data);
381       if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_clist), index)
382           != GTK_VISIBILITY_FULL)
383         gtk_clist_moveto(GTK_CLIST(fontsel->font_clist), index, -1, 0.5, 0);
384     }
385       
386   /* Try to scroll the font style clist to the selected item */
387   selection = GTK_CLIST(fontsel->font_style_clist)->selection;
388   if (selection)
389     {
390       index = GPOINTER_TO_INT (selection->data);
391       if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->font_style_clist), index)
392           != GTK_VISIBILITY_FULL)
393         gtk_clist_moveto(GTK_CLIST(fontsel->font_style_clist), index, -1,
394                          0.5, 0);
395     }
396       
397   /* Try to scroll the font size clist to the selected item */
398   selection = GTK_CLIST(fontsel->size_clist)->selection;
399   if (selection)
400     {
401       index = GPOINTER_TO_INT (selection->data);
402       if (gtk_clist_row_is_visible(GTK_CLIST(fontsel->size_clist), index)
403           != GTK_VISIBILITY_FULL)
404       gtk_clist_moveto(GTK_CLIST(fontsel->size_clist), index, -1, 0.5, 0);
405     }
406 }
407
408 /* This is called when a family is selected in the list. */
409 static void
410 gtk_font_selection_select_font (GtkWidget      *w,
411                                 gint            row,
412                                 gint            column,
413                                 GdkEventButton *bevent,
414                                 gpointer        data)
415 {
416   GtkFontSelection *fontsel;
417   gchar *family_name;
418   gint index;
419   
420   fontsel = GTK_FONT_SELECTION (data);
421
422   if (GTK_CLIST (fontsel->font_clist)->selection)
423     {
424       index = GPOINTER_TO_INT (GTK_CLIST (fontsel->font_clist)->selection->data);
425
426       if (gtk_clist_get_text (GTK_CLIST (fontsel->font_clist), index, 0, &family_name) &&
427           strcasecmp (fontsel->font_desc->family_name, family_name) != 0)
428         {
429           g_free (fontsel->font_desc->family_name);
430           fontsel->font_desc->family_name  = g_strdup (family_name);
431           
432           gtk_font_selection_show_available_styles (fontsel);
433           gtk_font_selection_select_best_style (fontsel, TRUE);
434         }
435     }
436 }
437
438 static int
439 cmp_strings (const void *a, const void *b)
440 {
441   return strcasecmp (*(const char **)a, *(const char **)b);
442 }
443
444 static void
445 gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
446 {
447   gchar **families;
448   int n_families, i;
449
450   pango_context_list_families (gtk_widget_get_pango_context (GTK_WIDGET (fontsel)),
451                                &families, &n_families);
452   qsort (families, n_families, sizeof(char *), cmp_strings);
453
454   gtk_clist_freeze (GTK_CLIST (fontsel->font_clist));
455   gtk_clist_clear (GTK_CLIST (fontsel->font_clist));
456
457   for (i=0; i<n_families; i++)
458     {
459       gtk_clist_append (GTK_CLIST (fontsel->font_clist), &families[i]);
460
461       if (!strcasecmp (families[i], fontsel->font_desc->family_name))
462         {
463           gtk_clist_select_row (GTK_CLIST(fontsel->font_clist), i, 0);
464           gtk_entry_set_text(GTK_ENTRY(fontsel->font_entry), families[i]);
465         }
466     }
467   
468   gtk_clist_thaw (GTK_CLIST(fontsel->font_clist));
469
470   pango_font_map_free_families (families, n_families);
471 }
472
473 static gint
474 gtk_font_selection_on_clist_key_press (GtkWidget        *clist,
475                                        GdkEventKey      *event,
476                                        GtkFontSelection *fontsel)
477 {
478 #ifdef FONTSEL_DEBUG
479   g_message("In on_clist_key_press\n");
480 #endif
481   if (event->keyval == GDK_Up)
482     return gtk_font_selection_select_next (fontsel, clist, -1);
483   else if (event->keyval == GDK_Down)
484     return gtk_font_selection_select_next (fontsel, clist, 1);
485   else
486     return FALSE;
487 }
488
489
490 static gboolean
491 gtk_font_selection_select_next (GtkFontSelection *fontsel,
492                                 GtkWidget        *clist,
493                                 gint              step)
494 {
495   GList *selection;
496   gint current_row, row;
497   
498   selection = GTK_CLIST(clist)->selection;
499   if (!selection)
500     return FALSE;
501   current_row = GPOINTER_TO_INT (selection->data);
502   
503   /* Stop the normal clist key handler from being run. */
504   gtk_signal_emit_stop_by_name (GTK_OBJECT (clist), "key_press_event");
505
506   for (row = current_row + step;
507        row >= 0 && row < GTK_CLIST(clist)->rows;
508        row += step)
509     {
510       /* If this is the style clist, make sure that the item is not a charset
511          entry. */
512       if (clist == fontsel->font_style_clist)
513         if (GPOINTER_TO_INT (gtk_clist_get_row_data(GTK_CLIST(clist), row)) == -1)
514           continue;
515       
516       /* Now we've found the row to select. */
517       if (gtk_clist_row_is_visible(GTK_CLIST(clist), row)
518           != GTK_VISIBILITY_FULL)
519         gtk_clist_moveto(GTK_CLIST(clist), row, -1, (step < 0) ? 0 : 1, 0);
520       gtk_clist_select_row(GTK_CLIST(clist), row, 0);
521       break;
522     }
523   return TRUE;
524 }
525
526 static int
527 compare_font_descriptions (const PangoFontDescription *a, const PangoFontDescription *b)
528 {
529   int val = strcasecmp (a->family_name, b->family_name);
530   if (val != 0)
531     return val;
532
533   if (a->weight != b->weight)
534     return a->weight - b->weight;
535
536   if (a->style != b->style)
537     return a->style - b->style;
538   
539   if (a->stretch != b->stretch)
540     return a->stretch - b->stretch;
541
542   if (a->variant != b->variant)
543     return a->variant - b->variant;
544
545   return 0;
546 }
547
548 static int
549 font_description_sort_func (const void *a, const void *b)
550 {
551   return compare_font_descriptions (*(PangoFontDescription **)a, *(PangoFontDescription **)b);
552 }
553
554 /* This fills the font style clist with all the possible style combinations
555    for the current font family. */
556 static void
557 gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
558 {
559   PangoFontDescription **descs;
560   int n_descs, i;
561   gint match_row = 0;
562   gchar *str;
563   
564   pango_context_list_fonts (gtk_widget_get_pango_context (GTK_WIDGET (fontsel)),
565                             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 (gtk_widget_get_pango_context (GTK_WIDGET (fontsel)),
837                             new_desc->family_name, &descs, &n_descs);
838
839   for (i=0; i<n_descs; i++)
840     {
841       if (descs[i]->weight == new_desc->weight &&
842           descs[i]->style == new_desc->style &&
843           descs[i]->stretch == new_desc->stretch &&
844           descs[i]->variant == new_desc->variant)
845         {
846           found = TRUE;
847           break;
848         }
849     }
850
851   pango_font_descriptions_free (descs, n_descs);
852
853   if (!found)
854     return FALSE;
855
856   pango_font_description_free (fontsel->font_desc);
857   fontsel->font_desc = new_desc;
858
859   return TRUE;
860 }
861
862
863 /* This returns the text in the preview entry. You should copy the returned
864    text if you need it. */
865 gchar*
866 gtk_font_selection_get_preview_text  (GtkFontSelection *fontsel)
867 {
868   return gtk_entry_get_text (GTK_ENTRY (fontsel->preview_entry));
869 }
870
871
872 /* This sets the text in the preview entry. */
873 void
874 gtk_font_selection_set_preview_text  (GtkFontSelection *fontsel,
875                                       const gchar         *text)
876 {
877   gtk_entry_set_text (GTK_ENTRY (fontsel->preview_entry), text);
878 }
879
880 /*****************************************************************************
881  * GtkFontSelectionDialog
882  *****************************************************************************/
883
884 GtkType
885 gtk_font_selection_dialog_get_type (void)
886 {
887   static guint font_selection_dialog_type = 0;
888   
889   if (!font_selection_dialog_type)
890     {
891       GtkTypeInfo fontsel_diag_info =
892       {
893         "GtkFontSelectionDialog",
894         sizeof (GtkFontSelectionDialog),
895         sizeof (GtkFontSelectionDialogClass),
896         (GtkClassInitFunc) gtk_font_selection_dialog_class_init,
897         (GtkObjectInitFunc) gtk_font_selection_dialog_init,
898         /* reserved_1 */ NULL,
899         /* reserved_2 */ NULL,
900         (GtkClassInitFunc) NULL,
901       };
902       
903       font_selection_dialog_type = gtk_type_unique (GTK_TYPE_WINDOW, &fontsel_diag_info);
904     }
905   
906   return font_selection_dialog_type;
907 }
908
909 static void
910 gtk_font_selection_dialog_class_init (GtkFontSelectionDialogClass *klass)
911 {
912   GtkObjectClass *object_class;
913   
914   object_class = (GtkObjectClass*) klass;
915   
916   font_selection_dialog_parent_class = gtk_type_class (GTK_TYPE_WINDOW);
917 }
918
919 static void
920 gtk_font_selection_dialog_init (GtkFontSelectionDialog *fontseldiag)
921 {
922   fontseldiag->dialog_width = -1;
923   fontseldiag->auto_resize = TRUE;
924   
925   gtk_widget_set_events(GTK_WIDGET(fontseldiag), GDK_STRUCTURE_MASK);
926   gtk_signal_connect (GTK_OBJECT (fontseldiag), "configure_event",
927                       (GtkSignalFunc) gtk_font_selection_dialog_on_configure,
928                       fontseldiag);
929   
930   gtk_container_set_border_width (GTK_CONTAINER (fontseldiag), 4);
931   gtk_window_set_policy(GTK_WINDOW(fontseldiag), FALSE, TRUE, TRUE);
932   
933   fontseldiag->main_vbox = gtk_vbox_new (FALSE, 4);
934   gtk_widget_show (fontseldiag->main_vbox);
935   gtk_container_add (GTK_CONTAINER (fontseldiag), fontseldiag->main_vbox);
936   
937   fontseldiag->fontsel = gtk_font_selection_new();
938   gtk_container_set_border_width (GTK_CONTAINER (fontseldiag->fontsel), 4);
939   gtk_widget_show (fontseldiag->fontsel);
940   gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
941                       fontseldiag->fontsel, TRUE, TRUE, 0);
942   
943   /* Create the action area */
944   fontseldiag->action_area = gtk_hbutton_box_new ();
945   gtk_button_box_set_layout(GTK_BUTTON_BOX(fontseldiag->action_area),
946                             GTK_BUTTONBOX_END);
947   gtk_button_box_set_spacing(GTK_BUTTON_BOX(fontseldiag->action_area), 5);
948   gtk_box_pack_start (GTK_BOX (fontseldiag->main_vbox),
949                       fontseldiag->action_area, FALSE, FALSE, 0);
950   gtk_widget_show (fontseldiag->action_area);
951   
952   fontseldiag->ok_button = gtk_button_new_with_label(_("OK"));
953   GTK_WIDGET_SET_FLAGS (fontseldiag->ok_button, GTK_CAN_DEFAULT);
954   gtk_widget_show(fontseldiag->ok_button);
955   gtk_box_pack_start (GTK_BOX (fontseldiag->action_area),
956                       fontseldiag->ok_button, TRUE, TRUE, 0);
957   gtk_widget_grab_default (fontseldiag->ok_button);
958   
959   fontseldiag->apply_button = gtk_button_new_with_label(_("Apply"));
960   GTK_WIDGET_SET_FLAGS (fontseldiag->apply_button, GTK_CAN_DEFAULT);
961   /*gtk_widget_show(fontseldiag->apply_button);*/
962   gtk_box_pack_start (GTK_BOX(fontseldiag->action_area),
963                       fontseldiag->apply_button, TRUE, TRUE, 0);
964   
965   fontseldiag->cancel_button = gtk_button_new_with_label(_("Cancel"));
966   GTK_WIDGET_SET_FLAGS (fontseldiag->cancel_button, GTK_CAN_DEFAULT);
967   gtk_widget_show(fontseldiag->cancel_button);
968   gtk_box_pack_start (GTK_BOX(fontseldiag->action_area),
969                       fontseldiag->cancel_button, TRUE, TRUE, 0);
970   
971   
972 }
973
974 GtkWidget*
975 gtk_font_selection_dialog_new   (const gchar      *title)
976 {
977   GtkFontSelectionDialog *fontseldiag;
978   
979   fontseldiag = gtk_type_new (GTK_TYPE_FONT_SELECTION_DIALOG);
980   gtk_window_set_title (GTK_WINDOW (fontseldiag),
981                         title ? title : _("Font Selection"));
982   
983   return GTK_WIDGET (fontseldiag);
984 }
985
986 gchar*
987 gtk_font_selection_dialog_get_font_name (GtkFontSelectionDialog *fsd)
988 {
989   return gtk_font_selection_get_font_name(GTK_FONT_SELECTION(fsd->fontsel));
990 }
991
992 GdkFont*
993 gtk_font_selection_dialog_get_font      (GtkFontSelectionDialog *fsd)
994 {
995   return gtk_font_selection_get_font(GTK_FONT_SELECTION(fsd->fontsel));
996 }
997
998 gboolean
999 gtk_font_selection_dialog_set_font_name (GtkFontSelectionDialog *fsd,
1000                                          const gchar      *fontname)
1001 {
1002   return gtk_font_selection_set_font_name(GTK_FONT_SELECTION(fsd->fontsel),
1003                                           fontname);
1004 }
1005
1006 gchar*
1007 gtk_font_selection_dialog_get_preview_text (GtkFontSelectionDialog *fsd)
1008 {
1009   return gtk_font_selection_get_preview_text(GTK_FONT_SELECTION(fsd->fontsel));
1010 }
1011
1012 void
1013 gtk_font_selection_dialog_set_preview_text (GtkFontSelectionDialog *fsd,
1014                                             const gchar   *text)
1015 {
1016   gtk_font_selection_set_preview_text(GTK_FONT_SELECTION(fsd->fontsel), text);
1017 }
1018
1019
1020 /* This turns auto-shrink off if the user resizes the width of the dialog.
1021    It also turns it back on again if the user resizes it back to its normal
1022    width. */
1023 static gint
1024 gtk_font_selection_dialog_on_configure (GtkWidget         *widget,
1025                                         GdkEventConfigure *event,
1026                                         GtkFontSelectionDialog *fsd)
1027 {
1028   /* This sets the initial width. */
1029   if (fsd->dialog_width == -1)
1030     fsd->dialog_width = event->width;
1031   else if (fsd->auto_resize && fsd->dialog_width != event->width)
1032     {
1033       fsd->auto_resize = FALSE;
1034       gtk_window_set_policy(GTK_WINDOW(fsd), FALSE, TRUE, FALSE);
1035     }
1036   else if (!fsd->auto_resize && fsd->dialog_width == event->width)
1037     {
1038       fsd->auto_resize = TRUE;
1039       gtk_window_set_policy(GTK_WINDOW(fsd), FALSE, TRUE, TRUE);
1040     }
1041   
1042   return FALSE;
1043 }