gtkfontsel.c 57.1 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
2 3
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
4
 * Massively updated for Pango by Owen Taylor, May 2000
5 6 7 8 9
 * GtkFontSelection widget for Gtk+, by Damon Chaplin, May 1998.
 * Based on the GnomeFontSelector widget, by Elliot Lee, but major changes.
 * The GnomeFontSelector was derived from app/text_tool.c in the GIMP.
 *
 * This library is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public
11 12 13 14 15 16
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * 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 21 22 23 24
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

25
/*
26
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
27 28 29 30 31
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

32
#include "config.h"
33
#include <stdlib.h>
34
#include <glib/gprintf.h>
35 36
#include <string.h>

37 38
#include <atk/atk.h>

39
#include "gdk/gdk.h"
40 41
#include "gdk/gdkkeysyms.h"

42 43
#include "gtkfontsel.h"

44
#include "gtkbutton.h"
45
#include "gtkcellrenderertext.h"
46 47 48 49 50
#include "gtkentry.h"
#include "gtkframe.h"
#include "gtkhbbox.h"
#include "gtkhbox.h"
#include "gtklabel.h"
51
#include "gtkliststore.h"
52
#include "gtkrc.h"
53
#include "gtkstock.h"
54
#include "gtktable.h"
55 56
#include "gtktreeselection.h"
#include "gtktreeview.h"
57
#include "gtkvbox.h"
58
#include "gtkscrolledwindow.h"
59
#include "gtkintl.h"
60
#include "gtkaccessible.h"
61
#include "gtkprivate.h"
62
#include "gtkbuildable.h"
63
#include "gtkalias.h"
64

65 66 67 68 69 70 71 72
/* We don't enable the font and style entries because they don't add
 * much in terms of visible effect and have a weird effect on keynav.
 * the Windows font selector has entries similarly positioned but they
 * act in conjunction with the associated lists to form a single focus
 * location.
 */
#undef INCLUDE_FONT_ENTRIES

73 74
/* This is the default text shown in the preview entry, though the user
   can set it. Remember that some fonts only have capital letters. */
75
#define PREVIEW_TEXT N_("abcdefghijk ABCDEFGHIJK")
76

Matthias Clasen's avatar
Matthias Clasen committed
77 78
#define DEFAULT_FONT_NAME "Sans 10"

79 80 81 82 83
/* This is the initial and maximum height of the preview entry (it expands
   when large font sizes are selected). Initial height is also the minimum. */
#define INITIAL_PREVIEW_HEIGHT 44
#define MAX_PREVIEW_HEIGHT 300

84
/* These are the sizes of the font, style & size lists. */
85
#define FONT_LIST_HEIGHT	136
Damon Chaplin's avatar
Damon Chaplin committed
86 87
#define FONT_LIST_WIDTH		190
#define FONT_STYLE_LIST_WIDTH	170
88 89
#define FONT_SIZE_LIST_WIDTH	60

90
/* These are what we use as the standard font sizes, for the size list.
91 92
 */
static const guint16 font_sizes[] = {
93
  6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 26, 28,
94
  32, 36, 40, 48, 56, 64, 72
95 96
};

97 98 99 100 101 102 103
enum {
   PROP_0,
   PROP_FONT_NAME,
   PROP_FONT,
   PROP_PREVIEW_TEXT
};

104 105 106 107 108 109 110 111 112 113 114 115 116 117 118

enum {
  FAMILY_COLUMN,
  FAMILY_NAME_COLUMN
};

enum {
  FACE_COLUMN,
  FACE_NAME_COLUMN
};

enum {
  SIZE_COLUMN
};

119 120 121 122 123 124 125 126
static void    gtk_font_selection_set_property       (GObject         *object,
						      guint            prop_id,
						      const GValue    *value,
						      GParamSpec      *pspec);
static void    gtk_font_selection_get_property       (GObject         *object,
						      guint            prop_id,
						      GValue          *value,
						      GParamSpec      *pspec);
127 128 129 130 131
static void    gtk_font_selection_finalize	     (GObject         *object);
static void    gtk_font_selection_screen_changed     (GtkWidget	      *widget,
						      GdkScreen       *previous_screen);
static void    gtk_font_selection_style_set          (GtkWidget      *widget,
						      GtkStyle       *prev_style);
132 133

/* These are the callbacks & related functions. */
134
static void     gtk_font_selection_select_font           (GtkTreeSelection *selection,
135 136 137 138 139 140
							  gpointer          data);
static void     gtk_font_selection_show_available_fonts  (GtkFontSelection *fs);

static void     gtk_font_selection_show_available_styles (GtkFontSelection *fs);
static void     gtk_font_selection_select_best_style     (GtkFontSelection *fs,
							  gboolean          use_first);
141
static void     gtk_font_selection_select_style          (GtkTreeSelection *selection,
142 143 144
							  gpointer          data);

static void     gtk_font_selection_select_best_size      (GtkFontSelection *fs);
145 146
static void     gtk_font_selection_show_available_sizes  (GtkFontSelection *fs,
							  gboolean          first_time);
147
static void     gtk_font_selection_size_activate         (GtkWidget        *w,
148
							  gpointer          data);
149 150 151
static gboolean gtk_font_selection_size_focus_out        (GtkWidget        *w,
							  GdkEventFocus    *event,
							  gpointer          data);
152
static void     gtk_font_selection_select_size           (GtkTreeSelection *selection,
153 154
							  gpointer          data);

155
static void     gtk_font_selection_scroll_on_map         (GtkWidget        *w,
156 157
							  gpointer          data);

158 159
static void     gtk_font_selection_preview_changed       (GtkWidget        *entry,
							  GtkFontSelection *fontsel);
160 161
static void     gtk_font_selection_scroll_to_selection   (GtkFontSelection *fontsel);

162 163

/* Misc. utility functions. */
Manish Singh's avatar
Manish Singh committed
164
static void    gtk_font_selection_load_font          (GtkFontSelection *fs);
165 166
static void    gtk_font_selection_update_preview     (GtkFontSelection *fs);

167
static GdkFont* gtk_font_selection_get_font_internal (GtkFontSelection *fontsel);
168 169 170 171 172 173 174 175 176 177
static PangoFontDescription *gtk_font_selection_get_font_description (GtkFontSelection *fontsel);
static gboolean gtk_font_selection_select_font_desc  (GtkFontSelection      *fontsel,
						      PangoFontDescription  *new_desc,
						      PangoFontFamily      **pfamily,
						      PangoFontFace        **pface);
