gtksettings.c 81.8 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 * Copyright (C) 2000 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

19 20
#define PANGO_ENABLE_BACKEND /* for pango_fc_font_map_cache_clear() */

21
#include "config.h"
22 23 24

#include <string.h>

25
#include "gtkmodules.h"
Havoc Pennington's avatar
Havoc Pennington committed
26
#include "gtksettings.h"
27
#include "gtkrc.h"
Havoc Pennington's avatar
Havoc Pennington committed
28
#include "gtkintl.h"
29
#include "gtkwidget.h"
30
#include "gtkprivate.h"
31

32 33
#ifdef GDK_WINDOWING_X11
#include "x11/gdkx.h"
34
#include <pango/pangofc-fontmap.h>
35 36
#endif

37 38 39 40 41 42
#ifdef GDK_WINDOWING_QUARTZ
#define DEFAULT_KEY_THEME "Mac"
#else
#define DEFAULT_KEY_THEME NULL
#endif

43 44
#define DEFAULT_TIMEOUT_INITIAL 200
#define DEFAULT_TIMEOUT_REPEAT   20
45
#define DEFAULT_TIMEOUT_EXPAND  500
46

47 48
typedef struct _GtkSettingsValuePrivate GtkSettingsValuePrivate;

49 50 51 52
typedef enum
{
  GTK_SETTINGS_SOURCE_DEFAULT,
  GTK_SETTINGS_SOURCE_RC_FILE,
53
  GTK_SETTINGS_SOURCE_XSETTING,
54 55 56
  GTK_SETTINGS_SOURCE_APPLICATION
} GtkSettingsSource;

57 58 59
struct _GtkSettingsValuePrivate
{
  GtkSettingsValue public;
60
  GtkSettingsSource source;
61 62 63 64 65
};

struct _GtkSettingsPropertyValue
{
  GValue value;
66
  GtkSettingsSource source;
67 68
};

69 70
enum {
  PROP_0,
71
  PROP_DOUBLE_CLICK_TIME,
72
  PROP_DOUBLE_CLICK_DISTANCE,
73 74
  PROP_CURSOR_BLINK,
  PROP_CURSOR_BLINK_TIME,
75
  PROP_CURSOR_BLINK_TIMEOUT,
76 77
  PROP_SPLIT_CURSOR,
  PROP_THEME_NAME,
78
  PROP_ICON_THEME_NAME,
79
  PROP_FALLBACK_ICON_THEME,
Havoc Pennington's avatar
Havoc Pennington committed
80
  PROP_KEY_THEME_NAME,
Anders Carlsson's avatar
Anders Carlsson committed
81
  PROP_MENU_BAR_ACCEL,
82
  PROP_DND_DRAG_THRESHOLD,
83
  PROP_FONT_NAME,
84
  PROP_ICON_SIZES,
85
  PROP_MODULES,
86
#ifdef GDK_WINDOWING_X11
87 88 89 90
  PROP_XFT_ANTIALIAS,
  PROP_XFT_HINTING,
  PROP_XFT_HINTSTYLE,
  PROP_XFT_RGBA,
91
  PROP_XFT_DPI,
92 93
  PROP_CURSOR_THEME_NAME,
  PROP_CURSOR_THEME_SIZE,
94
#endif
95
  PROP_ALTERNATIVE_BUTTON_ORDER,
96
  PROP_ALTERNATIVE_SORT_ARROWS,
97
  PROP_SHOW_INPUT_METHOD_MENU,
98 99
  PROP_SHOW_UNICODE_MENU,
  PROP_TIMEOUT_INITIAL,
100
  PROP_TIMEOUT_REPEAT,
101
  PROP_TIMEOUT_EXPAND,
102
  PROP_COLOR_SCHEME,
103
  PROP_ENABLE_ANIMATIONS,
104
  PROP_TOUCHSCREEN_MODE,
Kristian Rietveld's avatar
Kristian Rietveld committed
105 106 107
  PROP_TOOLTIP_TIMEOUT,
  PROP_TOOLTIP_BROWSE_TIMEOUT,
  PROP_TOOLTIP_BROWSE_MODE_TIMEOUT,
108 109 110
  PROP_KEYNAV_CURSOR_ONLY,
  PROP_KEYNAV_WRAP_AROUND,
  PROP_ERROR_BELL,
111 112 113
  PROP_COLOR_HASH,
  PROP_FILE_CHOOSER_BACKEND,
  PROP_PRINT_BACKENDS,
114 115
  PROP_PRINT_PREVIEW_COMMAND,
  PROP_ENABLE_MNEMONICS,
116
  PROP_ENABLE_ACCELS,
117
  PROP_RECENT_FILES_LIMIT,
118
  PROP_IM_MODULE,
119
  PROP_RECENT_FILES_MAX_AGE,
120 121 122
  PROP_FONTCONFIG_TIMESTAMP,
  PROP_SOUND_THEME_NAME,
  PROP_ENABLE_INPUT_FEEDBACK_SOUNDS,
123
  PROP_ENABLE_EVENT_SOUNDS,
124 125
  PROP_ENABLE_TOOLTIPS,
  PROP_TOOLBAR_STYLE,
126
  PROP_TOOLBAR_ICON_SIZE,
127 128
  PROP_AUTO_MNEMONICS,
  PROP_APPLICATION_PREFER_DARK_THEME
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
};


/* --- prototypes --- */
static void	gtk_settings_finalize		 (GObject		*object);
static void	gtk_settings_get_property	 (GObject		*object,
						  guint			 property_id,
						  GValue		*value,
						  GParamSpec		*pspec);
static void	gtk_settings_set_property	 (GObject		*object,
						  guint			 property_id,
						  const GValue		*value,
						  GParamSpec		*pspec);
static void	gtk_settings_notify		 (GObject		*object,
						  GParamSpec		*pspec);
static guint	settings_install_property_parser (GtkSettingsClass      *class,
						  GParamSpec            *pspec,
						  GtkRcPropertyParser    parser);
147
static void    settings_update_double_click      (GtkSettings           *settings);
148 149
static void    settings_update_modules           (GtkSettings           *settings);

150 151
#ifdef GDK_WINDOWING_X11
static void    settings_update_cursor_theme      (GtkSettings           *settings);
152 153
static void    settings_update_resolution        (GtkSettings           *settings);
static void    settings_update_font_options      (GtkSettings           *settings);
154
static gboolean settings_update_fontconfig       (GtkSettings           *settings);
155
#endif
156
static void    settings_update_color_scheme      (GtkSettings *settings);
157

158
static void    merge_color_scheme                (GtkSettings           *settings, 
159
						  const GValue          *value, 
160 161 162
						  GtkSettingsSource      source);
static gchar  *get_color_scheme                  (GtkSettings           *settings);
static GHashTable *get_color_hash                (GtkSettings           *settings);
163 164 165 166 167 168 169 170


/* --- variables --- */
static GQuark		 quark_property_parser = 0;
static GSList           *object_list = NULL;
static guint		 class_n_properties = 0;


Matthias Clasen's avatar
Matthias Clasen committed
171
G_DEFINE_TYPE (GtkSettings, gtk_settings, G_TYPE_OBJECT)
172

Matthias Clasen's avatar
Matthias Clasen committed
173
/* --- functions --- */
174 175 176
static void
gtk_settings_init (GtkSettings *settings)
{
Tim Janik's avatar
Tim Janik committed
177 178
  GParamSpec **pspecs, **p;
  guint i = 0;
179 180 181 182 183 184 185 186
  
  g_datalist_init (&settings->queued_settings);
  object_list = g_slist_prepend (object_list, settings);

  /* build up property array for all yet existing properties and queue
   * notification for them (at least notification for internal properties
   * will instantly be caught)
   */
Tim Janik's avatar
Tim Janik committed
187 188 189 190
  pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (settings), NULL);
  for (p = pspecs; *p; p++)
    if ((*p)->owner_type == G_OBJECT_TYPE (settings))
      i++;
191
  settings->property_values = g_new0 (GtkSettingsPropertyValue, i);
Tim Janik's avatar
Tim Janik committed
192
  i = 0;
193
  g_object_freeze_notify (G_OBJECT (settings));
