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 /*
33 * Modified to allow filtering of fonts for gretl, Allin Cottrell, 2002
34 */
35
36 #include "gretl.h" /* this must provide standard and GTK headers and
37 deal with gettext */
38 #include "dlgutils.h"
39 #include "gtkfontselhack.h"
40 #include "fontfilter.h"
41
42 #define FONT_DEBUG 0
43
44 #define GTK_TYPE_FNTHACK (gtk_fontsel_hack_get_type ())
45 #define GTK_FNTHACK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_FNTHACK, GtkFontselHack))
46 #define GTK_FNTHACK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FNTHACK, GtkFontselHackClass))
47 #define GTK_IS_FNTHACK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_FNTHACK))
48 #define GTK_IS_FNTHACK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FNTHACK))
49 #define GTK_FNTHACK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FNTHACK, GtkFontselHackClass))
50
51
52 #define GTK_TYPE_FNTHACK_DIALOG (gtk_fontsel_hack_dialog_get_type ())
53 #define GTK_FNTHACK_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_FNTHACK_DIALOG, GtkFontselHackDialog))
54 #define GTK_FNTHACK_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FNTHACK_DIALOG, GtkFontselHackDialogClass))
55 #define GTK_IS_FNTHACK_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_FNTHACK_DIALOG))
56 #define GTK_IS_FNTHACK_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FNTHACK_DIALOG))
57 #define GTK_FNTHACK_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FNTHACK_DIALOG, GtkFontselHackDialogClass))
58
59 #define GTK_TYPE_FONT_FILTER (gtk_font_filter_get_type())
60
61 struct _GtkFontselHack
62 {
63 GtkVBox parent_instance;
64
65 GtkWidget *font_entry;
66 GtkWidget *family_list;
67 GtkWidget *font_style_entry;
68 GtkWidget *face_list;
69 GtkWidget *size_entry;
70 GtkWidget *size_list;
71 GtkWidget *pixels_button;
72 GtkWidget *points_button;
73 GtkWidget *filter_button;
74 GtkWidget *preview_entry;
75
76 PangoFontFamily *family; /* Current family */
77 PangoFontFace *face; /* Current face */
78
79 gint size;
80 FontFilterType filter;
81 };
82
83 struct _GtkFontselHackClass
84 {
85 GtkVBoxClass parent_class;
86
87 /* Padding for future expansion */
88 void (*_gtk_reserved1) (void);
89 void (*_gtk_reserved2) (void);
90 void (*_gtk_reserved3) (void);
91 void (*_gtk_reserved4) (void);
92 };
93
94 struct _GtkFontselHackDialog
95 {
96 GtkDialog parent_instance;
97 GtkWidget *fontsel;
98 GtkWidget *main_vbox;
99 GtkWidget *action_area;
100 GtkWidget *ok_button;
101 GtkWidget *cancel_button;
102 /* If the user changes the width of the dialog, we turn auto-shrink off. */
103 gint dialog_width;
104 gboolean auto_resize;
105 };
106
107 struct _GtkFontselHackDialogClass
108 {
109 GtkDialogClass parent_class;
110
111 /* Padding for future expansion */
112 void (*_gtk_reserved1) (void);
113 void (*_gtk_reserved2) (void);
114 void (*_gtk_reserved3) (void);
115 void (*_gtk_reserved4) (void);
116 };
117
118 /* This is the default text shown in the preview entry, though the user
119 can set it. Remember that some fonts only have capital letters. */
120 #define PREVIEW_TEXT N_("abcdefghijk ABCDEFGHIJK")
121
122 /* This is the initial and maximum height of the preview entry (it expands
123 when large font sizes are selected). Initial height is also the minimum. */
124 #define INITIAL_PREVIEW_HEIGHT 44
125 #define MAX_PREVIEW_HEIGHT 300
126
127 /* These are the sizes of the font, style & size lists. */
128 #define FONT_LIST_HEIGHT 136
129 #define FONT_LIST_WIDTH 190
130 #define FONT_STYLE_LIST_WIDTH 170
131 #define FONT_SIZE_LIST_WIDTH 60
132
133 /* These are what we use as the standard font sizes, for the size list.
134 */
135 static const guint16 font_sizes[] = {
136 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 26, 28,
137 32, 36, 40, 48, 56, 64, 72
138 };
139
140 enum {
141 PROP_0,
142 PROP_FONT_NAME,
143 PROP_PREVIEW_TEXT,
144 PROP_FILTER
145 };
146
147 enum {
148 FAMILY_COLUMN,
149 FAMILY_NAME_COLUMN
150 };
151
152 enum {
153 FACE_COLUMN,
154 FACE_NAME_COLUMN
155 };
156
157 enum {
158 SIZE_COLUMN
159 };
160
161 static void gtk_fontsel_hack_class_init (GtkFontselHackClass *klass);
162 static void gtk_fontsel_hack_set_property (GObject *object,
163 guint prop_id,
164 const GValue *value,
165 GParamSpec *pspec);
166 static void gtk_fontsel_hack_get_property (GObject *object,
167 guint prop_id,
168 GValue *value,
169 GParamSpec *pspec);
170 static void gtk_fontsel_hack_init (GtkFontselHack *fontsel);
171 static void gtk_fontsel_hack_finalize (GObject *object);
172
173 /* These are the callbacks & related functions. */
174 static void gtk_fontsel_hack_select_font (GtkTreeSelection *selection,
175 gpointer data);
176 static void gtk_fontsel_hack_show_available_fonts (GtkFontselHack *fs);
177
178 static void gtk_fontsel_hack_show_available_styles (GtkFontselHack *fs);
179 static void gtk_fontsel_hack_select_best_style (GtkFontselHack *fs,
180 gboolean use_first);
181 static void gtk_fontsel_hack_select_style (GtkTreeSelection *selection,
182 gpointer data);
183
184 static void gtk_fontsel_hack_select_best_size (GtkFontselHack *fs);
185 static void gtk_fontsel_hack_show_available_sizes (GtkFontselHack *fs,
186 gboolean first_time);
187 static void gtk_fontsel_hack_size_activate (GtkWidget *w,
188 gpointer data);
189 static gboolean gtk_fontsel_hack_size_focus_out (GtkWidget *w,
190 GdkEventFocus *event,
191 gpointer data);
192 static void gtk_fontsel_hack_select_size (GtkTreeSelection *selection,
193 gpointer data);
194
195 static void gtk_fontsel_hack_scroll_on_map (GtkWidget *w,
196 gpointer data);
197
198 static void gtk_fontsel_hack_screen_changed (GtkWidget *widget,
199 GdkScreen *previous_screen);
200
201 static void gtk_fontsel_hack_preview_changed (GtkWidget *entry,
202 GtkFontselHack *fontsel);
203
204 /* Misc. utility functions. */
205 static void gtk_fontsel_hack_load_font (GtkFontselHack *fs);
206 static void gtk_fontsel_hack_update_preview (GtkFontselHack *fs);
207
208 /* FontselHackDialog */
209 static void gtk_fontsel_hack_dialog_class_init (GtkFontselHackDialogClass *klass);
210 static void gtk_fontsel_hack_dialog_init (GtkFontselHackDialog *fontseldiag);
211
212 static gint gtk_fontsel_hack_dialog_on_configure (GtkWidget *widget,
213 GdkEventConfigure *event,
214 GtkFontselHackDialog *fsd);
215
gtk_font_filter_get_type(void)216 GType gtk_font_filter_get_type (void)
217 {
218 static GType etype = 0;
219
220 if (etype == 0) {
221 static const GEnumValue values[] = {
222 { FONT_HACK_NONE, "FONT_HACK_NONE", "use no font filter" },
223 { FONT_HACK_LATIN, "FONT_HACK_LATIN", "latin text fonts" },
224 { FONT_HACK_LATIN_MONO, "FONT_HACK_LATIN_MONO", "monospaced latin text fonts" },
225 { 0, NULL, NULL }
226 };
227
228 etype = g_enum_register_static("GtkFontFilter", values);
229 }
230
231 return etype;
232 }
233
G_DEFINE_TYPE(GtkFontselHack,gtk_fontsel_hack,GTK_TYPE_VBOX)234 G_DEFINE_TYPE (GtkFontselHack, gtk_fontsel_hack, GTK_TYPE_VBOX)
235
236 static void
237 gtk_fontsel_hack_class_init (GtkFontselHackClass *klass)
238 {
239 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
240 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
241
242 gobject_class->set_property = gtk_fontsel_hack_set_property;
243 gobject_class->get_property = gtk_fontsel_hack_get_property;
244
245 widget_class->screen_changed = gtk_fontsel_hack_screen_changed;
246
247 g_object_class_install_property(gobject_class,
248 PROP_FONT_NAME,
249 g_param_spec_string("font-name",
250 _("Font name"),
251 _("The X string that represents this font"),
252 NULL,
253 G_PARAM_READWRITE));
254 g_object_class_install_property(gobject_class,
255 PROP_PREVIEW_TEXT,
256 g_param_spec_string("preview-text",
257 _("Preview text"),
258 _("The text to display in order to demonstrate the selected font"),
259 PREVIEW_TEXT,
260 G_PARAM_READWRITE));
261 g_object_class_install_property(gobject_class,
262 PROP_FILTER,
263 g_param_spec_enum("filter",
264 _("Filter"),
265 _("The filter for acceptable fonts."),
266 GTK_TYPE_FONT_FILTER,
267 FONT_HACK_NONE,
268 G_PARAM_READWRITE));
269
270 gobject_class->finalize = gtk_fontsel_hack_finalize;
271 }
272
273 static void
gtk_fontsel_hack_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)274 gtk_fontsel_hack_set_property (GObject *object,
275 guint prop_id,
276 const GValue *value,
277 GParamSpec *pspec)
278 {
279 GtkFontselHack *fontsel;
280
281 fontsel = GTK_FNTHACK(object);
282
283 switch (prop_id) {
284 case PROP_FONT_NAME:
285 gtk_fontsel_hack_set_font_name(fontsel, g_value_get_string(value));
286 break;
287 case PROP_PREVIEW_TEXT:
288 gtk_fontsel_hack_set_preview_text(fontsel, g_value_get_string(value));
289 break;
290 default:
291 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
292 break;
293 }
294 }
295
gtk_fontsel_hack_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)296 static void gtk_fontsel_hack_get_property (GObject *object,
297 guint prop_id,
298 GValue *value,
299 GParamSpec *pspec)
300 {
301 GtkFontselHack *fontsel;
302
303 fontsel = GTK_FNTHACK(object);
304
305 switch (prop_id) {
306 case PROP_FONT_NAME:
307 g_value_set_string(value, gtk_fontsel_hack_get_font_name(fontsel));
308 break;
309 case PROP_PREVIEW_TEXT:
310 g_value_set_string(value, gtk_fontsel_hack_get_preview_text(fontsel));
311 break;
312 case PROP_FILTER:
313 g_value_set_int(value, gtk_fontsel_hack_get_filter(fontsel));
314 break;
315 default:
316 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
317 break;
318 }
319 }
320
321 static void
gtk_fontsel_hack_init(GtkFontselHack * fontsel)322 gtk_fontsel_hack_init (GtkFontselHack *fontsel)
323 {
324 GtkWidget *scrolled_win;
325 GtkWidget *text_frame;
326 GtkWidget *text_box;
327 GtkWidget *table, *label;
328 GtkWidget *font_label, *style_label;
329 GtkListStore *model;
330 GtkTreeViewColumn *column;
331 GList *focus_chain = NULL;
332
333 gtk_widget_push_composite_child();
334
335 fontsel->size = 12 * PANGO_SCALE;
336 fontsel->filter = FONT_HACK_NONE;
337
338 /* Create the table of font, style & size */
339 table = gtk_table_new(3, 3, FALSE);
340 gtk_widget_show(table);
341 gtk_table_set_col_spacings(GTK_TABLE (table), 8);
342 gtk_box_pack_start(GTK_BOX(fontsel), table, TRUE, TRUE, 0);
343
344 fontsel->size_entry = gtk_entry_new();
345 gtk_widget_set_size_request(fontsel->size_entry, 20, -1);
346 gtk_widget_show(fontsel->size_entry);
347 gtk_table_attach(GTK_TABLE(table), fontsel->size_entry, 2, 3, 1, 2,
348 GTK_FILL, 0, 0, 0);
349 g_signal_connect(G_OBJECT(fontsel->size_entry), "activate",
350 (GCallback) gtk_fontsel_hack_size_activate,
351 fontsel);
352 g_signal_connect_after(G_OBJECT(fontsel->size_entry), "focus-out-event",
353 (GCallback) gtk_fontsel_hack_size_focus_out,
354 fontsel);
355
356 font_label = gtk_label_new_with_mnemonic(_("_Family:"));
357 gtk_misc_set_alignment(GTK_MISC(font_label), 0.0, 0.5);
358 gtk_widget_show(font_label);
359 gtk_table_attach(GTK_TABLE(table), font_label, 0, 1, 0, 1,
360 GTK_FILL, 0, 0, 0);
361
362 style_label = gtk_label_new_with_mnemonic(_("_Style:"));
363 gtk_misc_set_alignment(GTK_MISC(style_label), 0.0, 0.5);
364 gtk_widget_show(style_label);
365 gtk_table_attach(GTK_TABLE(table), style_label, 1, 2, 0, 1,
366 GTK_FILL, 0, 0, 0);
367
368 label = gtk_label_new_with_mnemonic(_("Si_ze:"));
369 gtk_label_set_mnemonic_widget(GTK_LABEL(label),
370 fontsel->size_entry);
371 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
372 gtk_widget_show(label);
373 gtk_table_attach(GTK_TABLE(table), label, 2, 3, 0, 1,
374 GTK_FILL, 0, 0, 0);
375
376
377 /* Create the lists */
378
379 model = gtk_list_store_new(2,
380 G_TYPE_OBJECT, /* FAMILY_COLUMN */
381 G_TYPE_STRING); /* FAMILY_NAME_COLUMN */
382 fontsel->family_list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
383 g_object_unref(model);
384
385 column = gtk_tree_view_column_new_with_attributes("Family",
386 gtk_cell_renderer_text_new(),
387 "text", FAMILY_NAME_COLUMN,
388 NULL);
389 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
390 gtk_tree_view_append_column(GTK_TREE_VIEW(fontsel->family_list), column);
391
392 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(fontsel->family_list), FALSE);
393 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(fontsel->family_list)),
394 GTK_SELECTION_BROWSE);
395
396 gtk_label_set_mnemonic_widget(GTK_LABEL(font_label), fontsel->family_list);
397
398 scrolled_win = gtk_scrolled_window_new(NULL, NULL);
399 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_win), GTK_SHADOW_IN);
400 gtk_widget_set_size_request(scrolled_win, FONT_LIST_WIDTH, FONT_LIST_HEIGHT);
401 gtk_container_add(GTK_CONTAINER(scrolled_win), fontsel->family_list);
402 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_win),
403 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
404 gtk_widget_show(fontsel->family_list);
405 gtk_widget_show(scrolled_win);
406
407 gtk_table_attach(GTK_TABLE(table), scrolled_win, 0, 1, 1, 3,
408 GTK_EXPAND | GTK_FILL,
409 GTK_EXPAND | GTK_FILL, 0, 0);
410 focus_chain = g_list_append(focus_chain, scrolled_win);
411
412 model = gtk_list_store_new(2,
413 G_TYPE_OBJECT, /* FACE_COLUMN */
414 G_TYPE_STRING); /* FACE_NAME_COLUMN */
415 fontsel->face_list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
416 g_object_unref(model);
417
418 gtk_label_set_mnemonic_widget(GTK_LABEL(style_label), fontsel->face_list);
419
420 column = gtk_tree_view_column_new_with_attributes("Face",
421 gtk_cell_renderer_text_new(),
422 "text", FACE_NAME_COLUMN,
423 NULL);
424 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
425 gtk_tree_view_append_column(GTK_TREE_VIEW(fontsel->face_list), column);
426
427 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(fontsel->face_list), FALSE);
428 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(fontsel->face_list)),
429 GTK_SELECTION_BROWSE);
430
431 scrolled_win = gtk_scrolled_window_new(NULL, NULL);
432 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_win), GTK_SHADOW_IN);
433 gtk_widget_set_size_request(scrolled_win, FONT_STYLE_LIST_WIDTH, FONT_LIST_HEIGHT);
434 gtk_container_add(GTK_CONTAINER(scrolled_win), fontsel->face_list);
435 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_win),
436 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
437 gtk_widget_show(fontsel->face_list);
438 gtk_widget_show(scrolled_win);
439 gtk_table_attach(GTK_TABLE(table), scrolled_win, 1, 2, 1, 3,
440 GTK_EXPAND | GTK_FILL,
441 GTK_EXPAND | GTK_FILL, 0, 0);
442 focus_chain = g_list_append(focus_chain, scrolled_win);
443
444 focus_chain = g_list_append(focus_chain, fontsel->size_entry);
445
446 model = gtk_list_store_new(1, G_TYPE_INT);
447 fontsel->size_list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
448 g_object_unref(model);
449
450 column = gtk_tree_view_column_new_with_attributes("Size",
451 gtk_cell_renderer_text_new(),
452 "text", SIZE_COLUMN,
453 NULL);
454 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
455 gtk_tree_view_append_column(GTK_TREE_VIEW(fontsel->size_list), column);
456
457 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(fontsel->size_list), FALSE);
458 gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(fontsel->size_list)),
459 GTK_SELECTION_BROWSE);
460
461 scrolled_win = gtk_scrolled_window_new(NULL, NULL);
462 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_win), GTK_SHADOW_IN);
463 gtk_container_add(GTK_CONTAINER(scrolled_win), fontsel->size_list);
464 gtk_widget_set_size_request(scrolled_win, -1, FONT_LIST_HEIGHT);
465 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_win),
466 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
467 gtk_widget_show(fontsel->size_list);
468 gtk_widget_show(scrolled_win);
469 gtk_table_attach(GTK_TABLE(table), scrolled_win, 2, 3, 2, 3,
470 GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
471 focus_chain = g_list_append(focus_chain, scrolled_win);
472
473 gtk_container_set_focus_chain(GTK_CONTAINER(table), focus_chain);
474 g_list_free(focus_chain);
475
476 /* Insert the fonts. */
477 gtk_fontsel_hack_show_available_fonts(fontsel);
478
479 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(fontsel->family_list)), "changed",
480 G_CALLBACK(gtk_fontsel_hack_select_font), fontsel);
481
482 g_signal_connect_after(G_OBJECT(fontsel->family_list), "map",
483 G_CALLBACK(gtk_fontsel_hack_scroll_on_map),
484 fontsel);
485
486 gtk_fontsel_hack_show_available_styles(fontsel);
487
488 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(fontsel->face_list)), "changed",
489 G_CALLBACK(gtk_fontsel_hack_select_style), fontsel);
490
491 gtk_fontsel_hack_show_available_sizes(fontsel, TRUE);
492
493 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(fontsel->size_list)), "changed",
494 G_CALLBACK(gtk_fontsel_hack_select_size), fontsel);
495
496 /* create the text entry widget */
497 label = gtk_label_new_with_mnemonic(_("_Preview:"));
498 gtk_widget_show(label);
499
500 text_frame = gtk_frame_new(NULL);
501 gtk_frame_set_label_widget(GTK_FRAME(text_frame), label);
502
503 gtk_widget_show(text_frame);
504 gtk_frame_set_shadow_type(GTK_FRAME(text_frame), GTK_SHADOW_ETCHED_IN);
505 gtk_box_pack_start(GTK_BOX(fontsel), text_frame,
506 FALSE, TRUE, 0);
507
508 /* This is just used to get a 4-pixel space around the preview entry. */
509 text_box = gtk_hbox_new(FALSE, 0);
510 gtk_widget_show(text_box);
511 gtk_container_add(GTK_CONTAINER(text_frame), text_box);
512 gtk_container_set_border_width(GTK_CONTAINER(text_box), 4);
513
514 fontsel->preview_entry = gtk_entry_new();
515 gtk_label_set_mnemonic_widget(GTK_LABEL(label), fontsel->preview_entry);
516
517 gtk_widget_show(fontsel->preview_entry);
518 g_signal_connect(G_OBJECT(fontsel->preview_entry), "changed",
519 (GCallback) gtk_fontsel_hack_preview_changed,
520 fontsel);
521 gtk_widget_set_size_request(fontsel->preview_entry, -1, INITIAL_PREVIEW_HEIGHT);
522 gtk_box_pack_start(GTK_BOX(text_box), fontsel->preview_entry,
523 TRUE, TRUE, 0);
524
525 gtk_fontsel_hack_update_preview(fontsel);
526
527 gtk_widget_pop_composite_child();
528 }
529
530 static void
gtk_fontsel_hack_display_fonts(GtkFontselHack * fontsel)531 gtk_fontsel_hack_display_fonts (GtkFontselHack *fontsel)
532 {
533 /* Insert the (possibly revised) list of fonts. */
534 gtk_fontsel_hack_show_available_fonts(fontsel);
535 gtk_fontsel_hack_show_available_styles(fontsel);
536 gtk_fontsel_hack_show_available_sizes(fontsel, TRUE);
537 }
538
539 GtkWidget *
gtk_fontsel_hack_new(void)540 gtk_fontsel_hack_new (void)
541 {
542 GtkFontselHack *fontsel;
543
544 fontsel = g_object_new(GTK_TYPE_FNTHACK, NULL);
545
546 return GTK_WIDGET(fontsel);
547 }
548
549 static void
gtk_fontsel_hack_finalize(GObject * object)550 gtk_fontsel_hack_finalize (GObject *object)
551 {
552 g_return_if_fail(GTK_IS_FNTHACK(object));
553
554 (* G_OBJECT_CLASS (gtk_fontsel_hack_parent_class)->finalize) (object);
555 }
556
557 static void
gtk_fontsel_hack_screen_changed(GtkWidget * widget,GdkScreen * previous_screen)558 gtk_fontsel_hack_screen_changed (GtkWidget *widget,
559 GdkScreen *previous_screen)
560 {
561 GtkFontselHack *fontsel = GTK_FNTHACK(widget);
562
563 if (gtk_widget_has_screen(GTK_WIDGET(fontsel))) {
564 gtk_fontsel_hack_show_available_fonts(fontsel);
565 gtk_fontsel_hack_show_available_sizes(fontsel, TRUE);
566 gtk_fontsel_hack_show_available_styles(fontsel);
567 }
568 }
569
570 static void
gtk_fontsel_hack_preview_changed(GtkWidget * entry,GtkFontselHack * fontsel)571 gtk_fontsel_hack_preview_changed (GtkWidget *entry,
572 GtkFontselHack *fontsel)
573 {
574 g_object_notify(G_OBJECT(fontsel), "preview_text");
575 }
576
577 static void
scroll_to_selection(GtkTreeView * tree_view)578 scroll_to_selection (GtkTreeView *tree_view)
579 {
580 GtkTreeSelection *selection = gtk_tree_view_get_selection(tree_view);
581 GtkTreeModel *model;
582 GtkTreeIter iter;
583
584 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
585 GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
586
587 gtk_tree_view_scroll_to_cell(tree_view, path, NULL, TRUE, 0.5, 0.5);
588 gtk_tree_path_free(path);
589 }
590 }
591
592 static void
set_cursor_to_iter(GtkTreeView * view,GtkTreeIter * iter)593 set_cursor_to_iter (GtkTreeView *view,
594 GtkTreeIter *iter)
595 {
596 GtkTreeModel *model = gtk_tree_view_get_model(view);
597 GtkTreePath *path = gtk_tree_model_get_path(model, iter);
598
599 if (path != NULL) {
600 gtk_tree_view_set_cursor(view, path, 0, FALSE);
601 gtk_tree_path_free(path);
602 }
603 }
604
605 /* This is called when the list is mapped. Here we scroll to the current
606 font if necessary. */
607 static void
gtk_fontsel_hack_scroll_on_map(GtkWidget * widget,gpointer data)608 gtk_fontsel_hack_scroll_on_map (GtkWidget *widget,
609 gpointer data)
610 {
611 GtkFontselHack *fontsel;
612
613 fontsel = GTK_FNTHACK (data);
614
615 /* Try to scroll the font family list to the selected item */
616 scroll_to_selection(GTK_TREE_VIEW(fontsel->family_list));
617
618 /* Try to scroll the font family list to the selected item */
619 scroll_to_selection(GTK_TREE_VIEW(fontsel->face_list));
620
621 /* Try to scroll the font family list to the selected item */
622 scroll_to_selection(GTK_TREE_VIEW(fontsel->size_list));
623 }
624
625 /* This is called when a family is selected in the list. */
626 static void
gtk_fontsel_hack_select_font(GtkTreeSelection * selection,gpointer data)627 gtk_fontsel_hack_select_font (GtkTreeSelection *selection,
628 gpointer data)
629 {
630 GtkFontselHack *fontsel;
631 GtkTreeModel *model;
632 GtkTreeIter iter;
633
634 fontsel = GTK_FNTHACK(data);
635
636 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
637 PangoFontFamily *family;
638
639 gtk_tree_model_get(model, &iter, FAMILY_COLUMN, &family, -1);
640 if (fontsel->family != family) {
641 fontsel->family = family;
642 gtk_fontsel_hack_show_available_styles(fontsel);
643 gtk_fontsel_hack_select_best_style(fontsel, TRUE);
644 }
645
646 g_object_unref(family);
647 }
648 }
649
650 static int
cmp_families(const void * a,const void * b)651 cmp_families (const void *a, const void *b)
652 {
653 const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a);
654 const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b);
655
656 return g_utf8_collate(a_name, b_name);
657 }
658
659 static void
gtk_fontsel_hack_show_available_fonts(GtkFontselHack * fontsel)660 gtk_fontsel_hack_show_available_fonts (GtkFontselHack *fontsel)
661 {
662 GtkTreeModel *model;
663 GtkListStore *store;
664 PangoContext *context;
665 PangoFontFamily **families;
666 const char *famname;
667 gint nf, i, got_ok;
668 GtkTreeIter iter, match_iter;
669 gint err = 0;
670
671 model = gtk_tree_view_get_model(GTK_TREE_VIEW(fontsel->family_list));
672 store = GTK_LIST_STORE(model);
673 gtk_list_store_clear(store);
674
675 context = gtk_widget_get_pango_context(GTK_WIDGET(fontsel));
676 pango_context_list_families(context, &families, &nf);
677 qsort(families, nf, sizeof *families, cmp_families);
678
679 #if FONT_DEBUG
680 fprintf(stderr, "Font selector: got %d families\n", nf);
681 #endif
682
683 fontsel->family = NULL;
684 got_ok = 0;
685
686 gtk_tree_model_get_iter_first(model, &iter);
687
688 for (i=0; i<nf && !err; i++) {
689 famname = pango_font_family_get_name(families[i]);
690 if (famname == NULL) {
691 /* bullet-proofing */
692 continue;
693 }
694
695 #if FONT_DEBUG
696 fprintf(stderr, "Examining font family '%s'\n", famname);
697 #endif
698 if (!validate_font_family(families[i], famname, i, nf, fontsel->filter, &err)) {
699 continue;
700 }
701
702 gtk_list_store_append(store, &iter);
703 gtk_list_store_set(store, &iter,
704 FAMILY_COLUMN, families[i],
705 FAMILY_NAME_COLUMN, famname,
706 -1);
707
708 if (!got_ok) {
709 if (fontsel->filter != FONT_HACK_NONE ||
710 i == 0 || !g_ascii_strcasecmp(famname, "sans")) {
711 got_ok = 1;
712 fontsel->family = families[i];
713 match_iter = iter;
714 }
715 }
716 }
717
718 if (fontsel->family != NULL) {
719 set_cursor_to_iter(GTK_TREE_VIEW(fontsel->family_list), &match_iter);
720 }
721
722 g_free(families);
723 }
724
725 static int
compare_font_descriptions(const PangoFontDescription * a,const PangoFontDescription * b)726 compare_font_descriptions (const PangoFontDescription *a,
727 const PangoFontDescription *b)
728 {
729 int val = strcmp(pango_font_description_get_family(a),
730 pango_font_description_get_family(b));
731
732 if (val != 0) {
733 return val;
734 }
735
736 if (pango_font_description_get_weight(a) !=
737 pango_font_description_get_weight(b))
738 return pango_font_description_get_weight(a) -
739 pango_font_description_get_weight(b);
740
741 if (pango_font_description_get_style(a) !=
742 pango_font_description_get_style(b))
743 return pango_font_description_get_style(a) -
744 pango_font_description_get_style(b);
745
746 if (pango_font_description_get_stretch(a) !=
747 pango_font_description_get_stretch(b))
748 return pango_font_description_get_stretch(a) -
749 pango_font_description_get_stretch(b);
750
751 if (pango_font_description_get_variant(a) !=
752 pango_font_description_get_variant(b))
753 return pango_font_description_get_variant(a) -
754 pango_font_description_get_variant(b);
755
756 return 0;
757 }
758
759 static int
faces_sort_func(const void * a,const void * b)760 faces_sort_func (const void *a, const void *b)
761 {
762 PangoFontDescription *desc_a = pango_font_face_describe(*(PangoFontFace **)a);
763 PangoFontDescription *desc_b = pango_font_face_describe(*(PangoFontFace **)b);
764
765 int ord = compare_font_descriptions(desc_a, desc_b);
766
767 pango_font_description_free(desc_a);
768 pango_font_description_free(desc_b);
769
770 return ord;
771 }
772
773 static gboolean
font_description_style_equal(const PangoFontDescription * a,const PangoFontDescription * b)774 font_description_style_equal (const PangoFontDescription *a,
775 const PangoFontDescription *b)
776 {
777 return (pango_font_description_get_weight(a) ==
778 pango_font_description_get_weight(b) &&
779 pango_font_description_get_style(a) ==
780 pango_font_description_get_style(b) &&
781 pango_font_description_get_stretch(a) ==
782 pango_font_description_get_stretch(b) &&
783 pango_font_description_get_variant(a) ==
784 pango_font_description_get_variant(b));
785 }
786
787 /* This fills the font style list with all the possible style combinations
788 for the current font family. */
789
790 static void
gtk_fontsel_hack_show_available_styles(GtkFontselHack * fontsel)791 gtk_fontsel_hack_show_available_styles (GtkFontselHack *fontsel)
792 {
793 gint n_faces, i;
794 PangoFontFace **faces;
795 PangoFontDescription *old_desc;
796 GtkListStore *model;
797 GtkTreeIter iter, match_row;
798 PangoFontFace *match_face = NULL;
799
800 model = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(fontsel->face_list)));
801
802 if (fontsel->face) {
803 old_desc = pango_font_face_describe(fontsel->face);
804 } else {
805 old_desc= NULL;
806 }
807
808 pango_font_family_list_faces(fontsel->family, &faces, &n_faces);
809 qsort(faces, n_faces, sizeof *faces, faces_sort_func);
810
811 gtk_list_store_clear(model);
812 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter);
813
814 for (i=0; i<n_faces; i++) {
815 const gchar *str = pango_font_face_get_face_name(faces[i]);
816
817 gtk_list_store_append(model, &iter);
818 gtk_list_store_set(model, &iter,
819 FACE_COLUMN, faces[i],
820 FACE_NAME_COLUMN, str,
821 -1);
822
823 if (i == 0) {
824 match_row = iter;
825 match_face = faces[i];
826 } else if (old_desc) {
827 PangoFontDescription *tmp_desc = pango_font_face_describe(faces[i]);
828
829 if (font_description_style_equal(tmp_desc, old_desc)) {
830 match_row = iter;
831 match_face = faces[i];
832 }
833 pango_font_description_free(tmp_desc);
834 }
835 }
836
837 if (old_desc != NULL) {
838 pango_font_description_free(old_desc);
839 }
840
841 fontsel->face = match_face;
842 if (match_face) {
843 set_cursor_to_iter(GTK_TREE_VIEW(fontsel->face_list), &match_row);
844 }
845
846 g_free(faces);
847 }
848
849 /* This selects a style when the user selects a font. It just uses the first
850 available style at present. I was thinking of trying to maintain the
851 selected style, e.g. bold italic, when the user selects different fonts.
852 However, the interface is so easy to use now I'm not sure it's worth it.
853 Note: This will load a font. */
854
855 static void
gtk_fontsel_hack_select_best_style(GtkFontselHack * fontsel,gboolean use_first)856 gtk_fontsel_hack_select_best_style (GtkFontselHack *fontsel,
857 gboolean use_first)
858 {
859 GtkTreeIter iter;
860 GtkTreeModel *model;
861
862 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
863
864 if (gtk_tree_model_get_iter_first (model, &iter)) {
865 set_cursor_to_iter(GTK_TREE_VIEW(fontsel->face_list), &iter);
866 scroll_to_selection(GTK_TREE_VIEW(fontsel->face_list));
867 }
868
869 gtk_fontsel_hack_show_available_sizes(fontsel, FALSE);
870 gtk_fontsel_hack_select_best_size(fontsel);
871 }
872
873
874 /* This is called when a style is selected in the list. */
875
876 static void
gtk_fontsel_hack_select_style(GtkTreeSelection * selection,gpointer data)877 gtk_fontsel_hack_select_style (GtkTreeSelection *selection,
878 gpointer data)
879 {
880 GtkFontselHack *fontsel = GTK_FNTHACK(data);
881 GtkTreeModel *model;
882 GtkTreeIter iter;
883
884 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
885 PangoFontFace *face;
886
887 gtk_tree_model_get(model, &iter, FACE_COLUMN, &face, -1);
888 fontsel->face = face;
889
890 g_object_unref(face);
891 }
892
893 gtk_fontsel_hack_show_available_sizes(fontsel, FALSE);
894 gtk_fontsel_hack_select_best_size(fontsel);
895 }
896
897 static void
gtk_fontsel_hack_show_available_sizes(GtkFontselHack * fontsel,gboolean first_time)898 gtk_fontsel_hack_show_available_sizes (GtkFontselHack *fontsel,
899 gboolean first_time)
900 {
901 size_t i;
902 GtkListStore *model;
903 gchar buffer[128];
904 gchar *p;
905
906 model = GTK_LIST_STORE(gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->size_list)));
907
908 /* Insert the standard font sizes */
909 if (first_time) {
910 GtkTreeIter iter;
911
912 gtk_list_store_clear (model);
913 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
914
915 for (i = 0; i < G_N_ELEMENTS (font_sizes); i++) {
916 gtk_list_store_append (model, &iter);
917 gtk_list_store_set (model, &iter, SIZE_COLUMN, font_sizes[i], -1);
918
919 if (font_sizes[i] * PANGO_SCALE == fontsel->size)
920 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
921 }
922 } else {
923 GtkTreeIter iter;
924 gboolean found = FALSE;
925
926 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
927 for (i = 0; i < G_N_ELEMENTS (font_sizes) && !found; i++) {
928 if (font_sizes[i] * PANGO_SCALE == fontsel->size) {
929 set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
930 found = TRUE;
931 }
932
933 gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter);
934 }
935
936 if (!found) {
937 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
938
939 gtk_tree_selection_unselect_all (selection);
940 }
941 }
942
943 /* Set the entry to the new size, rounding to 1 digit,
944 * trimming of trailing 0's and a trailing period
945 */
946 sprintf (buffer, "%.1f", fontsel->size / (1.0 * PANGO_SCALE));
947 if (strchr (buffer, '.')) {
948 p = buffer + strlen (buffer) - 1;
949 while (*p == '0')
950 p--;
951 if (*p == '.')
952 p--;
953 p[1] = '\0';
954 }
955
956 /* Compare, to avoid moving the cursor unecessarily */
957 if (strcmp (gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry)), buffer) != 0)
958 gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
959 }
960
961 static void
gtk_fontsel_hack_select_best_size(GtkFontselHack * fontsel)962 gtk_fontsel_hack_select_best_size (GtkFontselHack *fontsel)
963 {
964 gtk_fontsel_hack_load_font(fontsel);
965 }
966
967 static void
gtk_fontsel_hack_set_size(GtkFontselHack * fontsel,gint new_size)968 gtk_fontsel_hack_set_size (GtkFontselHack *fontsel,
969 gint new_size)
970 {
971 if (fontsel->size != new_size) {
972 fontsel->size = new_size;
973
974 gtk_fontsel_hack_show_available_sizes (fontsel, FALSE);
975 gtk_fontsel_hack_load_font (fontsel);
976 }
977 }
978
979 /* If the user hits return in the font size entry, we change to the new font
980 size. */
981
982 static void
gtk_fontsel_hack_size_activate(GtkWidget * w,gpointer data)983 gtk_fontsel_hack_size_activate (GtkWidget *w,
984 gpointer data)
985 {
986 GtkFontselHack *fontsel;
987 gint new_size;
988 const gchar *text;
989
990 fontsel = GTK_FNTHACK(data);
991
992 text = gtk_entry_get_text(GTK_ENTRY(fontsel->size_entry));
993 new_size = (int) MAX(0.1, atof(text) * PANGO_SCALE + 0.5);
994
995 gtk_fontsel_hack_set_size(fontsel, new_size);
996 }
997
998 static gboolean
gtk_fontsel_hack_size_focus_out(GtkWidget * w,GdkEventFocus * event,gpointer data)999 gtk_fontsel_hack_size_focus_out (GtkWidget*w,
1000 GdkEventFocus *event,
1001 gpointer data)
1002 {
1003 gtk_fontsel_hack_size_activate(w, data);
1004
1005 return TRUE;
1006 }
1007
1008 /* This is called when a size is selected in the list. */
1009
1010 static void
gtk_fontsel_hack_select_size(GtkTreeSelection * selection,gpointer data)1011 gtk_fontsel_hack_select_size (GtkTreeSelection *selection,
1012 gpointer data)
1013 {
1014 GtkFontselHack *fontsel;
1015 GtkTreeModel *model;
1016 GtkTreeIter iter;
1017 gint new_size;
1018
1019 fontsel = GTK_FNTHACK(data);
1020
1021 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
1022 gtk_tree_model_get(model, &iter, SIZE_COLUMN, &new_size, -1);
1023 gtk_fontsel_hack_set_size(fontsel, new_size * PANGO_SCALE);
1024 }
1025 }
1026
1027 static void
gtk_fontsel_hack_load_font(GtkFontselHack * fontsel)1028 gtk_fontsel_hack_load_font (GtkFontselHack *fontsel)
1029 {
1030 gtk_fontsel_hack_update_preview(fontsel);
1031 }
1032
1033 static PangoFontDescription *
gtk_fontsel_hack_get_font_description(GtkFontselHack * fontsel)1034 gtk_fontsel_hack_get_font_description (GtkFontselHack *fontsel)
1035 {
1036 PangoFontDescription *font_desc = pango_font_face_describe(fontsel->face);
1037
1038 pango_font_description_set_size(font_desc, fontsel->size);
1039
1040 return font_desc;
1041 }
1042
1043 /* This sets the font in the preview entry to the selected font, and
1044 tries to make sure that the preview entry is a reasonable size,
1045 i.e. so that the text can be seen with a bit of space to spare. But
1046 it tries to avoid resizing the entry every time the font changes.
1047 This is also used to shrink the preview if the font size was
1048 decreased, but that made it awkward if the users wanted to resize
1049 the window themselves. */
1050
1051 static void
gtk_fontsel_hack_update_preview(GtkFontselHack * fontsel)1052 gtk_fontsel_hack_update_preview (GtkFontselHack *fontsel)
1053 {
1054 #if GTK_MAJOR_VERSION < 3
1055 GtkRcStyle *rc_style;
1056 #endif
1057 gint new_height;
1058 GtkRequisition req, old_requisition;
1059 GtkWidget *preview_entry = fontsel->preview_entry;
1060 const gchar *text;
1061
1062 gtk_widget_get_child_requisition(preview_entry, &old_requisition);
1063
1064 #if GTK_MAJOR_VERSION >= 3
1065 gtk_widget_modify_font(preview_entry, gtk_fontsel_hack_get_font_description(fontsel));
1066 #else
1067 rc_style = gtk_rc_style_new();
1068 rc_style->font_desc = gtk_fontsel_hack_get_font_description(fontsel);
1069 gtk_widget_modify_style(preview_entry, rc_style);
1070 g_object_unref(rc_style);
1071 #endif
1072
1073 gtk_widget_size_request(preview_entry, NULL);
1074 gtk_widget_get_requisition(preview_entry, &req);
1075
1076 /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
1077 new_height = CLAMP(req.height,
1078 INITIAL_PREVIEW_HEIGHT,
1079 MAX_PREVIEW_HEIGHT);
1080
1081 if (new_height > old_requisition.height || new_height < old_requisition.height - 30)
1082 gtk_widget_set_size_request(preview_entry, -1, new_height);
1083
1084 /* This sets the preview text, if it hasn't been set already. */
1085 text = gtk_entry_get_text(GTK_ENTRY (preview_entry));
1086 if (*text == '\0') {
1087 gtk_entry_set_text(GTK_ENTRY(preview_entry), _(PREVIEW_TEXT));
1088 }
1089 gtk_editable_set_position(GTK_EDITABLE(preview_entry), 0);
1090 }
1091
1092 /*****************************************************************************
1093 * These functions are the main public interface for getting/setting the font.
1094 *****************************************************************************/
1095
1096 gchar *
gtk_fontsel_hack_get_font_name(GtkFontselHack * fontsel)1097 gtk_fontsel_hack_get_font_name (GtkFontselHack *fontsel)
1098 {
1099 PangoFontDescription *font_desc =
1100 gtk_fontsel_hack_get_font_description(fontsel);
1101 gchar *result;
1102
1103 result = pango_font_description_to_string(font_desc);
1104 pango_font_description_free(font_desc);
1105
1106 return result;
1107 }
1108
1109 /* This sets the current font, selecting the appropriate list rows.
1110 First we check the fontname is valid and try to find the font
1111 family - i.e. the name in the main list. If we can't find that,
1112 then just return. Next we try to set each of the properties
1113 according to the fontname. Finally we select the font family &
1114 style in the lists. */
1115
1116 gboolean
gtk_fontsel_hack_set_font_name(GtkFontselHack * fontsel,const gchar * fontname)1117 gtk_fontsel_hack_set_font_name (GtkFontselHack *fontsel,
1118 const gchar *fontname)
1119 {
1120 PangoFontFamily *new_family = NULL;
1121 PangoFontFace *new_face = NULL;
1122 PangoFontFace *fallback_face = NULL;
1123 PangoFontDescription *new_desc;
1124 GtkTreeModel *model;
1125 GtkTreeIter iter;
1126 GtkTreeIter match_iter;
1127 gboolean valid;
1128
1129 g_return_val_if_fail(GTK_IS_FNTHACK(fontsel), FALSE);
1130
1131 new_desc = pango_font_description_from_string(fontname);
1132
1133 /* Check to make sure that this is in the list of allowed fonts */
1134
1135 model = gtk_tree_view_get_model(GTK_TREE_VIEW(fontsel->family_list));
1136 for (valid = gtk_tree_model_get_iter_first (model, &iter);
1137 valid;
1138 valid = gtk_tree_model_iter_next(model, &iter)) {
1139 PangoFontFamily *family;
1140
1141 gtk_tree_model_get(model, &iter, FAMILY_COLUMN, &family, -1);
1142
1143 if (g_ascii_strcasecmp(pango_font_family_get_name(family),
1144 pango_font_description_get_family(new_desc)) == 0)
1145 new_family = family;
1146
1147 g_object_unref(family);
1148
1149 if (new_family)
1150 break;
1151 }
1152
1153 if (!new_family)
1154 return FALSE;
1155
1156 fontsel->family = new_family;
1157 set_cursor_to_iter(GTK_TREE_VIEW(fontsel->family_list), &iter);
1158 gtk_fontsel_hack_show_available_styles(fontsel);
1159
1160 model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));
1161 for (valid = gtk_tree_model_get_iter_first(model, &iter);
1162 valid;
1163 valid = gtk_tree_model_iter_next(model, &iter)) {
1164 PangoFontFace *face;
1165 PangoFontDescription *tmp_desc;
1166
1167 gtk_tree_model_get(model, &iter, FACE_COLUMN, &face, -1);
1168 tmp_desc = pango_font_face_describe(face);
1169
1170 if (font_description_style_equal(tmp_desc, new_desc))
1171 new_face = face;
1172
1173 if (!fallback_face) {
1174 fallback_face = face;
1175 match_iter = iter;
1176 }
1177
1178 pango_font_description_free(tmp_desc);
1179 g_object_unref(face);
1180
1181 if (new_face) {
1182 match_iter = iter;
1183 break;
1184 }
1185 }
1186
1187 if (!new_face)
1188 new_face = fallback_face;
1189
1190 fontsel->face = new_face;
1191 set_cursor_to_iter(GTK_TREE_VIEW(fontsel->face_list), &match_iter);
1192
1193 gtk_fontsel_hack_set_size(fontsel, pango_font_description_get_size(new_desc));
1194
1195 g_object_freeze_notify(G_OBJECT(fontsel));
1196 g_object_notify(G_OBJECT(fontsel), "font_name");
1197 g_object_thaw_notify(G_OBJECT(fontsel));
1198
1199 pango_font_description_free(new_desc);
1200
1201 return TRUE;
1202 }
1203
1204 gint
gtk_fontsel_hack_get_filter(GtkFontselHack * fontsel)1205 gtk_fontsel_hack_get_filter (GtkFontselHack *fontsel)
1206 {
1207 return fontsel->filter;
1208 }
1209
1210 void
gtk_fontsel_hack_set_filter(GtkFontselHack * fontsel,FontFilterType filter)1211 gtk_fontsel_hack_set_filter (GtkFontselHack *fontsel,
1212 FontFilterType filter)
1213 {
1214 fontsel->filter = filter;
1215 gtk_fontsel_hack_display_fonts(fontsel);
1216 }
1217
1218 /* This returns the text in the preview entry. You should copy the returned
1219 text if you need it. */
1220
1221 G_CONST_RETURN gchar*
gtk_fontsel_hack_get_preview_text(GtkFontselHack * fontsel)1222 gtk_fontsel_hack_get_preview_text (GtkFontselHack *fontsel)
1223 {
1224 return gtk_entry_get_text(GTK_ENTRY(fontsel->preview_entry));
1225 }
1226
1227
1228 /* This sets the text in the preview entry. */
1229
1230 void
gtk_fontsel_hack_set_preview_text(GtkFontselHack * fontsel,const gchar * text)1231 gtk_fontsel_hack_set_preview_text (GtkFontselHack *fontsel,
1232 const gchar *text)
1233 {
1234 gtk_entry_set_text(GTK_ENTRY(fontsel->preview_entry), text);
1235 }
1236
1237 /*****************************************************************************
1238 * GtkFontselHackDialog
1239 *****************************************************************************/
1240
1241 static void gtk_fontsel_hack_dialog_buildable_interface_init (GtkBuildableIface *iface);
1242 static GObject * gtk_fontsel_hack_dialog_buildable_get_internal_child (GtkBuildable *buildable,
1243 GtkBuilder *builder,
1244 const gchar *childname);
1245
1246 G_DEFINE_TYPE_WITH_CODE (GtkFontselHackDialog, gtk_fontsel_hack_dialog,
1247 GTK_TYPE_DIALOG,
1248 G_IMPLEMENT_INTERFACE(GTK_TYPE_BUILDABLE,
1249 gtk_fontsel_hack_dialog_buildable_interface_init))
1250
1251 static GtkBuildableIface *parent_buildable_iface;
1252
1253 static void
gtk_fontsel_hack_dialog_buildable_interface_init(GtkBuildableIface * iface)1254 gtk_fontsel_hack_dialog_buildable_interface_init (GtkBuildableIface *iface)
1255 {
1256 parent_buildable_iface = g_type_interface_peek_parent(iface);
1257 iface->get_internal_child = gtk_fontsel_hack_dialog_buildable_get_internal_child;
1258 }
1259
1260 static GObject *
gtk_fontsel_hack_dialog_buildable_get_internal_child(GtkBuildable * buildable,GtkBuilder * builder,const gchar * childname)1261 gtk_fontsel_hack_dialog_buildable_get_internal_child (GtkBuildable *buildable,
1262 GtkBuilder *builder,
1263 const gchar *childname)
1264 {
1265 if (strcmp(childname, "ok_button") == 0)
1266 return G_OBJECT(GTK_FNTHACK_DIALOG(buildable)->ok_button);
1267 else if (strcmp(childname, "cancel_button") == 0)
1268 return G_OBJECT(GTK_FNTHACK_DIALOG(buildable)->cancel_button);
1269 else if (strcmp(childname, "font_selection") == 0)
1270 return G_OBJECT(GTK_FNTHACK_DIALOG(buildable)->fontsel);
1271
1272 return parent_buildable_iface->get_internal_child(buildable, builder, childname);
1273 }
1274
1275 static void
gtk_fontsel_hack_dialog_class_init(GtkFontselHackDialogClass * klass)1276 gtk_fontsel_hack_dialog_class_init (GtkFontselHackDialogClass *klass)
1277 {
1278 }
1279
1280 static void
gtk_fontsel_hack_dialog_init(GtkFontselHackDialog * fontseldiag)1281 gtk_fontsel_hack_dialog_init (GtkFontselHackDialog *fontseldiag)
1282 {
1283 GtkDialog *dialog;
1284
1285 gtk_widget_push_composite_child();
1286
1287 dialog = GTK_DIALOG(fontseldiag);
1288
1289 fontseldiag->dialog_width = -1;
1290 fontseldiag->auto_resize = TRUE;
1291
1292 gtk_widget_set_events(GTK_WIDGET(fontseldiag), GDK_STRUCTURE_MASK);
1293 g_signal_connect(G_OBJECT(fontseldiag), "configure-event",
1294 (GCallback) gtk_fontsel_hack_dialog_on_configure,
1295 fontseldiag);
1296
1297 gtk_container_set_border_width(GTK_CONTAINER(fontseldiag), 4);
1298 gtk_window_set_resizable(GTK_WINDOW(fontseldiag), FALSE);
1299
1300 fontseldiag->main_vbox = gtk_dialog_get_content_area(dialog);
1301
1302 fontseldiag->fontsel = gtk_fontsel_hack_new();
1303 gtk_container_set_border_width(GTK_CONTAINER(fontseldiag->fontsel), 4);
1304 gtk_widget_show(fontseldiag->fontsel);
1305 gtk_box_pack_start(GTK_BOX(fontseldiag->main_vbox),
1306 fontseldiag->fontsel, TRUE, TRUE, 0);
1307
1308 /* Create the action area */
1309 fontseldiag->action_area = gtk_dialog_get_action_area(dialog);
1310
1311 fontseldiag->cancel_button = gtk_dialog_add_button(dialog,
1312 GTK_STOCK_CANCEL,
1313 GTK_RESPONSE_CANCEL);
1314 fontseldiag->ok_button = gtk_dialog_add_button(dialog,
1315 GTK_STOCK_OK,
1316 GTK_RESPONSE_OK);
1317 gtk_widget_grab_default(fontseldiag->ok_button);
1318
1319 gtk_window_set_title(GTK_WINDOW(fontseldiag), _("Font Selection"));
1320 #if GTK_MAJOR_VERSION < 3
1321 gtk_dialog_set_has_separator(GTK_DIALOG (dialog), FALSE);
1322 #endif
1323 gtk_widget_pop_composite_child();
1324 }
1325
1326 GtkWidget*
gtk_fontsel_hack_dialog_new(const gchar * title)1327 gtk_fontsel_hack_dialog_new (const gchar *title)
1328 {
1329 GtkFontselHackDialog *fontseldiag;
1330
1331 fontseldiag = g_object_new(GTK_TYPE_FNTHACK_DIALOG, NULL);
1332
1333 if (title)
1334 gtk_window_set_title(GTK_WINDOW(fontseldiag), title);
1335
1336 return GTK_WIDGET(fontseldiag);
1337 }
1338
1339 gchar*
gtk_fontsel_hack_dialog_get_font_name(GtkFontselHackDialog * fsd)1340 gtk_fontsel_hack_dialog_get_font_name (GtkFontselHackDialog *fsd)
1341 {
1342 return gtk_fontsel_hack_get_font_name(GTK_FNTHACK(fsd->fontsel));
1343 }
1344
1345 gboolean
gtk_fontsel_hack_dialog_set_font_name(GtkFontselHackDialog * fsd,const gchar * fontname)1346 gtk_fontsel_hack_dialog_set_font_name (GtkFontselHackDialog *fsd,
1347 const gchar *fontname)
1348 {
1349 return gtk_fontsel_hack_set_font_name(GTK_FNTHACK(fsd->fontsel), fontname);
1350 }
1351
1352 gint
gtk_fontsel_hack_dialog_get_filter(GtkFontselHackDialog * fsd)1353 gtk_fontsel_hack_dialog_get_filter (GtkFontselHackDialog *fsd)
1354 {
1355 return gtk_fontsel_hack_get_filter (GTK_FNTHACK (fsd->fontsel));
1356 }
1357
1358 void
gtk_fontsel_hack_dialog_set_filter(GtkFontselHackDialog * fsd,FontFilterType filter)1359 gtk_fontsel_hack_dialog_set_filter (GtkFontselHackDialog *fsd,
1360 FontFilterType filter)
1361 {
1362 gtk_fontsel_hack_set_filter(GTK_FNTHACK(fsd->fontsel), filter);
1363 }
1364
1365 G_CONST_RETURN gchar*
gtk_fontsel_hack_dialog_get_preview_text(GtkFontselHackDialog * fsd)1366 gtk_fontsel_hack_dialog_get_preview_text (GtkFontselHackDialog *fsd)
1367 {
1368 return gtk_fontsel_hack_get_preview_text(GTK_FNTHACK(fsd->fontsel));
1369 }
1370
1371 void
gtk_fontsel_hack_dialog_set_preview_text(GtkFontselHackDialog * fsd,const gchar * text)1372 gtk_fontsel_hack_dialog_set_preview_text (GtkFontselHackDialog *fsd,
1373 const gchar *text)
1374 {
1375 gtk_fontsel_hack_set_preview_text(GTK_FNTHACK(fsd->fontsel), text);
1376 }
1377
gtk_fontsel_hack_dialog_ok_button(GtkWidget * fsd)1378 GtkWidget *gtk_fontsel_hack_dialog_ok_button (GtkWidget *fsd)
1379 {
1380 return GTK_FNTHACK_DIALOG(fsd)->ok_button;
1381 }
1382
gtk_fontsel_hack_dialog_cancel_button(GtkWidget * fsd)1383 GtkWidget *gtk_fontsel_hack_dialog_cancel_button (GtkWidget *fsd)
1384 {
1385 return GTK_FNTHACK_DIALOG(fsd)->cancel_button;
1386 }
1387
1388 /* This turns auto-shrink off if the user resizes the width of the dialog.
1389 It also turns it back on again if the user resizes it back to its normal
1390 width. */
1391
1392 static gint
gtk_fontsel_hack_dialog_on_configure(GtkWidget * widget,GdkEventConfigure * event,GtkFontselHackDialog * fsd)1393 gtk_fontsel_hack_dialog_on_configure (GtkWidget *widget,
1394 GdkEventConfigure *event,
1395 GtkFontselHackDialog *fsd)
1396 {
1397 /* This sets the initial width. */
1398 if (fsd->dialog_width == -1) {
1399 fsd->dialog_width = event->width;
1400 } else if (fsd->auto_resize && fsd->dialog_width != event->width) {
1401 fsd->auto_resize = FALSE;
1402 gtk_window_set_resizable(GTK_WINDOW(fsd), FALSE);
1403 } else if (!fsd->auto_resize && fsd->dialog_width == event->width) {
1404 fsd->auto_resize = TRUE;
1405 gtk_window_set_resizable(GTK_WINDOW(fsd), FALSE);
1406 }
1407
1408 return FALSE;
1409 }
1410