static void     gtk_font_selection_reload_fonts          (GtkFontSelection *fontsel);
static void     gtk_font_selection_ref_family            (GtkFontSelection *fontsel,
							  PangoFontFamily  *family);
static void     gtk_font_selection_ref_face              (GtkFontSelection *fontsel,
							  PangoFontFace    *face);
178

Matthias Clasen's avatar
Matthias Clasen committed
179
G_DEFINE_TYPE (GtkFontSelection, gtk_font_selection, GTK_TYPE_VBOX)
180 181

static void
182
gtk_font_selection_class_init (GtkFontSelectionClass *klass)
183
{
184
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
185
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
186
  
187 188
  gobject_class->set_property = gtk_font_selection_set_property;
  gobject_class->get_property = gtk_font_selection_get_property;
189

190
  widget_class->screen_changed = gtk_font_selection_screen_changed;
191
  widget_class->style_set = gtk_font_selection_style_set;
192 193 194
   
  g_object_class_install_property (gobject_class,
                                   PROP_FONT_NAME,
195
                                   g_param_spec_string ("font-name",
196
                                                        P_("Font name"),
Matthias Clasen's avatar
Matthias Clasen committed
197 198
                                                        P_("The string that represents this font"),
                                                        DEFAULT_FONT_NAME,
199
                                                        GTK_PARAM_READWRITE));
200 201 202
  g_object_class_install_property (gobject_class,
				   PROP_FONT,
				   g_param_spec_boxed ("font",
203 204
						       P_("Font"),
						       P_("The GdkFont that is currently selected"),
205
						       GDK_TYPE_FONT,
206
						       GTK_PARAM_READABLE));
207 208
  g_object_class_install_property (gobject_class,
                                   PROP_PREVIEW_TEXT,
209
                                   g_param_spec_string ("preview-text",
210 211
                                                        P_("Preview text"),
                                                        P_("The text to display in order to demonstrate the selected font"),
Matthias Clasen's avatar
Matthias Clasen committed
212
                                                        _(PREVIEW_TEXT),
213
                                                        GTK_PARAM_READWRITE));
214
  gobject_class->finalize = gtk_font_selection_finalize;
215 216
}

217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
static void 
gtk_font_selection_set_property (GObject         *object,
				 guint            prop_id,
				 const GValue    *value,
				 GParamSpec      *pspec)
{
  GtkFontSelection *fontsel;

  fontsel = GTK_FONT_SELECTION (object);

  switch (prop_id)
    {
    case PROP_FONT_NAME:
      gtk_font_selection_set_font_name (fontsel, g_value_get_string (value));
      break;
    case PROP_PREVIEW_TEXT:
      gtk_font_selection_set_preview_text (fontsel, g_value_get_string (value));
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void gtk_font_selection_get_property (GObject         *object,
					     guint            prop_id,
					     GValue          *value,
					     GParamSpec      *pspec)
{
  GtkFontSelection *fontsel;

  fontsel = GTK_FONT_SELECTION (object);

  switch (prop_id)
    {
    case PROP_FONT_NAME:
253
      g_value_take_string (value, gtk_font_selection_get_font_name (fontsel));
254 255
      break;
    case PROP_FONT:
Matthias Clasen's avatar
Matthias Clasen committed
256
      g_value_set_boxed (value, gtk_font_selection_get_font_internal (fontsel));
257 258 259 260 261 262 263 264 265 266
      break;
    case PROP_PREVIEW_TEXT:
      g_value_set_string (value, gtk_font_selection_get_preview_text (fontsel));
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

267 268 269 270 271 272 273 274 275
/* Handles key press events on the lists, so that we can trap Enter to
 * activate the default button on our own.
 */
static gboolean
list_row_activated (GtkWidget *widget)
{
  GtkWindow *window;
  
  window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget)));
276
  if (!gtk_widget_is_toplevel (GTK_WIDGET (window)))
277 278 279 280 281
    window = NULL;
  
  if (window
      && widget != window->default_widget
      && !(widget == window->focus_widget &&
282
	   (!window->default_widget || !gtk_widget_get_sensitive (window->default_widget))))
283 284 285 286 287 288
    {
      gtk_window_activate_default (window);
    }
  
  return TRUE;
}
289

290
static void
291
gtk_font_selection_init (GtkFontSelection *fontsel)
292
{
293
  GtkWidget *scrolled_win;
294 295
  GtkWidget *text_box;
  GtkWidget *table, *label;
296
  GtkWidget *font_label, *style_label;
297
  GtkWidget *vbox;
298 299 300
  GtkListStore *model;
  GtkTreeViewColumn *column;
  GList *focus_chain = NULL;
301
  AtkObject *atk_obj;
302

303 304
  gtk_widget_push_composite_child ();

305
  gtk_box_set_spacing (GTK_BOX (fontsel), 12);
306
  fontsel->size = 12 * PANGO_SCALE;
307
  
308 309 310
  /* Create the table of font, style & size. */
  table = gtk_table_new (3, 3, FALSE);
  gtk_widget_show (table);
311 312
  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
  gtk_table_set_col_spacings (GTK_TABLE (table), 12);
313
  gtk_box_pack_start (GTK_BOX (fontsel), table, TRUE, TRUE, 0);
314

Manish Singh's avatar
Manish Singh committed
315
#ifdef INCLUDE_FONT_ENTRIES
316
  fontsel->font_entry = gtk_entry_new ();
Manish Singh's avatar
Manish Singh committed
317 318
  gtk_editable_set_editable (GTK_EDITABLE (fontsel->font_entry), FALSE);
  gtk_widget_set_size_request (fontsel->font_entry, 20, -1);
319
  gtk_widget_show (fontsel->font_entry);
320 321
  gtk_table_attach (GTK_TABLE (table), fontsel->font_entry, 0, 1, 1, 2,
		    GTK_FILL, 0, 0, 0);
322 323
  
  fontsel->font_style_entry = gtk_entry_new ();
Manish Singh's avatar
Manish Singh committed
324 325
  gtk_editable_set_editable (GTK_EDITABLE (fontsel->font_style_entry), FALSE);
  gtk_widget_set_size_request (fontsel->font_style_entry, 20, -1);
326
  gtk_widget_show (fontsel->font_style_entry);
327 328
  gtk_table_attach (GTK_TABLE (table), fontsel->font_style_entry, 1, 2, 1, 2,
		    GTK_FILL, 0, 0, 0);
329
#endif /* INCLUDE_FONT_ENTRIES */
330 331
  
  fontsel->size_entry = gtk_entry_new ();
Manish Singh's avatar
Manish Singh committed
332
  gtk_widget_set_size_request (fontsel->size_entry, 20, -1);
333 334 335
  gtk_widget_show (fontsel->size_entry);
  gtk_table_attach (GTK_TABLE (table), fontsel->size_entry, 2, 3, 1, 2,
		    GTK_FILL, 0, 0, 0);
Manish Singh's avatar
Manish Singh committed
336 337 338
  g_signal_connect (fontsel->size_entry, "activate",
		    G_CALLBACK (gtk_font_selection_size_activate),
		    fontsel);
339
  g_signal_connect_after (fontsel->size_entry, "focus-out-event",
Manish Singh's avatar
Manish Singh committed
340 341
			  G_CALLBACK (gtk_font_selection_size_focus_out),
			  fontsel);
342
  
343 344 345 346
  font_label = gtk_label_new_with_mnemonic (_("_Family:"));
  gtk_misc_set_alignment (GTK_MISC (font_label), 0.0, 0.5);
  gtk_widget_show (font_label);
  gtk_table_attach (GTK_TABLE (table), font_label, 0, 1, 0, 1,
347
		    GTK_FILL, 0, 0, 0);  
348 349 350 351 352

  style_label = gtk_label_new_with_mnemonic (_("_Style:"));
  gtk_misc_set_alignment (GTK_MISC (style_label), 0.0, 0.5);
  gtk_widget_show (style_label);
  gtk_table_attach (GTK_TABLE (table), style_label, 1, 2, 0, 1,
353
		    GTK_FILL, 0, 0, 0);
354
  
355 356 357 358 359 360 361 362 363
  label = gtk_label_new_with_mnemonic (_("Si_ze:"));
  gtk_label_set_mnemonic_widget (GTK_LABEL (label),
                                 fontsel->size_entry);
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  gtk_widget_show (label);
  gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1,
		    GTK_FILL, 0, 0, 0);
  
  
364 365 366 367 368 369 370 371
  /* Create the lists  */

  model = gtk_list_store_new (2,
			      G_TYPE_OBJECT,  /* FAMILY_COLUMN */
			      G_TYPE_STRING); /* FAMILY_NAME_COLUMN */
  fontsel->family_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
  g_object_unref (model);

372
  g_signal_connect (fontsel->family_list, "row-activated",
373 374
		    G_CALLBACK (list_row_activated), fontsel);

375 376 377 378 379 380 381 382 383 384 385 386 387
  column = gtk_tree_view_column_new_with_attributes ("Family",
						     gtk_cell_renderer_text_new (),
						     "text", FAMILY_NAME_COLUMN,
						     NULL);
  gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
  gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->family_list), column);

  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->family_list), FALSE);
  gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)),
			       GTK_SELECTION_BROWSE);
  
  gtk_label_set_mnemonic_widget (GTK_LABEL (font_label), fontsel->family_list);