Tim Janik's avatar
Tim Janik committed
194
  for (p = pspecs; *p; p++)
195
    {
Tim Janik's avatar
Tim Janik committed
196
      GParamSpec *pspec = *p;
197

Tim Janik's avatar
Tim Janik committed
198 199
      if (pspec->owner_type != G_OBJECT_TYPE (settings))
	continue;
200 201
      g_value_init (&settings->property_values[i].value, G_PARAM_SPEC_VALUE_TYPE (pspec));
      g_param_value_set_default (pspec, &settings->property_values[i].value);
202
      g_object_notify (G_OBJECT (settings), pspec->name);
203
      settings->property_values[i].source = GTK_SETTINGS_SOURCE_DEFAULT;
Tim Janik's avatar
Tim Janik committed
204
      i++;
205
    }
206
  g_object_thaw_notify (G_OBJECT (settings));
Tim Janik's avatar
Tim Janik committed
207
  g_free (pspecs);
208 209 210 211 212 213
}

static void
gtk_settings_class_init (GtkSettingsClass *class)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
Havoc Pennington's avatar
Havoc Pennington committed
214
  guint result;
215 216 217 218 219 220 221
  
  gobject_class->finalize = gtk_settings_finalize;
  gobject_class->get_property = gtk_settings_get_property;
  gobject_class->set_property = gtk_settings_set_property;
  gobject_class->notify = gtk_settings_notify;

  quark_property_parser = g_quark_from_static_string ("gtk-rc-property-parser");
Havoc Pennington's avatar
Havoc Pennington committed
222
  result = settings_install_property_parser (class,
223
                                             g_param_spec_int ("gtk-double-click-time",
224 225
                                                               P_("Double Click Time"),
                                                               P_("Maximum time allowed between two clicks for them to be considered a double click (in milliseconds)"),
226
                                                               0, G_MAXINT, 250,
227
                                                               GTK_PARAM_READWRITE),
Havoc Pennington's avatar
Havoc Pennington committed
228
                                             NULL);
229
  g_assert (result == PROP_DOUBLE_CLICK_TIME);
230 231
  result = settings_install_property_parser (class,
                                             g_param_spec_int ("gtk-double-click-distance",
232 233
                                                               P_("Double Click Distance"),
                                                               P_("Maximum distance allowed between two clicks for them to be considered a double click (in pixels)"),
234
                                                               0, G_MAXINT, 5,
235
                                                               GTK_PARAM_READWRITE),
236 237
                                             NULL);
  g_assert (result == PROP_DOUBLE_CLICK_DISTANCE);
238 239 240 241 242 243

  /**
   * GtkSettings:gtk-cursor-blink:
   *
   * Whether the cursor should blink. 
   *
244 245
   * Also see the #GtkSettings:gtk-cursor-blink-timeout setting, 
   * which allows more flexible control over cursor blinking.
246
   */
247 248
  result = settings_install_property_parser (class,
                                             g_param_spec_boolean ("gtk-cursor-blink",
249 250
								   P_("Cursor Blink"),
								   P_("Whether the cursor should blink"),
251
								   TRUE,
252
								   GTK_PARAM_READWRITE),
253 254 255 256
					     NULL);
  g_assert (result == PROP_CURSOR_BLINK);
  result = settings_install_property_parser (class,
                                             g_param_spec_int ("gtk-cursor-blink-time",
257
                                                               P_("Cursor Blink Time"),
258
                                                               P_("Length of the cursor blink cycle, in milliseconds"),
259
                                                               100, G_MAXINT, 1200,
260
                                                               GTK_PARAM_READWRITE),
261 262
                                             NULL);
  g_assert (result == PROP_CURSOR_BLINK_TIME);
263 264 265 266 267 268 269 270
 
  /**
   * GtkSettings:gtk-cursor-blink-timeout:
   *
   * Time after which the cursor stops blinking, in seconds.
   * The timer is reset after each user interaction.
   *
   * Setting this to zero has the same effect as setting
Matthias Clasen's avatar
Matthias Clasen committed
271
   * #GtkSettings:gtk-cursor-blink to %FALSE. 
272 273 274 275 276 277 278 279 280 281 282
   *
   * Since: 2.12
   */
  result = settings_install_property_parser (class,
                                             g_param_spec_int ("gtk-cursor-blink-timeout",
                                                               P_("Cursor Blink Timeout"),
                                                               P_("Time after which the cursor stops blinking, in seconds"),
                                                               1, G_MAXINT, G_MAXINT,
                                                               GTK_PARAM_READWRITE),
                                             NULL);
  g_assert (result == PROP_CURSOR_BLINK_TIMEOUT);
283 284
  result = settings_install_property_parser (class,
                                             g_param_spec_boolean ("gtk-split-cursor",
285 286
								   P_("Split Cursor"),
								   P_("Whether two cursors should be displayed for mixed left-to-right and right-to-left text"),
287
								   TRUE,
288
								   GTK_PARAM_READWRITE),
289 290
                                             NULL);
  g_assert (result == PROP_SPLIT_CURSOR);
291 292
  result = settings_install_property_parser (class,
                                             g_param_spec_string ("gtk-theme-name",
293 294
								   P_("Theme Name"),
								   P_("Name of theme RC file to load"),
295
								  "Raleigh",
296
								  GTK_PARAM_READWRITE),
297 298
                                             NULL);
  g_assert (result == PROP_THEME_NAME);
299

300 301
  result = settings_install_property_parser (class,
                                             g_param_spec_string ("gtk-icon-theme-name",
302 303
								  P_("Icon Theme Name"),
								  P_("Name of icon theme to use"),
304
								  "hicolor",
305
								  GTK_PARAM_READWRITE),
306
                                             NULL);
307
  g_assert (result == PROP_ICON_THEME_NAME);
308 309 310 311 312 313 314 315 316

  result = settings_install_property_parser (class,
                                             g_param_spec_string ("gtk-fallback-icon-theme",
								  P_("Fallback Icon Theme Name"),
								  P_("Name of a icon theme to fall back to"),
								  NULL,
								  GTK_PARAM_READWRITE),
                                             NULL);
  g_assert (result == PROP_FALLBACK_ICON_THEME);
317
  
318 319
  result = settings_install_property_parser (class,
                                             g_param_spec_string ("gtk-key-theme-name",
320 321
								  P_("Key Theme Name"),
								  P_("Name of key theme RC file to load"),
322
								  DEFAULT_KEY_THEME,
323
								  GTK_PARAM_READWRITE),
324
                                             NULL);
Havoc Pennington's avatar
Havoc Pennington committed
325 326 327 328
  g_assert (result == PROP_KEY_THEME_NAME);    

  result = settings_install_property_parser (class,
                                             g_param_spec_string ("gtk-menu-bar-accel",
329 330
                                                                  P_("Menu bar accelerator"),
                                                                  P_("Keybinding to activate the menu bar"),
Havoc Pennington's avatar
Havoc Pennington committed
331
                                                                  "F10",
332
                                                                  GTK_PARAM_READWRITE),
Havoc Pennington's avatar
Havoc Pennington committed
333 334
                                             NULL);
  g_assert (result == PROP_MENU_BAR_ACCEL);
Anders Carlsson's avatar
Anders Carlsson committed
335 336 337

  result = settings_install_property_parser (class,
					     g_param_spec_int ("gtk-dnd-drag-threshold",
338 339
							       P_("Drag threshold"),
							       P_("Number of pixels the cursor can move before dragging"),
Anders Carlsson's avatar
Anders Carlsson committed
340
							       1, G_MAXINT, 8,
341
                                                               GTK_PARAM_READWRITE),
Anders Carlsson's avatar
Anders Carlsson committed
342 343
					     NULL);
  g_assert (result == PROP_DND_DRAG_THRESHOLD);
344 345 346

  result = settings_install_property_parser (class,
                                             g_param_spec_string ("gtk-font-name",
347 348
								   P_("Font Name"),
								   P_("Name of default font to use"),
349
								  "Sans 10",
350
								  GTK_PARAM_READWRITE),
351 352
                                             NULL);
  g_assert (result == PROP_FONT_NAME);
353

354 355 356 357 358 359 360 361 362 363 364 365 366 367
  /**
   * GtkSettings:gtk-icon-sizes:
   *
   * A list of icon sizes. The list is separated by colons, and
   * item has the form:
   *
   * <replaceable>size-name</replaceable> = <replaceable>width</replaceable> , <replaceable>height</replaceable>
   *
   * E.g. "gtk-menu=16,16:gtk-button=20,20:gtk-dialog=48,48". 
   * GTK+ itself use the following named icon sizes: gtk-menu, 
   * gtk-button, gtk-small-toolbar, gtk-large-toolbar, gtk-dnd, 
   * gtk-dialog. Applications can register their own named icon 
   * sizes with gtk_icon_size_register().
   */
368 369
  result = settings_install_property_parser (class,
                                             g_param_spec_string ("gtk-icon-sizes",
370
								   P_("Icon Sizes"),
371
								   P_("List of icon sizes (gtk-menu=16,16:gtk-button=20,20..."),
372
								  NULL,
373
								  GTK_PARAM_READWRITE),
374 375
                                             NULL);
  g_assert (result == PROP_ICON_SIZES);
376

377 378 379 380 381
  result = settings_install_property_parser (class,
                                             g_param_spec_string ("gtk-modules",
								  P_("GTK Modules"),
								  P_("List of currently active GTK modules"),
								  NULL,
382
								  GTK_PARAM_READWRITE),
383 384 385
                                             NULL);
  g_assert (result == PROP_MODULES);

386 387 388
#ifdef GDK_WINDOWING_X11
  result = settings_install_property_parser (class,
					     g_param_spec_int ("gtk-xft-antialias",
389 390
 							       P_("Xft Antialias"),
 							       P_("Whether to antialias Xft fonts; 0=no, 1=yes, -1=default"),
391
 							       -1, 1, -1,
392
 							       GTK_PARAM_READWRITE),
393 394 395 396 397 398
					     NULL);
 
  g_assert (result == PROP_XFT_ANTIALIAS);
  
  result = settings_install_property_parser (class,
					     g_param_spec_int ("gtk-xft-hinting",
399 400
 							       P_("Xft Hinting"),
 							       P_("Whether to hint Xft fonts; 0=no, 1=yes, -1=default"),
401
 							       -1, 1, -1,
402
 							       GTK_PARAM_READWRITE),
403 404 405 406 407 408
					     NULL);
  
  g_assert (result == PROP_XFT_HINTING);
  
  result = settings_install_property_parser (class,
					     g_param_spec_string ("gtk-xft-hintstyle",
409
 								  P_("Xft Hint Style"),
410
 								  P_("What degree of hinting to use; hintnone, hintslight, hintmedium, or hintfull"),
411
 								  NULL,
412
 								  GTK_PARAM_READWRITE),
413 414 415 416 417 418
                                              NULL);
  
  g_assert (result == PROP_XFT_HINTSTYLE);
  
  result = settings_install_property_parser (class,
					     g_param_spec_string ("gtk-xft-rgba",
419 420
 								  P_("Xft RGBA"),
 								  P_("Type of subpixel antialiasing; none, rgb, bgr, vrgb, vbgr"),
421
 								  NULL,
422
 								  GTK_PARAM_READWRITE),
423 424 425 426 427 428
					     NULL);
  
  g_assert (result == PROP_XFT_RGBA);
  
  result = settings_install_property_parser (class,
					     g_param_spec_int ("gtk-xft-dpi",
429 430
 							       P_("Xft DPI"),
 							       P_("Resolution for Xft, in 1024 * dots/inch. -1 to use default value"),
431
 							       -1, 1024*1024, -1,
432
 							       GTK_PARAM_READWRITE),
433 434 435
					     NULL);
  
  g_assert (result == PROP_XFT_DPI);
436 437 438 439

  result = settings_install_property_parser (class,
                                             g_param_spec_string ("gtk-cursor-theme-name",
								  P_("Cursor theme name"),
440
								  P_("Name of the cursor theme to use, or NULL to use the default theme"),
441 442 443 444 445 446 447 448
								  NULL,
								  GTK_PARAM_READWRITE),
                                             NULL);
  g_assert (result == PROP_CURSOR_THEME_NAME);

  result = settings_install_property_parser (class,
					     g_param_spec_int ("gtk-cursor-theme-size",
 							       P_("Cursor theme size"),
449 450
 							       P_("Size to use for cursors, or 0 to use the default size"),
 							       0, 128, 0,
451 452 453 454 455
 							       GTK_PARAM_READWRITE),
					     NULL);
  
  g_assert (result == PROP_CURSOR_THEME_SIZE);

456
#endif  /* GDK_WINDOWING_X11 */
457 458 459 460 461
  result = settings_install_property_parser (class,
                                             g_param_spec_boolean ("gtk-alternative-button-order",
								   P_("Alternative button order"),
								   P_("Whether buttons in dialogs should use the alternative button order"),
								   FALSE,
462
								   GTK_PARAM_READWRITE),
463 464
                                             NULL);
  g_assert (result == PROP_ALTERNATIVE_BUTTON_ORDER);
465

466 467 468 469
  /**
   * GtkSettings:gtk-alternative-sort-arrows:
   *
   * Controls the direction of the sort indicators in sorted list and tree
470 471
   * views. By default an arrow pointing down means the column is sorted
   * in ascending order. When set to %TRUE, this order will be inverted.
472 473 474 475 476 477 478 479 480 481 482 483
   *
   * Since: 2.12
   */
  result = settings_install_property_parser (class,
                                             g_param_spec_boolean ("gtk-alternative-sort-arrows",
								   P_("Alternative sort indicator direction"),
								   P_("Whether the direction of the sort indicators in list and tree views is inverted compared to the default (where down means ascending)"),
								   FALSE,
								   GTK_PARAM_READWRITE),
                                             NULL);
  g_assert (result == PROP_ALTERNATIVE_SORT_ARROWS);

484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
  result = settings_install_property_parser (class,
					     g_param_spec_boolean ("gtk-show-input-method-menu",
								   P_("Show the 'Input Methods' menu"),
								   P_("Whether the context menus of entries and text views should offer to change the input method"),
								   TRUE,
								   GTK_PARAM_READWRITE),
					     NULL);
  g_assert (result == PROP_SHOW_INPUT_METHOD_MENU);

  result = settings_install_property_parser (class,
					     g_param_spec_boolean ("gtk-show-unicode-menu",
								   P_("Show the 'Insert Unicode Control Character' menu"),
								   P_("Whether the context menus of entries and text views should offer to insert control characters"),
								   TRUE,
								   GTK_PARAM_READWRITE),
					     NULL);
  g_assert (result == PROP_SHOW_UNICODE_MENU);

502 503 504 505 506
  result = settings_install_property_parser (class,
					     g_param_spec_int ("gtk-timeout-initial",
 							       P_("Start timeout"),
 							       P_("Starting value for timeouts, when button is pressed"),
 							       0, G_MAXINT, DEFAULT_TIMEOUT_INITIAL,
507
 							       GTK_PARAM_READWRITE),
508 509 510 511 512 513 514 515 516
					     NULL);

  g_assert (result == PROP_TIMEOUT_INITIAL);

  result = settings_install_property_parser (class,
					     g_param_spec_int ("gtk-timeout-repeat",
 							       P_("Repeat timeout"),
 							       P_("Repeat value for timeouts, when button is pressed"),
 							       0, G_MAXINT, DEFAULT_TIMEOUT_REPEAT,
517
 							       GTK_PARAM_READWRITE),
518 519 520
					     NULL);

  g_assert (result == PROP_TIMEOUT_REPEAT);
521

522 523 524 525 526 527 528 529 530 531
  result = settings_install_property_parser (class,
					     g_param_spec_int ("gtk-timeout-expand",
 							       P_("Expand timeout"),
 							       P_("Expand value for timeouts, when a widget is expanding a new region"),
 							       0, G_MAXINT, DEFAULT_TIMEOUT_EXPAND,
 							       GTK_PARAM_READWRITE),
					     NULL);

  g_assert (result == PROP_TIMEOUT_EXPAND);