388
  scrolled_win = gtk_scrolled_window_new (NULL, NULL);
389
  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
Manish Singh's avatar
Manish Singh committed
390 391
  gtk_widget_set_size_request (scrolled_win,
			       FONT_LIST_WIDTH, FONT_LIST_HEIGHT);
392
  gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->family_list);
393 394
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
				  GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
395
  gtk_widget_show (fontsel->family_list);
396
  gtk_widget_show (scrolled_win);
397

398
  gtk_table_attach (GTK_TABLE (table), scrolled_win, 0, 1, 1, 3,
399 400
		    GTK_EXPAND | GTK_FILL,
		    GTK_EXPAND | GTK_FILL, 0, 0);
401 402 403 404 405 406 407
  focus_chain = g_list_append (focus_chain, scrolled_win);
  
  model = gtk_list_store_new (2,
			      G_TYPE_OBJECT,  /* FACE_COLUMN */
			      G_TYPE_STRING); /* FACE_NAME_COLUMN */
  fontsel->face_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
  g_object_unref (model);
408 409
  g_signal_connect (fontsel->face_list, "row-activated",
		    G_CALLBACK (list_row_activated), fontsel);
410 411 412 413 414 415 416 417 418 419 420 421 422

  gtk_label_set_mnemonic_widget (GTK_LABEL (style_label), fontsel->face_list);

  column = gtk_tree_view_column_new_with_attributes ("Face",
						     gtk_cell_renderer_text_new (),
						     "text", FACE_NAME_COLUMN,
						     NULL);
  gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
  gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->face_list), column);

  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->face_list), FALSE);
  gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)),
			       GTK_SELECTION_BROWSE);
423
  
424
  scrolled_win = gtk_scrolled_window_new (NULL, NULL);
425
  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
Manish Singh's avatar
Manish Singh committed
426 427
  gtk_widget_set_size_request (scrolled_win,
			       FONT_STYLE_LIST_WIDTH, FONT_LIST_HEIGHT);
428
  gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->face_list);
429 430
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
				  GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
431
  gtk_widget_show (fontsel->face_list);
432
  gtk_widget_show (scrolled_win);
433
  gtk_table_attach (GTK_TABLE (table), scrolled_win, 1, 2, 1, 3,
434 435
		    GTK_EXPAND | GTK_FILL,
		    GTK_EXPAND | GTK_FILL, 0, 0);
436 437 438 439 440 441 442
  focus_chain = g_list_append (focus_chain, scrolled_win);
  
  focus_chain = g_list_append (focus_chain, fontsel->size_entry);

  model = gtk_list_store_new (1, G_TYPE_INT);
  fontsel->size_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (model));
  g_object_unref (model);
443 444
  g_signal_connect (fontsel->size_list, "row-activated",
		    G_CALLBACK (list_row_activated), fontsel);
445 446 447 448 449 450 451 452 453 454 455

  column = gtk_tree_view_column_new_with_attributes ("Size",
						     gtk_cell_renderer_text_new (),
						     "text", SIZE_COLUMN,
						     NULL);
  gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
  gtk_tree_view_append_column (GTK_TREE_VIEW (fontsel->size_list), column);

  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (fontsel->size_list), FALSE);
  gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)),
			       GTK_SELECTION_BROWSE);
456
  
457
  scrolled_win = gtk_scrolled_window_new (NULL, NULL);
458 459
  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), GTK_SHADOW_IN);
  gtk_container_add (GTK_CONTAINER (scrolled_win), fontsel->size_list);
Manish Singh's avatar
Manish Singh committed
460
  gtk_widget_set_size_request (scrolled_win, -1, FONT_LIST_HEIGHT);
461
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
462 463
				  GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
  gtk_widget_show (fontsel->size_list);
464
  gtk_widget_show (scrolled_win);
465
  gtk_table_attach (GTK_TABLE (table), scrolled_win, 2, 3, 2, 3,
466 467 468 469 470
		    GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  focus_chain = g_list_append (focus_chain, scrolled_win);

  gtk_container_set_focus_chain (GTK_CONTAINER (table), focus_chain);
  g_list_free (focus_chain);
471
  
472 473 474
  /* Insert the fonts. */
  g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->family_list)), "changed",
		    G_CALLBACK (gtk_font_selection_select_font), fontsel);
475

Manish Singh's avatar
Manish Singh committed
476 477 478
  g_signal_connect_after (fontsel->family_list, "map",
			  G_CALLBACK (gtk_font_selection_scroll_on_map),
			  fontsel);
479
  
480 481
  g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->face_list)), "changed",
		    G_CALLBACK (gtk_font_selection_select_style), fontsel);
482

483 484
  g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list)), "changed",
		    G_CALLBACK (gtk_font_selection_select_size), fontsel);
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
  atk_obj = gtk_widget_get_accessible (fontsel->size_list);
  if (GTK_IS_ACCESSIBLE (atk_obj))
    {
      /* Accessibility support is enabled.
       * Make the label ATK_RELATON_LABEL_FOR for the size list as well.
       */
      AtkObject *atk_label;
      AtkRelationSet *relation_set;
      AtkRelation *relation;
      AtkObject *obj_array[1];

      atk_label = gtk_widget_get_accessible (label);
      relation_set = atk_object_ref_relation_set (atk_obj);
      relation = atk_relation_set_get_relation_by_type (relation_set, ATK_RELATION_LABELLED_BY);
      if (relation)
        {
501
          atk_relation_add_target (relation, atk_label);
502 503 504 505 506 507 508 509 510 511 512 513 514
        }
      else 
        {
          obj_array[0] = atk_label;
          relation = atk_relation_new (obj_array, 1, ATK_RELATION_LABELLED_BY);
          atk_relation_set_add (relation_set, relation);
        }
      g_object_unref (relation_set);

      relation_set = atk_object_ref_relation_set (atk_label);
      relation = atk_relation_set_get_relation_by_type (relation_set, ATK_RELATION_LABEL_FOR);
      if (relation)
        {
515
          atk_relation_add_target (relation, atk_obj);
516 517 518 519 520 521 522 523 524 525
        }
      else 
        {
          obj_array[0] = atk_obj;
          relation = atk_relation_new (obj_array, 1, ATK_RELATION_LABEL_FOR);
          atk_relation_set_add (relation_set, relation);
        }
      g_object_unref (relation_set);
    }    
      
526

527 528 529 530
  vbox = gtk_vbox_new (FALSE, 6);
  gtk_widget_show (vbox);
  gtk_box_pack_start (GTK_BOX (fontsel), vbox, FALSE, TRUE, 0);
  
531
  /* create the text entry widget */
532
  label = gtk_label_new_with_mnemonic (_("_Preview:"));
533
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
534
  gtk_widget_show (label);
535
  gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0);
536
  
537 538
  text_box = gtk_hbox_new (FALSE, 0);
  gtk_widget_show (text_box);
539
  gtk_box_pack_start (GTK_BOX (vbox), text_box, FALSE, TRUE, 0);
540
  
541
  fontsel->preview_entry = gtk_entry_new ();
542
  gtk_label_set_mnemonic_widget (GTK_LABEL (label), fontsel->preview_entry);
Matthias Clasen's avatar
Matthias Clasen committed
543
  gtk_entry_set_text (GTK_ENTRY (fontsel->preview_entry), _(PREVIEW_TEXT));
544
  
545
  gtk_widget_show (fontsel->preview_entry);
Manish Singh's avatar
Manish Singh committed
546 547 548 549
  g_signal_connect (fontsel->preview_entry, "changed",
		    G_CALLBACK (gtk_font_selection_preview_changed), fontsel);
  gtk_widget_set_size_request (fontsel->preview_entry,
			       -1, INITIAL_PREVIEW_HEIGHT);
550 551
  gtk_box_pack_start (GTK_BOX (text_box), fontsel->preview_entry,
		      TRUE, TRUE, 0);
552
  gtk_widget_pop_composite_child();
553 554
}

Matthias Clasen's avatar
Matthias Clasen committed
555 556 557 558 559 560 561
/**
 * gtk_font_selection_new:
 *
 * Creates a new #GtkFontSelection.
 *
 * Return value: a n ew #GtkFontSelection
 */
562
GtkWidget *
563
gtk_font_selection_new (void)
564 565
{
  GtkFontSelection *fontsel;
566
  
Manish Singh's avatar
Manish Singh committed
567
  fontsel = g_object_new (GTK_TYPE_FONT_SELECTION, NULL);
568
  
569 570 571 572
  return GTK_WIDGET (fontsel);
}

static void
573
gtk_font_selection_finalize (GObject *object)
574 575
{
  GtkFontSelection *fontsel;
576
  
577
  g_return_if_fail (GTK_IS_FONT_SELECTION (object));
578
  
579
  fontsel = GTK_FONT_SELECTION (object);
580

581 582
  if (fontsel->font)
    gdk_font_unref (fontsel->font);
583

584 585 586
  gtk_font_selection_ref_family (fontsel, NULL);
  gtk_font_selection_ref_face (fontsel, NULL);

587
  G_OBJECT_CLASS (gtk_font_selection_parent_class)->finalize (object);
588 589
}

590
static void
591 592
gtk_font_selection_ref_family (GtkFontSelection *fontsel,
			       PangoFontFamily  *family)
593
{
594 595 596 597 598 599
  if (family)
    family = g_object_ref (family);
  if (fontsel->family)
    g_object_unref (fontsel->family);
  fontsel->family = family;
}
600

601 602 603 604 605 606 607 608 609 610 611 612 613
static void gtk_font_selection_ref_face (GtkFontSelection *fontsel,
					 PangoFontFace    *face)
{
  if (face)
    face = g_object_ref (face);
  if (fontsel->face)
    g_object_unref (fontsel->face);
  fontsel->face = face;
}