532 533 534 535 536 537 538 539 540 541 542 543 544 545
  /**
   * GtkSettings:gtk-color-scheme:
   *
   * A palette of named colors for use in themes. The format of the string is
   * <programlisting>
   * name1: color1
   * name2: color2
   * ...
   * </programlisting>
   * Color names must be acceptable as identifiers in the 
   * <link linkend="gtk-Resource-Files">gtkrc</link> syntax, and
   * color specifications must be in the format accepted by
   * gdk_color_parse().
   * 
546 547 548 549
   * Note that due to the way the color tables from different sources are
   * merged, color specifications will be converted to hexadecimal form
   * when getting this property.
   *
550 551 552 553 554 555
   * Starting with GTK+ 2.12, the entries can alternatively be separated
   * by ';' instead of newlines:
   * <programlisting>
   * name1: color1; name2: color2; ...
   * </programlisting>
   *
556 557
   * Since: 2.10
   */
558 559 560 561
  result = settings_install_property_parser (class,
					     g_param_spec_string ("gtk-color-scheme",
 								  P_("Color scheme"),
 								  P_("A palette of named colors for use in themes"),
562
 								  "",
563 564 565 566
 								  GTK_PARAM_READWRITE),
					     NULL);

  g_assert (result == PROP_COLOR_SCHEME);
567 568 569 570 571 572 573 574 575 576

  result = settings_install_property_parser (class,
                                             g_param_spec_boolean ("gtk-enable-animations",
                                                                   P_("Enable Animations"),
                                                                   P_("Whether to enable toolkit-wide animations."),
                                                                   TRUE,
                                                                   GTK_PARAM_READWRITE),
                                             NULL);

  g_assert (result == PROP_ENABLE_ANIMATIONS);
577

578 579 580
  /**
   * GtkSettings:gtk-touchscreen-mode:
   *
581
   * When %TRUE, there are no motion notify events delivered on this screen,
582 583 584 585 586 587 588 589 590 591 592 593 594 595
   * and widgets can't use the pointer hovering them for any essential
   * functionality.
   *
   * Since: 2.10
   */
  result = settings_install_property_parser (class,
                                             g_param_spec_boolean ("gtk-touchscreen-mode",
                                                                   P_("Enable Touchscreen Mode"),
                                                                   P_("When TRUE, there are no motion notify events delivered on this screen"),
                                                                   FALSE,
                                                                   GTK_PARAM_READWRITE),
                                             NULL);

  g_assert (result == PROP_TOUCHSCREEN_MODE);
596

Kristian Rietveld's avatar
Kristian Rietveld committed
597 598 599 600 601 602 603 604 605 606
  /**
   * GtkSettings:gtk-tooltip-timeout:
   *
   * Time, in milliseconds, after which a tooltip could appear if the
   * cursor is hovering on top of a widget.
   *
   * Since: 2.12
   */
  result = settings_install_property_parser (class,
					     g_param_spec_int ("gtk-tooltip-timeout",
607 608 609 610 611
							       P_("Tooltip timeout"),
							       P_("Timeout before tooltip is shown"),
							       0, G_MAXINT,
							       500,
							       GTK_PARAM_READWRITE),
Kristian Rietveld's avatar
Kristian Rietveld committed
612 613 614 615 616 617 618 619 620 621 622
					     NULL);

  g_assert (result == PROP_TOOLTIP_TIMEOUT);

  /**
   * GtkSettings:gtk-tooltip-browse-timeout:
   *
   * Controls the time after which tooltips will appear when
   * browse mode is enabled, in milliseconds.
   *
   * Browse mode is enabled when the mouse pointer moves off an object
623
   * where a tooltip was currently being displayed. If the mouse pointer
Kristian Rietveld's avatar
Kristian Rietveld committed
624
   * hits another object before the browse mode timeout expires (see
625 626
   * #GtkSettings:gtk-tooltip-browse-mode-timeout), it will take the 
   * amount of milliseconds specified by this setting to popup the tooltip
Kristian Rietveld's avatar
Kristian Rietveld committed
627 628 629 630 631 632
   * for the new object.
   *
   * Since: 2.12
   */
  result = settings_install_property_parser (class,
					     g_param_spec_int ("gtk-tooltip-browse-timeout",
633 634 635 636 637
							       P_("Tooltip browse timeout"),
							       P_("Timeout before tooltip is shown when browse mode is enabled"),
							       0, G_MAXINT,
							       60,
							       GTK_PARAM_READWRITE),
Kristian Rietveld's avatar
Kristian Rietveld committed
638 639 640 641 642 643 644 645 646 647
					     NULL);

  g_assert (result == PROP_TOOLTIP_BROWSE_TIMEOUT);

  /**
   * GtkSettings:gtk-tooltip-browse-mode-timeout:
   *
   * Amount of time, in milliseconds, after which the browse mode
   * will be disabled.
   *
648
   * See #GtkSettings:gtk-tooltip-browse-timeout for more information
Kristian Rietveld's avatar
Kristian Rietveld committed
649 650 651 652 653 654 655 656 657 658 659 660 661 662 663
   * about browse mode.
   *
   * Since: 2.12
   */
  result = settings_install_property_parser (class,
					     g_param_spec_int ("gtk-tooltip-browse-mode-timeout",
 							       P_("Tooltip browse mode timeout"),
 							       P_("Timeout after which browse mode is disabled"),
 							       0, G_MAXINT,
							       500,
 							       GTK_PARAM_READWRITE),
					     NULL);

  g_assert (result == PROP_TOOLTIP_BROWSE_MODE_TIMEOUT);

664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721
  /**
   * GtkSettings:gtk-keynav-cursor-only:
   *
   * When %TRUE, keyboard navigation should be able to reach all widgets
   * by using the cursor keys only. Tab, Shift etc. keys can't be expected
   * to be present on the used input device.
   *
   * Since: 2.12
   */
  result = settings_install_property_parser (class,
                                             g_param_spec_boolean ("gtk-keynav-cursor-only",
                                                                   P_("Keynav Cursor Only"),
                                                                   P_("When TRUE, there are only cursor keys available to navigate widgets"),
                                                                   FALSE,
                                                                   GTK_PARAM_READWRITE),
                                             NULL);

  g_assert (result == PROP_KEYNAV_CURSOR_ONLY);

  /**
   * GtkSettings:gtk-keynav-wrap-around:
   *
   * When %TRUE, some widgets will wrap around when doing keyboard
   * navigation, such as menus, menubars and notebooks.
   *
   * Since: 2.12
   */
  result = settings_install_property_parser (class,
                                             g_param_spec_boolean ("gtk-keynav-wrap-around",
                                                                   P_("Keynav Wrap Around"),
                                                                   P_("Whether to wrap around when keyboard-navigating widgets"),
                                                                   TRUE,
                                                                   GTK_PARAM_READWRITE),
                                             NULL);

  g_assert (result == PROP_KEYNAV_WRAP_AROUND);

  /**
   * GtkSettings:gtk-error-bell:
   *
   * When %TRUE, keyboard navigation and other input-related errors
   * will cause a beep. Since the error bell is implemented using
   * gdk_window_beep(), the windowing system may offer ways to
   * configure the error bell in many ways, such as flashing the
   * window or similar visual effects.
   *
   * Since: 2.12
   */
  result = settings_install_property_parser (class,
                                             g_param_spec_boolean ("gtk-error-bell",
                                                                   P_("Error Bell"),
                                                                   P_("When TRUE, keyboard navigation and other errors will cause a beep"),
                                                                   TRUE,
                                                                   GTK_PARAM_READWRITE),
                                             NULL);

  g_assert (result == PROP_ERROR_BELL);

722 723 724
  /**
   * GtkSettings:color-hash:
   *
725 726
   * Holds a hash table representation of the #GtkSettings:gtk-color-scheme 
   * setting, mapping color names to #GdkColor<!-- -->s. 
727 728 729
   *
   * Since: 2.10
   */