static void
gtk_font_selection_reload_fonts (GtkFontSelection *fontsel)
{
614 615
  if (gtk_widget_has_screen (GTK_WIDGET (fontsel)))
    {
616 617 618
      PangoFontDescription *desc;
      desc = gtk_font_selection_get_font_description (fontsel);

619 620 621
      gtk_font_selection_show_available_fonts (fontsel);
      gtk_font_selection_show_available_sizes (fontsel, TRUE);
      gtk_font_selection_show_available_styles (fontsel);
622 623 624 625 626

      gtk_font_selection_select_font_desc (fontsel, desc, NULL, NULL);
      gtk_font_selection_scroll_to_selection (fontsel);

      pango_font_description_free (desc);
627 628 629
    }
}

630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
static void
gtk_font_selection_screen_changed (GtkWidget *widget,
				   GdkScreen *previous_screen)
{
  gtk_font_selection_reload_fonts (GTK_FONT_SELECTION (widget));
}

static void
gtk_font_selection_style_set (GtkWidget *widget,
			      GtkStyle  *prev_style)
{
  /* Maybe fonts where installed or removed... */
  gtk_font_selection_reload_fonts (GTK_FONT_SELECTION (widget));
}

645 646 647 648
static void
gtk_font_selection_preview_changed (GtkWidget        *entry,
				    GtkFontSelection *fontsel)
{
649
  g_object_notify (G_OBJECT (fontsel), "preview-text");
650
}
651

652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
static void
scroll_to_selection (GtkTreeView *tree_view)
{
  GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
  GtkTreeModel *model;
  GtkTreeIter iter;

  if (gtk_tree_selection_get_selected (selection, &model, &iter))
    {
      GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
      gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.5);
      gtk_tree_path_free (path);
    }
}

667 668 669 670 671 672 673
static void
set_cursor_to_iter (GtkTreeView *view,
		    GtkTreeIter *iter)
{
  GtkTreeModel *model = gtk_tree_view_get_model (view);
  GtkTreePath *path = gtk_tree_model_get_path (model, iter);
  
674
  gtk_tree_view_set_cursor (view, path, NULL, FALSE);
675 676 677 678

  gtk_tree_path_free (path);
}

679
static void
680
gtk_font_selection_scroll_to_selection (GtkFontSelection *fontsel)
681
{
682 683
  /* Try to scroll the font family list to the selected item */
  scroll_to_selection (GTK_TREE_VIEW (fontsel->family_list));
684
      
685 686
  /* Try to scroll the font family list to the selected item */
  scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
687
      
688 689
  /* Try to scroll the font family list to the selected item */
  scroll_to_selection (GTK_TREE_VIEW (fontsel->size_list));
690 691 692 693 694 695 696 697 698
/* This is called when the list is mapped. Here we scroll to the current
   font if necessary. */
}

static void
gtk_font_selection_scroll_on_map (GtkWidget		*widget,
                                  gpointer		 data)
{
  gtk_font_selection_scroll_to_selection (GTK_FONT_SELECTION (data));
699 700
}

701
/* This is called when a family is selected in the list. */
Damon Chaplin's avatar
Damon Chaplin committed
702
static void
703 704
gtk_font_selection_select_font (GtkTreeSelection *selection,
				gpointer          data)
Damon Chaplin's avatar
Damon Chaplin committed
705 706
{
  GtkFontSelection *fontsel;
707 708
  GtkTreeModel *model;
  GtkTreeIter iter;
709
#ifdef INCLUDE_FONT_ENTRIES
710
  const gchar *family_name;
711 712
#endif

Damon Chaplin's avatar
Damon Chaplin committed
713 714
  fontsel = GTK_FONT_SELECTION (data);

715
  if (gtk_tree_selection_get_selected (selection, &model, &iter))
Damon Chaplin's avatar
Damon Chaplin committed
716
    {
717 718 719 720
      PangoFontFamily *family;
      
      gtk_tree_model_get (model, &iter, FAMILY_COLUMN, &family, -1);
      if (fontsel->family != family)
Damon Chaplin's avatar
Damon Chaplin committed
721
	{
722
	  gtk_font_selection_ref_family (fontsel, family);
723
	  
724
#ifdef INCLUDE_FONT_ENTRIES
725
	  family_name = pango_font_family_get_name (fontsel->family);
Havoc Pennington's avatar
Havoc Pennington committed
726
	  gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), family_name);
727
#endif
728 729 730
	  
	  gtk_font_selection_show_available_styles (fontsel);
	  gtk_font_selection_select_best_style (fontsel, TRUE);
Damon Chaplin's avatar
Damon Chaplin committed
731
	}
732 733

      g_object_unref (family);
Damon Chaplin's avatar
Damon Chaplin committed
734 735 736
    }
}

737
static int
738
cmp_families (const void *a, const void *b)
739
{
740 741 742
  const char *a_name = pango_font_family_get_name (*(PangoFontFamily **)a);
  const char *b_name = pango_font_family_get_name (*(PangoFontFamily **)b);
  
743
  return g_utf8_collate (a_name, b_name);
744
}
Damon Chaplin's avatar
Damon Chaplin committed
745

746
static void
747
gtk_font_selection_show_available_fonts (GtkFontSelection *fontsel)
748
{
749 750 751
  GtkListStore *model;
  PangoFontFamily **families;
  PangoFontFamily *match_family = NULL;
752
  gint n_families, i;
753 754 755 756
  GtkTreeIter match_row;
  
  model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->family_list)));
  
757
  pango_context_list_families (gtk_widget_get_pango_context (GTK_WIDGET (fontsel)),
758 759
			       &families, &n_families);
  qsort (families, n_families, sizeof (PangoFontFamily *), cmp_families);
760

761
  gtk_list_store_clear (model);
762 763 764

  for (i=0; i<n_families; i++)
    {
765 766 767 768 769 770 771 772
      const gchar *name = pango_font_family_get_name (families[i]);
      GtkTreeIter iter;

      gtk_list_store_append (model, &iter);
      gtk_list_store_set (model, &iter,
			  FAMILY_COLUMN, families[i],
			  FAMILY_NAME_COLUMN, name,
			  -1);
773
      
774
      if (i == 0 || !g_ascii_strcasecmp (name, "sans"))
775 776 777 778
	{
	  match_family = families[i];
	  match_row = iter;
	}
779
    }
780

781
  gtk_font_selection_ref_family (fontsel, match_family);
782 783
  if (match_family)
    {
784
      set_cursor_to_iter (GTK_TREE_VIEW (fontsel->family_list), &match_row);
Manish Singh's avatar
Manish Singh committed
785
#ifdef INCLUDE_FONT_ENTRIES
786 787
      gtk_entry_set_text (GTK_ENTRY (fontsel->font_entry), 
			  pango_font_family_get_name (match_family));
788
#endif /* INCLUDE_FONT_ENTRIES */
789
    }
790

791
  g_free (families);
792
}
793

794 795 796
static int
compare_font_descriptions (const PangoFontDescription *a, const PangoFontDescription *b)
{
797
  int val = strcmp (pango_font_description_get_family (a), pango_font_description_get_family (b));
798 799 800
  if (val != 0)
    return val;

801 802
  if (pango_font_description_get_weight (a) != pango_font_description_get_weight (b))
    return pango_font_description_get_weight (a) - pango_font_description_get_weight (b);
803

804 805
  if (pango_font_description_get_style (a) != pango_font_description_get_style (b))
    return pango_font_description_get_style (a) - pango_font_description_get_style (b);
806
  
807 808
  if (pango_font_description_get_stretch (a) != pango_font_description_get_stretch (b))
    return pango_font_description_get_stretch (a) - pango_font_description_get_stretch (b);
809

810 811
  if (pango_font_description_get_variant (a) != pango_font_description_get_variant (b))
    return pango_font_description_get_variant (a) - pango_font_description_get_variant (b);
812 813 814 815 816

  return 0;
}

static int
817
faces_sort_func (const void *a, const void *b)
818
{
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
  PangoFontDescription *desc_a = pango_font_face_describe (*(PangoFontFace **)a);
  PangoFontDescription *desc_b = pango_font_face_describe (*(PangoFontFace **)b);
  
  int ord = compare_font_descriptions (desc_a, desc_b);

  pango_font_description_free (desc_a);
  pango_font_description_free (desc_b);

  return ord;
}

static gboolean
font_description_style_equal (const PangoFontDescription *a,
			      const PangoFontDescription *b)
{
  return (pango_font_description_get_weight (a) == pango_font_description_get_weight (b) &&
	  pango_font_description_get_style (a) == pango_font_description_get_style (b) &&
	  pango_font_description_get_stretch (a) == pango_font_description_get_stretch (b) &&
	  pango_font_description_get_variant (a) == pango_font_description_get_variant (b));
838
}
839

840
/* This fills the font style list with all the possible style combinations
841 842 843 844
   for the current font family. */
static void
gtk_font_selection_show_available_styles (GtkFontSelection *fontsel)
{
845
  gint n_faces, i;
846
  PangoFontFace **faces;
847
  PangoFontDescription *old_desc;
848 849 850 851 852 853
  GtkListStore *model;
  GtkTreeIter match_row;
  PangoFontFace *match_face = NULL;
  
  model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list)));
  
854 855 856 857 858
  if (fontsel->face)
    old_desc = pango_font_face_describe (fontsel->face);
  else
    old_desc= NULL;

859 860
  pango_font_family_list_faces (fontsel->family, &faces, &n_faces);
  qsort (faces, n_faces, sizeof (PangoFontFace *), faces_sort_func);
861

862
  gtk_list_store_clear (model);
863

864
  for (i=0; i < n_faces; i++)
865
    {
866 867
      GtkTreeIter iter;
      const gchar *str = pango_font_face_get_face_name (faces[i]);
868

869 870 871 872 873 874 875
      gtk_list_store_append (model, &iter);
      gtk_list_store_set (model, &iter,
			  FACE_COLUMN, faces[i],
			  FACE_NAME_COLUMN, str,
			  -1);

      if (i == 0)
876
	{
877 878 879 880 881 882
	  match_row = iter;
	  match_face = faces[i];
	}
      else if (old_desc)
	{
	  PangoFontDescription *tmp_desc = pango_font_face_describe (faces[i]);
883 884
	  
	  if (font_description_style_equal (tmp_desc, old_desc))
885 886 887 888
	    {
	      match_row = iter;
	      match_face = faces[i];
	    }
889
      
890 891
	  pango_font_description_free (tmp_desc);
	}
892
    }
893

894 895 896
  if (old_desc)
    pango_font_description_free (old_desc);

897
  gtk_font_selection_ref_face (fontsel, match_face);
898
  if (match_face)
899
    {
Manish Singh's avatar
Manish Singh committed
900
#ifdef INCLUDE_FONT_ENTRIES
901 902
      const gchar *str = pango_font_face_get_face_name (fontsel->face);

903
      gtk_entry_set_text (GTK_ENTRY (fontsel->font_style_entry), str);
904
#endif      
905
      set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &match_row);
906
    }
907 908

  g_free (faces);
909 910 911 912 913 914 915 916
}

/* This selects a style when the user selects a font. It just uses the first
   available style at present. I was thinking of trying to maintain the
   selected style, e.g. bold italic, when the user selects different fonts.
   However, the interface is so easy to use now I'm not sure it's worth it.
   Note: This will load a font. */
static void
917 918
gtk_font_selection_select_best_style (GtkFontSelection *fontsel,
				      gboolean	        use_first)
919
{
920 921 922 923 924
  GtkTreeIter iter;
  GtkTreeModel *model;

  model = gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->face_list));

925
  if (gtk_tree_model_get_iter_first (model, &iter))
926
    {
927
      set_cursor_to_iter (GTK_TREE_VIEW (fontsel->face_list), &iter);
928 929 930 931
      scroll_to_selection (GTK_TREE_VIEW (fontsel->face_list));
    }

  gtk_font_selection_show_available_sizes (fontsel, FALSE);
932 933 934 935 936 937
  gtk_font_selection_select_best_size (fontsel);
}


/* This is called when a style is selected in the list. */
static void
938 939
gtk_font_selection_select_style (GtkTreeSelection *selection,
				 gpointer          data)