730 731 732 733 734 735 736 737
  result = settings_install_property_parser (class, 
                                             g_param_spec_boxed ("color-hash",
                                                                 P_("Color Hash"),
                                                                 P_("A hash table representation of the color scheme."),
                                                                 G_TYPE_HASH_TABLE,
                                                                 GTK_PARAM_READABLE),
                                             NULL);
  g_assert (result == PROP_COLOR_HASH);
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752

  result = settings_install_property_parser (class, 
                                             g_param_spec_string ("gtk-file-chooser-backend",
                                                                  P_("Default file chooser backend"),
                                                                  P_("Name of the GtkFileChooser backend to use by default"),
                                                                  NULL,
                                                                  GTK_PARAM_READWRITE),
                                             NULL);
  g_assert (result == PROP_FILE_CHOOSER_BACKEND);

  /**
   * GtkSettings:gtk-print-backends:
   *
   * A comma-separated list of print backends to use in the print
   * dialog. Available print backends depend on the GTK+ installation,
Matthias Clasen's avatar
Matthias Clasen committed
753
   * and may include "file", "cups", "lpr" or "papi".
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770
   *
   * Since: 2.10
   */
  result = settings_install_property_parser (class,
                                             g_param_spec_string ("gtk-print-backends",
                                                                  P_("Default print backend"),
                                                                  P_("List of the GtkPrintBackend backends to use by default"),
                                                                  GTK_PRINT_BACKENDS,
                                                                  GTK_PARAM_READWRITE),
                                             NULL);
  g_assert (result == PROP_PRINT_BACKENDS);

  /**
   * GtkSettings:gtk-print-preview-command:
   *
   * A command to run for displaying the print preview. The command
   * should contain a %f placeholder, which will get replaced by
771 772 773 774
   * the path to the pdf file. The command may also contain a %s
   * placeholder, which will get replaced by the path to a file
   * containing the print settings in the format produced by 
   * gtk_print_settings_to_file().
775 776
   *
   * The preview application is responsible for removing the pdf file
777
   * and the print settings file when it is done.
778 779 780 781 782 783 784 785 786 787 788
   *
   * Since: 2.10
   */
  result = settings_install_property_parser (class,
                                             g_param_spec_string ("gtk-print-preview-command",
                                                                  P_("Default command to run when displaying a print preview"),
                                                                  P_("Command to run when displaying a print preview"),
                                                                  GTK_PRINT_PREVIEW_COMMAND,
                                                                  GTK_PARAM_READWRITE),
                                             NULL); 
  g_assert (result == PROP_PRINT_PREVIEW_COMMAND);
789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822

  /**
   * GtkSettings:gtk-enable-mnemonics:
   *
   * Whether labels and menu items should have visible mnemonics which
   * can be activated.
   *
   * Since: 2.12
   */
  result = settings_install_property_parser (class,
                                             g_param_spec_boolean ("gtk-enable-mnemonics",
                                                                   P_("Enable Mnemonics"),
                                                                   P_("Whether labels should have mnemonics"),
                                                                   TRUE,
                                                                   GTK_PARAM_READWRITE),
                                             NULL);
  g_assert (result == PROP_ENABLE_MNEMONICS);

  /**
   * GtkSettings:gtk-enable-accels:
   *
   * Whether menu items should have visible accelerators which can be
   * activated.
   *
   * Since: 2.12
   */
  result = settings_install_property_parser (class,
                                             g_param_spec_boolean ("gtk-enable-accels",
                                                                   P_("Enable Accelerators"),
                                                                   P_("Whether menu items should have accelerators"),
                                                                   TRUE,
                                                                   GTK_PARAM_READWRITE),
                                             NULL);
  g_assert (result == PROP_ENABLE_ACCELS);
823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841

  /**
   * GtkSettings:gtk-recent-files-limit:
   *
   * The number of recently used files that should be displayed by default by
   * #GtkRecentChooser implementations and by the #GtkFileChooser. A value of
   * -1 means every recently used file stored.
   *
   * Since: 2.12
   */
  result = settings_install_property_parser (class,
					     g_param_spec_int ("gtk-recent-files-limit",
 							       P_("Recent Files Limit"),
 							       P_("Number of recently used files"),
 							       -1, G_MAXINT,
							       50,
 							       GTK_PARAM_READWRITE),
					     NULL);
  g_assert (result == PROP_RECENT_FILES_LIMIT);
842 843 844 845

  /**
   * GtkSettings:gtk-im-module:
   *
846 847 848 849 850
   * Which IM (input method) module should be used by default. This is the 
   * input method that will be used if the user has not explicitly chosen 
   * another input method from the IM context menu.  
   *
   * See #GtkIMContext and see the #GtkSettings:gtk-show-input-method-menu property.
851 852 853 854 855 856 857 858 859
   */
  result = settings_install_property_parser (class,
					     g_param_spec_string ("gtk-im-module",
								  P_("Default IM module"),
								  P_("Which IM module should be used by default"),
								  NULL,
								  GTK_PARAM_READWRITE),
					     NULL);
  g_assert (result == PROP_IM_MODULE);
860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879

  /**
   * GtkSettings:gtk-recent-files-max-age:
   *
   * The maximum age, in days, of the items inside the recently used
   * resources list. Items older than this setting will be excised
   * from the list. If set to 0, the list will always be empty; if
   * set to -1, no item will be removed.
   *
   * Since: 2.14
   */
  result = settings_install_property_parser (class,
					     g_param_spec_int ("gtk-recent-files-max-age",
 							       P_("Recent Files Max Age"),
 							       P_("Maximum age of recently used files, in days"),
 							       -1, G_MAXINT,
							       30,
 							       GTK_PARAM_READWRITE),
					     NULL);
  g_assert (result == PROP_RECENT_FILES_MAX_AGE);
880 881

  result = settings_install_property_parser (class,
882 883 884 885 886
					     g_param_spec_uint ("gtk-fontconfig-timestamp",
								P_("Fontconfig configuration timestamp"),
								P_("Timestamp of current fontconfig configuration"),
								0, G_MAXUINT, 0,
								GTK_PARAM_READWRITE),
887 888 889
					     NULL);
  
  g_assert (result == PROP_FONTCONFIG_TIMESTAMP);
890

891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927
  /**
   * GtkSettings:gtk-sound-theme-name:
   *
   * The XDG sound theme to use for event sounds.
   *
   * See the <ulink url="http://www.freedesktop.org/wiki/Specifications/sound-theme-spec">Sound Theme spec</ulink> 
   * for more information on event sounds and sound themes.
   *
   * GTK+ itself does not support event sounds, you have to use a loadable 
   * module like the one that comes with libcanberra.
   *
   * Since: 2.14
   */
  result = settings_install_property_parser (class,
                                             g_param_spec_string ("gtk-sound-theme-name",
                                                                  P_("Sound Theme Name"),
                                                                  P_("XDG sound theme name"),
                                                                  "freedesktop",
                                                                  GTK_PARAM_READWRITE),
                                             NULL);
  g_assert (result == PROP_SOUND_THEME_NAME);

  /**
   * GtkSettings:gtk-enable-input-feedback-sounds:
   *
   * Whether to play event sounds as feedback to user input.
   *
   * See the <ulink url="http://www.freedesktop.org/wiki/Specifications/sound-theme-spec">Sound Theme spec</ulink> 
   * for more information on event sounds and sound themes.
   *
   * GTK+ itself does not support event sounds, you have to use a loadable 
   * module like the one that comes with libcanberra.
   *
   * Since: 2.14
   */
  result = settings_install_property_parser (class,
                                             g_param_spec_boolean ("gtk-enable-input-feedback-sounds",
Matthias Clasen's avatar
Matthias Clasen committed
928
                                                                   /* Translators: this means sounds that are played as feedback to user input */
Matthias Clasen's avatar
Matthias Clasen committed
929
								   P_("Audible Input Feedback"),
930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956
								   P_("Whether to play event sounds as feedback to user input"),
								   TRUE,
								   GTK_PARAM_READWRITE),
                                             NULL);
  g_assert (result == PROP_ENABLE_INPUT_FEEDBACK_SOUNDS);

  /**
   * GtkSettings:gtk-enable-event-sounds:
   *
   * Whether to play any event sounds at all.
   *
   * See the <ulink url="http://www.freedesktop.org/wiki/Specifications/sound-theme-spec">Sound Theme spec</ulink> 
   * for more information on event sounds and sound themes.
   *
   * GTK+ itself does not support event sounds, you have to use a loadable 
   * module like the one that comes with libcanberra.
   *
   * Since: 2.14
   */
  result = settings_install_property_parser (class,
                                             g_param_spec_boolean ("gtk-enable-event-sounds",
								   P_("Enable Event Sounds"),
								   P_("Whether to play any event sounds at all"),
								   TRUE,
								   GTK_PARAM_READWRITE),
                                             NULL);
  g_assert (result == PROP_ENABLE_EVENT_SOUNDS);