940
{
941
  GtkFontSelection *fontsel = GTK_FONT_SELECTION (data);
942 943
  GtkTreeModel *model;
  GtkTreeIter iter;
944
  
945
  if (gtk_tree_selection_get_selected (selection, &model, &iter))
946
    {
947 948 949
      PangoFontFace *face;
      
      gtk_tree_model_get (model, &iter, FACE_COLUMN, &face, -1);
950
      gtk_font_selection_ref_face (fontsel, face);
951
      g_object_unref (face);
952 953
    }

954
  gtk_font_selection_show_available_sizes (fontsel, FALSE);
955
  gtk_font_selection_select_best_size (fontsel);
956 957
}

958
static void
959 960
gtk_font_selection_show_available_sizes (GtkFontSelection *fontsel,
					 gboolean          first_time)
961
{
962
  gint i;
963
  GtkListStore *model;
964
  gchar buffer[128];
965 966
  gchar *p;
      
967
  model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (fontsel->size_list)));
968

969
  /* Insert the standard font sizes */
970 971 972
  if (first_time)
    {
      gtk_list_store_clear (model);
973

974 975 976 977 978 979 980 981
      for (i = 0; i < G_N_ELEMENTS (font_sizes); i++)
	{
	  GtkTreeIter iter;
	  
	  gtk_list_store_append (model, &iter);
	  gtk_list_store_set (model, &iter, SIZE_COLUMN, font_sizes[i], -1);
	  
	  if (font_sizes[i] * PANGO_SCALE == fontsel->size)
982
	    set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
983 984 985
	}
    }
  else
986
    {
987
      GtkTreeIter iter;
988
      gboolean found = FALSE;
989
      
990
      gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
991
      for (i = 0; i < G_N_ELEMENTS (font_sizes) && !found; i++)
992 993
	{
	  if (font_sizes[i] * PANGO_SCALE == fontsel->size)
994 995 996 997
	    {
	      set_cursor_to_iter (GTK_TREE_VIEW (fontsel->size_list), &iter);
	      found = TRUE;
	    }
998 999 1000

	  gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter);
	}
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011

      if (!found)
	{
	  GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (fontsel->size_list));
	  gtk_tree_selection_unselect_all (selection);
	}
    }

  /* Set the entry to the new size, rounding to 1 digit,
   * trimming of trailing 0's and a trailing period
   */
1012
  g_snprintf (buffer, sizeof (buffer), "%.1f", fontsel->size / (1.0 * PANGO_SCALE));
1013 1014 1015 1016 1017 1018 1019 1020
  if (strchr (buffer, '.'))
    {
      p = buffer + strlen (buffer) - 1;
      while (*p == '0')
	p--;
      if (*p == '.')
	p--;
      p[1] = '\0';
1021 1022
    }

1023 1024 1025
  /* Compare, to avoid moving the cursor unecessarily */
  if (strcmp (gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry)), buffer) != 0)
    gtk_entry_set_text (GTK_ENTRY (fontsel->size_entry), buffer);
1026 1027
}

1028
static void
1029
gtk_font_selection_select_best_size (GtkFontSelection *fontsel)
1030
{
1031 1032
  gtk_font_selection_load_font (fontsel);  
}
1033

1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
static void
gtk_font_selection_set_size (GtkFontSelection *fontsel,
			     gint              new_size)
{
  if (fontsel->size != new_size)
    {
      fontsel->size = new_size;

      gtk_font_selection_show_available_sizes (fontsel, FALSE);      
      gtk_font_selection_load_font (fontsel);
    }
}

1047 1048
/* If the user hits return in the font size entry, we change to the new font
   size. */
1049 1050 1051
static void
gtk_font_selection_size_activate (GtkWidget   *w,
                                  gpointer     data)
1052 1053 1054
{
  GtkFontSelection *fontsel;
  gint new_size;
1055
  const gchar *text;
1056
  
1057
  fontsel = GTK_FONT_SELECTION (data);
1058 1059

  text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
1060 1061
  new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);

1062 1063 1064 1065
  if (fontsel->size != new_size)
    gtk_font_selection_set_size (fontsel, new_size);
  else 
    list_row_activated (w);
1066 1067
}

1068 1069 1070 1071 1072
static gboolean
gtk_font_selection_size_focus_out (GtkWidget     *w,
				   GdkEventFocus *event,
				   gpointer       data)
{
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082
  GtkFontSelection *fontsel;
  gint new_size;
  const gchar *text;
  
  fontsel = GTK_FONT_SELECTION (data);

  text = gtk_entry_get_text (GTK_ENTRY (fontsel->size_entry));
  new_size = MAX (0.1, atof (text) * PANGO_SCALE + 0.5);

  gtk_font_selection_set_size (fontsel, new_size);
1083 1084 1085 1086
  
  return TRUE;
}

1087
/* This is called when a size is selected in the list. */
1088
static void
1089 1090
gtk_font_selection_select_size (GtkTreeSelection *selection,
				gpointer          data)
1091
{
1092
  GtkFontSelection *fontsel;
1093 1094
  GtkTreeModel *model;
  GtkTreeIter iter;
1095 1096 1097
  gint new_size;
  
  fontsel = GTK_FONT_SELECTION (data);
1098
  
1099
  if (gtk_tree_selection_get_selected (selection, &model, &iter))
1100
    {
1101
      gtk_tree_model_get (model, &iter, SIZE_COLUMN, &new_size, -1);
1102
      gtk_font_selection_set_size (fontsel, new_size * PANGO_SCALE);
1103 1104 1105
    }
}

1106 1107 1108 1109 1110 1111 1112 1113 1114
static void
gtk_font_selection_load_font (GtkFontSelection *fontsel)
{
  if (fontsel->font)
    gdk_font_unref (fontsel->font);
  fontsel->font = NULL;

  gtk_font_selection_update_preview (fontsel);
}
1115

1116 1117 1118
static PangoFontDescription *
gtk_font_selection_get_font_description (GtkFontSelection *fontsel)
{
1119 1120 1121 1122 1123 1124 1125 1126
  PangoFontDescription *font_desc;

  if (fontsel->face)
    {
      font_desc = pango_font_face_describe (fontsel->face);
      pango_font_description_set_size (font_desc, fontsel->size);
    }
  else
Matthias Clasen's avatar
Matthias Clasen committed
1127
    font_desc = pango_font_description_from_string (DEFAULT_FONT_NAME);
1128 1129 1130 1131

  return font_desc;
}

1132 1133 1134 1135 1136 1137 1138 1139
/* This sets the font in the preview entry to the selected font, and tries to
   make sure that the preview entry is a reasonable size, i.e. so that the
   text can be seen with a bit of space to spare. But it tries to avoid
   resizing the entry every time the font changes.
   This also used to shrink the preview if the font size was decreased, but
   that made it awkward if the user wanted to resize the window themself. */