957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972

  /**
   * GtkSettings:gtk-enable-tooltips:
   *
   * Whether tooltips should be shown on widgets.
   *
   * Since: 2.14
   */
  result = settings_install_property_parser (class,
                                             g_param_spec_boolean ("gtk-enable-tooltips",
                                                                   P_("Enable Tooltips"),
                                                                   P_("Whether tooltips should be shown on widgets"),
                                                                   TRUE,
                                                                   GTK_PARAM_READWRITE),
                                             NULL);
  g_assert (result == PROP_ENABLE_TOOLTIPS);
973 974 975 976 977 978 979 980 981 982 983 984 985

  /**
   * GtkSettings:toolbar-style:
   *
   * The size of icons in default toolbars.
   */
  result = settings_install_property_parser (class,
                                             g_param_spec_enum ("gtk-toolbar-style",
                                                                   P_("Toolbar style"),
                                                                   P_("Whether default toolbars have text only, text and icons, icons only, etc."),
                                                                   GTK_TYPE_TOOLBAR_STYLE,
                                                                   GTK_TOOLBAR_BOTH,
                                                                   GTK_PARAM_READWRITE),
986
                                             gtk_rc_property_parse_enum);
987 988 989 990 991 992 993 994 995 996 997 998 999 1000
  g_assert (result == PROP_TOOLBAR_STYLE);

  /**
   * GtkSettings:toolbar-icon-size:
   *
   * The size of icons in default toolbars.
   */
  result = settings_install_property_parser (class,
                                             g_param_spec_enum ("gtk-toolbar-icon-size",
                                                                   P_("Toolbar Icon Size"),
                                                                   P_("The size of icons in default toolbars."),
                                                                   GTK_TYPE_ICON_SIZE,
                                                                   GTK_ICON_SIZE_LARGE_TOOLBAR,
                                                                   GTK_PARAM_READWRITE),
1001
                                             gtk_rc_property_parse_enum);
1002
  g_assert (result == PROP_TOOLBAR_ICON_SIZE);
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019

  /**
   * GtkSettings:gtk-auto-mnemonics:
   *
   * Whether mnemonics should be automatically shown and hidden when the user
   * presses the mnemonic activator.
   *
   * Since: 2.20
   */
  result = settings_install_property_parser (class,
                                             g_param_spec_boolean ("gtk-auto-mnemonics",
                                                                   P_("Auto Mnemonics"),
                                                                   P_("Whether mnemonics should be automatically shown and hidden when the user presses the mnemonic activator."),
                                                                   FALSE,
                                                                   GTK_PARAM_READWRITE),
                                             NULL);
  g_assert (result == PROP_AUTO_MNEMONICS);
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045

  /**
   * GtkSettings:gtk-application-prefer-dark-theme:
   *
   * Whether the application prefers to use a dark theme. If a GTK+ theme
   * includes a dark variant, it will be used instead of the configured
   * theme.
   *
   * Some applications benefit from minimizing the amount of light pollution that
   * interferes with the content. Good candidates for dark themes are photo and
   * video editors that make the actual content get all the attention and minimize
   * the distraction of the chrome.
   *
   * Dark themes should not be used for documents, where large spaces are white/light
   * and the dark chrome creates too much contrast (web browser, text editor...).
   *
   * Since: 2.22
   */
  result = settings_install_property_parser (class,
                                             g_param_spec_boolean ("gtk-application-prefer-dark-theme",
                                                                 P_("Application prefers a dark theme"),
                                                                 P_("Whether the application prefers to have a dark theme."),
                                                                 FALSE,
                                                                 GTK_PARAM_READWRITE),
                                             NULL);
  g_assert (result == PROP_APPLICATION_PREFER_DARK_THEME);
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055
}

static void
gtk_settings_finalize (GObject *object)
{
  GtkSettings *settings = GTK_SETTINGS (object);
  guint i;

  object_list = g_slist_remove (object_list, settings);

Matthias Clasen's avatar
Matthias Clasen committed
1056 1057
  _gtk_rc_context_destroy (settings);

1058
  for (i = 0; i < class_n_properties; i++)
1059
    g_value_unset (&settings->property_values[i].value);
1060
  g_free (settings->property_values);
1061
  
1062 1063
  g_datalist_clear (&settings->queued_settings);

Matthias Clasen's avatar
Matthias Clasen committed
1064
  G_OBJECT_CLASS (gtk_settings_parent_class)->finalize (object);
1065 1066
}

1067 1068 1069 1070 1071 1072 1073
/**
 * gtk_settings_get_for_screen:
 * @screen : a #GdkScreen.
 * 
 * Gets the #GtkSettings object for @screen, creating it if necessary.
 *
 * Return value: a #GtkSettings object.
1074 1075
 *
 * Since: 2.2
1076 1077 1078
 */
GtkSettings*
gtk_settings_get_for_screen (GdkScreen *screen)
1079
{
1080 1081 1082 1083 1084 1085
  GtkSettings *settings;
  
  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
  
  settings = g_object_get_data (G_OBJECT (screen), "gtk-settings");
  if (!settings)
1086
    {
1087 1088
      settings = g_object_new (GTK_TYPE_SETTINGS, NULL);
      settings->screen = screen;
1089 1090
      g_object_set_data_full (G_OBJECT (screen), I_("gtk-settings"), 
			      settings, g_object_unref);
1091

1092
      gtk_rc_reparse_all_for_settings (settings, TRUE);
1093
      settings_update_double_click (settings);
1094
#ifdef GDK_WINDOWING_X11
1095 1096
      settings_update_cursor_theme (settings);
      settings_update_resolution (settings);
1097 1098
      settings_update_font_options (settings);
#endif
1099
      settings_update_color_scheme (settings);
1100
    }
1101 1102
  
  return settings;
1103 1104
}

1105 1106 1107 1108 1109
/**
 * gtk_settings_get_default:
 * 
 * Gets the #GtkSettings object for the default GDK screen, creating
 * it if necessary. See gtk_settings_get_for_screen().
1110 1111
 *
 * Return value: (transfer none): a #GtkSettings object. If there is no default
1112
 *  screen, then returns %NULL.
1113
 **/
1114
GtkSettings*
1115
gtk_settings_get_default (void)
1116
{
1117 1118 1119 1120 1121 1122
  GdkScreen *screen = gdk_screen_get_default ();

  if (screen)
    return gtk_settings_get_for_screen (screen);
  else
    return NULL;
1123 1124 1125 1126 1127 1128 1129 1130 1131
}

static void
gtk_settings_set_property (GObject      *object,
			   guint	 property_id,
			   const GValue *value,
			   GParamSpec   *pspec)
{
  GtkSettings *settings = GTK_SETTINGS (object);
1132

1133
  g_value_copy (value, &settings->property_values[property_id - 1].value);
1134
  settings->property_values[property_id - 1].source = GTK_SETTINGS_SOURCE_APPLICATION;
1135 1136 1137
  
  if (pspec->param_id == PROP_COLOR_SCHEME)
    merge_color_scheme (settings, value, GTK_SETTINGS_SOURCE_APPLICATION);
1138 1139 1140 1141 1142 1143 1144 1145 1146
}

static void
gtk_settings_get_property (GObject     *object,
			   guint	property_id,
			   GValue      *value,
			   GParamSpec  *pspec)
{
  GtkSettings *settings = GTK_SETTINGS (object);
1147 1148
  GType value_type = G_VALUE_TYPE (value);
  GType fundamental_type = G_TYPE_FUNDAMENTAL (value_type);
1149

1150 1151
  /* handle internal properties */
  switch (property_id)
1152
    {
1153
    case PROP_COLOR_HASH:
1154 1155
      g_value_set_boxed (value, get_color_hash (settings));
      return;
1156 1157 1158 1159
    case PROP_COLOR_SCHEME:
      g_value_take_string (value, get_color_scheme (settings));
      return;
    default: ;
1160 1161
    }

1162 1163 1164 1165 1166 1167
  /* For enums and strings, we need to get the value as a string,
   * not as an int, since we support using names/nicks as the setting
   * value.
   */
  if ((g_value_type_transformable (G_TYPE_INT, value_type) &&
       !(fundamental_type == G_TYPE_ENUM || fundamental_type == G_TYPE_FLAGS)) ||
1168 1169 1170
      g_value_type_transformable (G_TYPE_STRING, G_VALUE_TYPE (value)) ||
      g_value_type_transformable (GDK_TYPE_COLOR, G_VALUE_TYPE (value)))
    {
1171 1172
      if (settings->property_values[property_id - 1].source == GTK_SETTINGS_SOURCE_APPLICATION ||
	  !gdk_screen_get_setting (settings->screen, pspec->name, value))
1173
        g_value_copy (&settings->property_values[property_id - 1].value, value);
1174
      else 
1175
        g_param_value_validate (pspec, value);
1176
    }
1177
  else
1178 1179 1180 1181 1182 1183 1184
    {
      GValue val = { 0, };

      /* Try to get xsetting as a string and parse it. */
      
      g_value_init (&val, G_TYPE_STRING);

1185 1186
      if (settings->property_values[property_id - 1].source == GTK_SETTINGS_SOURCE_APPLICATION ||
	  !gdk_screen_get_setting (settings->screen, pspec->name, &val))
1187
        {
1188
          g_value_copy (&settings->property_values[property_id - 1].value, value);
1189 1190 1191 1192 1193
        }
      else
        {
          GValue tmp_value = { 0, };
          GValue gstring_value = { 0, };
1194
          GtkRcPropertyParser parser = (GtkRcPropertyParser) g_param_spec_get_qdata (pspec, quark_property_parser);
1195 1196
          
          g_value_init (&gstring_value, G_TYPE_GSTRING);
1197 1198
          g_value_take_boxed (&gstring_value,
                              g_string_new (g_value_get_string (&val)));
1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209

          g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));

          if (parser && _gtk_settings_parse_convert (parser, &gstring_value,
                                                     pspec, &tmp_value))
            {
              g_value_copy (&tmp_value, value);
              g_param_value_validate (pspec, value);
            }
          else
            {
1210
              g_value_copy (&settings->property_values[property_id - 1].value, value);
1211 1212 1213 1214 1215 1216 1217 1218
            }

          g_value_unset (&gstring_value);
          g_value_unset (&tmp_value);
        }

      g_value_unset (&val);
    }
1219 1220 1221 1222 1223 1224
}

static void
gtk_settings_notify (GObject    *object,
		     GParamSpec *pspec)
{
1225
  GtkSettings *settings = GTK_SETTINGS (object);
Tim Janik's avatar
Tim Janik committed
1226
  guint property_id = pspec->param_id;
1227 1228 1229

  if (settings->screen == NULL) /* initialization */
    return;
1230 1231 1232

  switch (property_id)
    {
1233 1234 1235
    case PROP_MODULES:
      settings_update_modules (settings);
      break;
1236
    case PROP_DOUBLE_CLICK_TIME:
1237 1238
    case PROP_DOUBLE_CLICK_DISTANCE:
      settings_update_double_click (settings);
1239
      break;
1240 1241 1242
    case PROP_COLOR_SCHEME:
      settings_update_color_scheme (settings);
      break;
1243 1244
#ifdef GDK_WINDOWING_X11
    case PROP_XFT_DPI:
1245
      settings_update_resolution (settings);
1246 1247 1248 1249
      /* This is a hack because with gtk_rc_reset_styles() doesn't get
       * widgets with gtk_widget_style_set(), and also causes more
       * recomputation than necessary.
       */
1250 1251
      gtk_rc_reset_styles (GTK_SETTINGS (object));
      break;
1252 1253 1254 1255 1256 1257 1258
    case PROP_XFT_ANTIALIAS:
    case PROP_XFT_HINTING:
    case PROP_XFT_HINTSTYLE:
    case PROP_XFT_RGBA:
      settings_update_font_options (settings);
      gtk_rc_reset_styles (GTK_SETTINGS (object));
      break;
1259 1260 1261 1262
    case PROP_FONTCONFIG_TIMESTAMP:
      if (settings_update_fontconfig (settings))
	gtk_rc_reset_styles (GTK_SETTINGS (object));
      break;
1263 1264 1265 1266
    case PROP_CURSOR_THEME_NAME:
    case PROP_CURSOR_THEME_SIZE:
      settings_update_cursor_theme (settings);
      break;
1267
#endif /* GDK_WINDOWING_X11 */
1268 1269 1270
    }
}

1271 1272 1273 1274 1275
gboolean
_gtk_settings_parse_convert (GtkRcPropertyParser parser,
			     const GValue       *src_value,
			     GParamSpec         *pspec,
			     GValue	        *dest_value)
1276
{
1277
  gboolean success = FALSE;
1278

1279
  g_return_val_if_fail (G_VALUE_HOLDS (dest_value, G_PARAM_SPEC_VALUE_TYPE (pspec)), FALSE);
1280

1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292
  if (parser)
    {
      GString *gstring;
      gboolean free_gstring = TRUE;
      
      if (G_VALUE_HOLDS (src_value, G_TYPE_GSTRING))
	{
	  gstring = g_value_get_boxed (src_value);
	  free_gstring = FALSE;
	}
      else if (G_VALUE_HOLDS_LONG (src_value))
	{
1293
	  gstring = g_string_new (NULL);
1294
	  g_string_append_printf (gstring, "%ld", g_value_get_long (src_value));
1295 1296 1297
	}
      else if (G_VALUE_HOLDS_DOUBLE (src_value))
	{
1298
	  gstring = g_string_new (NULL);
1299
	  g_string_append_printf (gstring, "%f", g_value_get_double (src_value));
1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
	}
      else if (G_VALUE_HOLDS_STRING (src_value))
	{
	  gchar *tstr = g_strescape (g_value_get_string (src_value), NULL);
	  
	  gstring = g_string_new ("\"");
	  g_string_append (gstring, tstr);
	  g_string_append_c (gstring, '\"');
	  g_free (tstr);
	}
1310 1311
      else
	{
1312 1313
	  g_return_val_if_fail (G_VALUE_HOLDS (src_value, G_TYPE_GSTRING), FALSE);
	  gstring = NULL; /* silence compiler */
1314
	}
1315 1316 1317 1318 1319 1320

      success = (parser (pspec, gstring, dest_value) &&
		 !g_param_value_validate (pspec, dest_value));

      if (free_gstring)
	g_string_free (gstring, TRUE);
1321
    }
1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332
  else if (G_VALUE_HOLDS (src_value, G_TYPE_GSTRING))
    {
      if (G_VALUE_HOLDS (dest_value, G_TYPE_STRING))
	{
	  GString *gstring = g_value_get_boxed (src_value);

	  g_value_set_string (dest_value, gstring ? gstring->str : NULL);
	  success = !g_param_value_validate (pspec, dest_value);
	}
    }
  else if (g_value_type_transformable (G_VALUE_TYPE (src_value), G_VALUE_TYPE (dest_value)))
1333 1334 1335 1336 1337 1338
    success = g_param_value_convert (pspec, src_value, dest_value, TRUE);

  return success;
}

static void
1339 1340 1341
apply_queued_setting (GtkSettings             *data,
		      GParamSpec              *pspec,
		      GtkSettingsValuePrivate *qvalue)