static void
gtk_font_selection_update_preview (GtkFontSelection *fontsel)
1140
{
1141 1142 1143 1144
  GtkRcStyle *rc_style;
  gint new_height;
  GtkRequisition old_requisition;
  GtkWidget *preview_entry = fontsel->preview_entry;
1145
  const gchar *text;
1146 1147

  gtk_widget_get_child_requisition (preview_entry, &old_requisition);
1148
  
1149
  rc_style = gtk_rc_style_new ();
1150 1151
  rc_style->font_desc = gtk_font_selection_get_font_description (fontsel);
  
1152
  gtk_widget_modify_style (preview_entry, rc_style);
1153
  g_object_unref (rc_style);
1154 1155 1156 1157 1158

  gtk_widget_size_request (preview_entry, NULL);
  
  /* We don't ever want to be over MAX_PREVIEW_HEIGHT pixels high. */
  new_height = CLAMP (preview_entry->requisition.height, INITIAL_PREVIEW_HEIGHT, MAX_PREVIEW_HEIGHT);
1159

1160
  if (new_height > old_requisition.height || new_height < old_requisition.height - 30)
Manish Singh's avatar
Manish Singh committed
1161
    gtk_widget_set_size_request (preview_entry, -1, new_height);
1162 1163
  
  /* This sets the preview text, if it hasn't been set already. */
1164 1165
  text = gtk_entry_get_text (GTK_ENTRY (preview_entry));
  if (strlen (text) == 0)
1166
    gtk_entry_set_text (GTK_ENTRY (preview_entry), _(PREVIEW_TEXT));
Manish Singh's avatar
Manish Singh committed
1167
  gtk_editable_set_position (GTK_EDITABLE (preview_entry), 0);
1168
}
1169

1170
static GdkFont*
1171
gtk_font_selection_get_font_internal (GtkFontSelection *fontsel)
1172
{
1173
  if (!fontsel->font)
1174 1175
    {
      PangoFontDescription *font_desc = gtk_font_selection_get_font_description (fontsel);
1176
      fontsel->font = gdk_font_from_description_for_display (gtk_widget_get_display (GTK_WIDGET (fontsel)), font_desc);
1177 1178
      pango_font_description_free (font_desc);
    }
1179
  
1180 1181 1182 1183
  return fontsel->font;
}


1184 1185 1186 1187
/*****************************************************************************
 * These functions are the main public interface for getting/setting the font.
 *****************************************************************************/

1188 1189 1190 1191 1192 1193 1194
/**
 * gtk_font_selection_get_family_list:
 * @fontsel: a #GtkFontSelection
 *
 * This returns the #GtkTreeView that lists font families, for
 * example, 'Sans', 'Serif', etc.
 * 
Matthias Clasen's avatar
Matthias Clasen committed
1195
 * Return value: A #GtkWidget that is part of @fontsel
1196 1197
 *
 * Since: 2.14
Matthias Clasen's avatar
Matthias Clasen committed
1198
 */
1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213
GtkWidget *
gtk_font_selection_get_family_list (GtkFontSelection *fontsel)
{
  g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
  
  return fontsel->family_list;
}

/**
 * gtk_font_selection_get_face_list:
 * @fontsel: a #GtkFontSelection
 *
 * This returns the #GtkTreeView which lists all styles available for
 * the selected font. For example, 'Regular', 'Bold', etc.
 * 
Matthias Clasen's avatar
Matthias Clasen committed
1214
 * Return value: A #GtkWidget that is part of @fontsel
1215 1216
 *
 * Since: 2.14
Matthias Clasen's avatar
Matthias Clasen committed
1217
 */
1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232
GtkWidget *
gtk_font_selection_get_face_list (GtkFontSelection *fontsel)
{
  g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
  
  return fontsel->face_list;
}

/**
 * gtk_font_selection_get_size_entry:
 * @fontsel: a #GtkFontSelection
 *
 * This returns the #GtkEntry used to allow the user to edit the font
 * number manually instead of selecting it from the list of font sizes. 
 * 
Matthias Clasen's avatar
Matthias Clasen committed
1233
 * Return value: A #GtkWidget that is part of @fontsel
1234 1235
 *
 * Since: 2.14
Matthias Clasen's avatar
Matthias Clasen committed
1236
 */
1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250
GtkWidget *
gtk_font_selection_get_size_entry (GtkFontSelection *fontsel)
{
  g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
  
  return fontsel->size_entry;
}

/**
 * gtk_font_selection_get_size_list:
 * @fontsel: a #GtkFontSelection
 *
 * This returns the #GtkTreeeView used to list font sizes. 
 * 
Matthias Clasen's avatar
Matthias Clasen committed
1251
 * Return value: A #GtkWidget that is part of @fontsel
1252 1253
 *
 * Since: 2.14
Matthias Clasen's avatar
Matthias Clasen committed
1254
 */
1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268
GtkWidget *
gtk_font_selection_get_size_list (GtkFontSelection *fontsel)
{
  g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
  
  return fontsel->size_list;
}

/**
 * gtk_font_selection_get_preview_entry:
 * @fontsel: a #GtkFontSelection
 * 
 * This returns the #GtkEntry used to display the font as a preview.
 *
Matthias Clasen's avatar
Matthias Clasen committed
1269
 * Return value: A #GtkWidget that is part of @fontsel
1270 1271
 *
 * Since: 2.14
Matthias Clasen's avatar
Matthias Clasen committed
1272
 */
1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284
GtkWidget *
gtk_font_selection_get_preview_entry (GtkFontSelection *fontsel)
{
  g_return_val_if_fail (GTK_IS_FONT_SELECTION (fontsel), NULL);
  
  return fontsel->preview_entry;
}

/**
 * gtk_font_selection_get_family:
 * @fontsel: a #GtkFontSelection
 * 
Matthias Clasen's avatar
Matthias Clasen committed
1285 1286
 * Gets the #PangoFontFamily representing the selected font family.
 *
1287
 * Return value: A #PangoFontFamily representing the selected font
Matthias Clasen's avatar
Matthias Clasen committed
1288 1289 1290
 *     family. Font families are a collection of font faces. The 
 *     returned object is owned by @fontsel and must not be modified 
 *     or freed.
1291 1292
 *
 * Since: 2.14