1342 1343
{
  GValue tmp_value = { 0, };
1344
  GtkRcPropertyParser parser = (GtkRcPropertyParser) g_param_spec_get_qdata (pspec, quark_property_parser);
1345 1346

  g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1347
  if (_gtk_settings_parse_convert (parser, &qvalue->public.value,
1348
				   pspec, &tmp_value))
1349
    {
1350 1351 1352
      if (pspec->param_id == PROP_COLOR_SCHEME) 
        merge_color_scheme (data, &tmp_value, qvalue->source);

1353
      if (data->property_values[pspec->param_id - 1].source <= qvalue->source)
1354
	{
1355
          g_value_copy (&tmp_value, &data->property_values[pspec->param_id - 1].value);
1356
	  data->property_values[pspec->param_id - 1].source = qvalue->source;
1357
          g_object_notify (G_OBJECT (data), g_param_spec_get_name (pspec));
1358
	}
1359

1360
    }
1361 1362
  else
    {
1363
      gchar *debug = g_strdup_value_contents (&qvalue->public.value);
1364
      
jacob berkman's avatar
jacob berkman committed
1365
      g_message ("%s: failed to retrieve property `%s' of type `%s' from rc file value \"%s\" of type `%s'",
1366
		 qvalue->public.origin ? qvalue->public.origin : "(for origin information, set GTK_DEBUG)",
1367 1368 1369 1370 1371
		 pspec->name,
		 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
		 debug,
		 G_VALUE_TYPE_NAME (&tmp_value));
      g_free (debug);
1372
    }
1373
  g_value_unset (&tmp_value);
1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394
}

static guint
settings_install_property_parser (GtkSettingsClass   *class,
				  GParamSpec         *pspec,
				  GtkRcPropertyParser parser)
{
  GSList *node, *next;

  switch (G_TYPE_FUNDAMENTAL (G_PARAM_SPEC_VALUE_TYPE (pspec)))
    {
    case G_TYPE_BOOLEAN:
    case G_TYPE_UCHAR:
    case G_TYPE_CHAR:
    case G_TYPE_UINT:
    case G_TYPE_INT:
    case G_TYPE_ULONG:
    case G_TYPE_LONG:
    case G_TYPE_FLOAT:
    case G_TYPE_DOUBLE:
    case G_TYPE_STRING:
1395
    case G_TYPE_ENUM:
1396
      break;
1397 1398 1399 1400 1401 1402
    case G_TYPE_BOXED:
      if (strcmp (g_param_spec_get_name (pspec), "color-hash") == 0)
        {
          break;
        }
      /* fall through */
1403 1404
    default:
      if (!parser)
1405 1406 1407 1408 1409
        {
          g_warning (G_STRLOC ": parser needs to be specified for property \"%s\" of type `%s'",
                     pspec->name, g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
          return 0;
        }
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421
    }
  if (g_object_class_find_property (G_OBJECT_CLASS (class), pspec->name))
    {
      g_warning (G_STRLOC ": an rc-data property \"%s\" already exists",
		 pspec->name);
      return 0;
    }
  
  for (node = object_list; node; node = node->next)
    g_object_freeze_notify (node->data);

  g_object_class_install_property (G_OBJECT_CLASS (class), ++class_n_properties, pspec);
1422
  g_param_spec_set_qdata (pspec, quark_property_parser, (gpointer) parser);
1423 1424 1425 1426

  for (node = object_list; node; node = node->next)
    {
      GtkSettings *settings = node->data;
1427
      GtkSettingsValuePrivate *qvalue;
1428
      
1429 1430 1431 1432
      settings->property_values = g_renew (GtkSettingsPropertyValue, settings->property_values, class_n_properties);
      settings->property_values[class_n_properties - 1].value.g_type = 0;
      g_value_init (&settings->property_values[class_n_properties - 1].value, G_PARAM_SPEC_VALUE_TYPE (pspec));
      g_param_value_set_default (pspec, &settings->property_values[class_n_properties - 1].value);
1433
      settings->property_values[class_n_properties - 1].source = GTK_SETTINGS_SOURCE_DEFAULT;
1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449
      g_object_notify (G_OBJECT (settings), pspec->name);
      
      qvalue = g_datalist_get_data (&settings->queued_settings, pspec->name);
      if (qvalue)
	apply_queued_setting (settings, pspec, qvalue);
    }

  for (node = object_list; node; node = next)
    {
      next = node->next;
      g_object_thaw_notify (node->data);
    }

  return class_n_properties;
}

1450
GtkRcPropertyParser
1451
_gtk_rc_property_parser_from_type (GType type)
1452
{
1453
  if (type == GDK_TYPE_COLOR)
1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466
    return gtk_rc_property_parse_color;
  else if (type == GTK_TYPE_REQUISITION)
    return gtk_rc_property_parse_requisition;
  else if (type == GTK_TYPE_BORDER)
    return gtk_rc_property_parse_border;
  else if (G_TYPE_FUNDAMENTAL (type) == G_TYPE_ENUM && G_TYPE_IS_DERIVED (type))
    return gtk_rc_property_parse_enum;
  else if (G_TYPE_FUNDAMENTAL (type) == G_TYPE_FLAGS && G_TYPE_IS_DERIVED (type))
    return gtk_rc_property_parse_flags;
  else
    return NULL;
}

1467
void
Manish Singh's avatar
Manish Singh committed
1468
gtk_settings_install_property (GParamSpec *pspec)
1469
{
1470 1471
  static GtkSettingsClass *klass = NULL;

1472
  GtkRcPropertyParser parser;
1473

1474
  g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1475

1476 1477 1478
  if (! klass)
    klass = g_type_class_ref (GTK_TYPE_SETTINGS);

1479
  parser = _gtk_rc_property_parser_from_type (G_PARAM_SPEC_VALUE_TYPE (pspec));
1480

1481
  settings_install_property_parser (klass, pspec, parser);
1482 1483 1484
}

void
Manish Singh's avatar
Manish Singh committed
1485 1486
gtk_settings_install_property_parser (GParamSpec          *pspec,
				      GtkRcPropertyParser  parser)
1487
{
1488 1489
  static GtkSettingsClass *klass = NULL;

1490 1491
  g_return_if_fail (G_IS_PARAM_SPEC (pspec));
  g_return_if_fail (parser != NULL);
1492 1493 1494 1495 1496

  if (! klass)
    klass = g_type_class_ref (GTK_TYPE_SETTINGS);

  settings_install_property_parser (klass, pspec, parser);
1497 1498 1499 1500 1501
}

static void
free_value (gpointer data)
{
1502
  GtkSettingsValuePrivate *qvalue = data;
1503
  
1504 1505
  g_value_unset (&qvalue->public.value);
  g_free (qvalue->public.origin);
1506
  g_slice_free (GtkSettingsValuePrivate, qvalue);
1507 1508
}

1509 1510 1511 1512
static void
gtk_settings_set_property_value_internal (GtkSettings            *settings,
					  const gchar            *prop_name,
					  const GtkSettingsValue *new_value,
1513
					  GtkSettingsSource       source)
1514
{
1515
  GtkSettingsValuePrivate *qvalue;
1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529
  GParamSpec *pspec;
  gchar *name;
  GQuark name_quark;

  if (!G_VALUE_HOLDS_LONG (&new_value->value) &&
      !G_VALUE_HOLDS_DOUBLE (&new_value->value) &&
      !G_VALUE_HOLDS_STRING (&new_value->value) &&
      !G_VALUE_HOLDS (&new_value->value, G_TYPE_GSTRING))
    {
      g_warning (G_STRLOC ": value type invalid");
      return;
    }
  
  name = g_strdup (prop_name);
1530
  g_strcanon (name, G_CSET_DIGITS "-" G_CSET_a_2_z G_CSET_A_2_Z, '-');
1531 1532
  name_quark = g_quark_from_string (name);
  g_free (name);
1533 1534 1535 1536

  qvalue = g_datalist_id_get_data (&settings->queued_settings, name_quark);
  if (!qvalue)
    {
1537
      qvalue = g_slice_new0 (GtkSettingsValuePrivate);
1538 1539 1540 1541
      g_datalist_id_set_data_full (&settings->queued_settings, name_quark, qvalue, free_value);
    }
  else
    {
1542 1543
      g_free (qvalue->public.origin);
      g_value_unset (&qvalue->public.value);
1544
    }
1545 1546 1547
  qvalue->public.origin = g_strdup (new_value->origin);
  g_value_init (&qvalue->public.value, G_VALUE_TYPE (&new_value->value));
  g_value_copy (&new_value->value, &qvalue->public.value);
1548
  qvalue->source = source;