]> Pileus Git - ~andy/gtk/blob - gtk/gtksettings.c
Some initial docs
[~andy/gtk] / gtk / gtksettings.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2000 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19
20 #define PANGO_ENABLE_BACKEND /* for pango_fc_font_map_cache_clear() */
21
22 #include "config.h"
23
24 #include <string.h>
25
26 #include "gtksettings.h"
27
28 #include "gtkmodules.h"
29 #include "gtkmodulesprivate.h"
30 #include "gtksettingsprivate.h"
31 #include "gtkintl.h"
32 #include "gtkwidget.h"
33 #include "gtkprivate.h"
34 #include "gtkcssproviderprivate.h"
35 #include "gtksymboliccolor.h"
36 #include "gtktypebuiltins.h"
37 #include "gtkversion.h"
38
39 #ifdef GDK_WINDOWING_X11
40 #include "x11/gdkx.h"
41 #include <pango/pangofc-fontmap.h>
42 #endif
43
44 #ifdef GDK_WINDOWING_QUARTZ
45 #include "quartz/gdkquartz.h"
46 #endif
47
48 #undef GDK_DEPRECATED
49 #undef GDK_DEPRECATED_FOR
50 #define GDK_DEPRECATED
51 #define GDK_DEPRECATED_FOR(f)
52 #undef GTK_DISABLE_DEPRECATED
53
54 #include "deprecated/gtkrc.h"
55
56
57 /**
58  * SECTION:gtksettings
59  * @Short_description: Sharing settings between applications
60  * @Title: Settings
61  *
62  * GtkSettings provide a mechanism to share global settings between
63  * applications.
64  *
65  * On the X window system, this sharing is realized by an
66  * <ulink url="http://www.freedesktop.org/wiki/Specifications/xsettings-spec">XSettings</ulink>
67  * manager that is usually part of the desktop environment, along with
68  * utilities that let the user change these settings. In the absence of
69  * an Xsettings manager, GTK+ reads default values for settings from
70  * <filename>settings.ini</filename> files in
71  * <filename>/etc/gtk-3.0</filename> and <filename>$XDG_CONFIG_HOME/gtk-3.0</filename>. These files must be valid key files (see #GKeyFile), and have
72  * a section called Settings. Themes can also provide default values
73  * for settings by installing a <filename>settings.ini</filename> file
74  * next to their <filename>gtk.css</filename> file.
75  *
76  * Applications can override system-wide settings with
77  * gtk_settings_set_string_property(), gtk_settings_set_long_property(),
78  * etc. This should be restricted to special cases though; GtkSettings are
79  * not meant as an application configuration facility. When doing so, you
80  * need to be aware that settings that are specific to individual widgets
81  * may not be available before the widget type has been realized at least
82  * once. The following example demonstrates a way to do this:
83  * <informalexample><programlisting>
84  *   gtk_init (&argc, &argv);
85  *
86  *   /&ast; make sure the type is realized &ast;/
87  *   g_type_class_unref (g_type_class_ref (GTK_TYPE_IMAGE_MENU_ITEM));
88  *
89  *   g_object_set (gtk_settings_get_default (), "gtk-menu-images", FALSE, NULL);
90  * </programlisting></informalexample>
91  *
92  * There is one GtkSettings instance per screen. It can be obtained with
93  * gtk_settings_get_for_screen(), but in many cases, it is more convenient
94  * to use gtk_widget_get_settings(). gtk_settings_get_default() returns the
95  * GtkSettings instance for the default screen.
96  */
97
98
99 #define DEFAULT_TIMEOUT_INITIAL 200
100 #define DEFAULT_TIMEOUT_REPEAT   20
101 #define DEFAULT_TIMEOUT_EXPAND  500
102
103 typedef struct _GtkSettingsPropertyValue GtkSettingsPropertyValue;
104 typedef struct _GtkSettingsValuePrivate GtkSettingsValuePrivate;
105
106 struct _GtkSettingsPrivate
107 {
108   GData *queued_settings;      /* of type GtkSettingsValue* */
109   GtkSettingsPropertyValue *property_values;
110   GdkScreen *screen;
111   GtkCssProvider *theme_provider;
112   GtkCssProvider *key_theme_provider;
113 };
114
115 typedef enum
116 {
117   GTK_SETTINGS_SOURCE_DEFAULT,
118   GTK_SETTINGS_SOURCE_THEME,
119   GTK_SETTINGS_SOURCE_XSETTING,
120   GTK_SETTINGS_SOURCE_APPLICATION
121 } GtkSettingsSource;
122
123 struct _GtkSettingsValuePrivate
124 {
125   GtkSettingsValue public;
126   GtkSettingsSource source;
127 };
128
129 struct _GtkSettingsPropertyValue
130 {
131   GValue value;
132   GtkSettingsSource source;
133 };
134
135 enum {
136   PROP_0,
137   PROP_DOUBLE_CLICK_TIME,
138   PROP_DOUBLE_CLICK_DISTANCE,
139   PROP_CURSOR_BLINK,
140   PROP_CURSOR_BLINK_TIME,
141   PROP_CURSOR_BLINK_TIMEOUT,
142   PROP_SPLIT_CURSOR,
143   PROP_THEME_NAME,
144   PROP_ICON_THEME_NAME,
145   PROP_FALLBACK_ICON_THEME,
146   PROP_KEY_THEME_NAME,
147   PROP_MENU_BAR_ACCEL,
148   PROP_DND_DRAG_THRESHOLD,
149   PROP_FONT_NAME,
150   PROP_ICON_SIZES,
151   PROP_MODULES,
152   PROP_XFT_ANTIALIAS,
153   PROP_XFT_HINTING,
154   PROP_XFT_HINTSTYLE,
155   PROP_XFT_RGBA,
156   PROP_XFT_DPI,
157   PROP_CURSOR_THEME_NAME,
158   PROP_CURSOR_THEME_SIZE,
159   PROP_ALTERNATIVE_BUTTON_ORDER,
160   PROP_ALTERNATIVE_SORT_ARROWS,
161   PROP_SHOW_INPUT_METHOD_MENU,
162   PROP_SHOW_UNICODE_MENU,
163   PROP_TIMEOUT_INITIAL,
164   PROP_TIMEOUT_REPEAT,
165   PROP_TIMEOUT_EXPAND,
166   PROP_COLOR_SCHEME,
167   PROP_ENABLE_ANIMATIONS,
168   PROP_TOUCHSCREEN_MODE,
169   PROP_TOOLTIP_TIMEOUT,
170   PROP_TOOLTIP_BROWSE_TIMEOUT,
171   PROP_TOOLTIP_BROWSE_MODE_TIMEOUT,
172   PROP_KEYNAV_CURSOR_ONLY,
173   PROP_KEYNAV_WRAP_AROUND,
174   PROP_ERROR_BELL,
175   PROP_COLOR_HASH,
176   PROP_FILE_CHOOSER_BACKEND,
177   PROP_PRINT_BACKENDS,
178   PROP_PRINT_PREVIEW_COMMAND,
179   PROP_ENABLE_MNEMONICS,
180   PROP_ENABLE_ACCELS,
181   PROP_RECENT_FILES_LIMIT,
182   PROP_IM_MODULE,
183   PROP_RECENT_FILES_MAX_AGE,
184   PROP_FONTCONFIG_TIMESTAMP,
185   PROP_SOUND_THEME_NAME,
186   PROP_ENABLE_INPUT_FEEDBACK_SOUNDS,
187   PROP_ENABLE_EVENT_SOUNDS,
188   PROP_ENABLE_TOOLTIPS,
189   PROP_TOOLBAR_STYLE,
190   PROP_TOOLBAR_ICON_SIZE,
191   PROP_AUTO_MNEMONICS,
192   PROP_VISIBLE_FOCUS,
193   PROP_APPLICATION_PREFER_DARK_THEME,
194   PROP_BUTTON_IMAGES,
195   PROP_ENTRY_SELECT_ON_FOCUS,
196   PROP_ENTRY_PASSWORD_HINT_TIMEOUT,
197   PROP_MENU_IMAGES,
198   PROP_MENU_BAR_POPUP_DELAY,
199   PROP_SCROLLED_WINDOW_PLACEMENT,
200   PROP_CAN_CHANGE_ACCELS,
201   PROP_MENU_POPUP_DELAY,
202   PROP_MENU_POPDOWN_DELAY,
203   PROP_LABEL_SELECT_ON_FOCUS,
204   PROP_COLOR_PALETTE,
205   PROP_IM_PREEDIT_STYLE,
206   PROP_IM_STATUS_STYLE,
207   PROP_SHELL_SHOWS_APP_MENU
208 };
209
210 /* --- prototypes --- */
211 static void     gtk_settings_provider_iface_init (GtkStyleProviderIface *iface);
212
213 static void     gtk_settings_finalize            (GObject               *object);
214 static void     gtk_settings_get_property        (GObject               *object,
215                                                   guint                  property_id,
216                                                   GValue                *value,
217                                                   GParamSpec            *pspec);
218 static void     gtk_settings_set_property        (GObject               *object,
219                                                   guint                  property_id,
220                                                   const GValue          *value,
221                                                   GParamSpec            *pspec);
222 static void     gtk_settings_notify              (GObject               *object,
223                                                   GParamSpec            *pspec);
224 static guint    settings_install_property_parser (GtkSettingsClass      *class,
225                                                   GParamSpec            *pspec,
226                                                   GtkRcPropertyParser    parser);
227 static void    settings_update_double_click      (GtkSettings           *settings);
228 static void    settings_update_modules           (GtkSettings           *settings);
229
230 static void    settings_update_cursor_theme      (GtkSettings           *settings);
231 static void    settings_update_resolution        (GtkSettings           *settings);
232 static void    settings_update_font_options      (GtkSettings           *settings);
233 static gboolean settings_update_fontconfig       (GtkSettings           *settings);
234 static void    settings_update_color_scheme      (GtkSettings *settings);
235 static void    settings_update_theme             (GtkSettings *settings);
236 static void    settings_update_key_theme         (GtkSettings *settings);
237
238 static void    merge_color_scheme                (GtkSettings           *settings,
239                                                   const GValue          *value,
240                                                   GtkSettingsSource      source);
241 static gchar  *get_color_scheme                  (GtkSettings           *settings);
242 static GHashTable *get_color_hash                (GtkSettings           *settings);
243 static void gtk_settings_load_from_key_file      (GtkSettings           *settings,
244                                                   const gchar           *path,
245                                                   GtkSettingsSource      source);
246
247 /* the default palette for GtkColorSelelection */
248 static const gchar default_color_palette[] =
249   "black:white:gray50:red:purple:blue:light blue:green:yellow:orange:"
250   "lavender:brown:goldenrod4:dodger blue:pink:light green:gray10:gray30:gray75:gray90";
251
252 /* --- variables --- */
253 static GQuark            quark_property_parser = 0;
254 static GSList           *object_list = NULL;
255 static guint             class_n_properties = 0;
256
257
258 G_DEFINE_TYPE_EXTENDED (GtkSettings, gtk_settings, G_TYPE_OBJECT, 0,
259                         G_IMPLEMENT_INTERFACE (GTK_TYPE_STYLE_PROVIDER,
260                                                gtk_settings_provider_iface_init));
261
262 /* --- functions --- */
263 static void
264 gtk_settings_init (GtkSettings *settings)
265 {
266   GtkSettingsPrivate *priv;
267   GParamSpec **pspecs, **p;
268   guint i = 0;
269   gchar *path;
270
271   priv = G_TYPE_INSTANCE_GET_PRIVATE (settings,
272                                       GTK_TYPE_SETTINGS,
273                                       GtkSettingsPrivate);
274
275   settings->priv = priv;
276   g_datalist_init (&priv->queued_settings);
277   object_list = g_slist_prepend (object_list, settings);
278
279   /* build up property array for all yet existing properties and queue
280    * notification for them (at least notification for internal properties
281    * will instantly be caught)
282    */
283   pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (settings), NULL);
284   for (p = pspecs; *p; p++)
285     if ((*p)->owner_type == G_OBJECT_TYPE (settings))
286       i++;
287   priv->property_values = g_new0 (GtkSettingsPropertyValue, i);
288   i = 0;
289   g_object_freeze_notify (G_OBJECT (settings));
290
291   for (p = pspecs; *p; p++)
292     {
293       GParamSpec *pspec = *p;
294       GType value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
295
296       if (pspec->owner_type != G_OBJECT_TYPE (settings))
297         continue;
298       g_value_init (&priv->property_values[i].value, value_type);
299       g_param_value_set_default (pspec, &priv->property_values[i].value);
300
301       g_object_notify (G_OBJECT (settings), pspec->name);
302       priv->property_values[i].source = GTK_SETTINGS_SOURCE_DEFAULT;
303       i++;
304     }
305   g_free (pspecs);
306
307   path = g_build_filename (_gtk_get_sysconfdir (), "gtk-3.0", "settings.ini", NULL);
308   if (g_file_test (path, G_FILE_TEST_EXISTS))
309     gtk_settings_load_from_key_file (settings, path, GTK_SETTINGS_SOURCE_DEFAULT);
310   g_free (path);
311
312   path = g_build_filename (g_get_user_config_dir (), "gtk-3.0", "settings.ini", NULL);
313   if (g_file_test (path, G_FILE_TEST_EXISTS))
314     gtk_settings_load_from_key_file (settings, path, GTK_SETTINGS_SOURCE_DEFAULT);
315   g_free (path);
316
317   g_object_thaw_notify (G_OBJECT (settings));
318 }
319
320 static void
321 gtk_settings_class_init (GtkSettingsClass *class)
322 {
323   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
324   guint result;
325
326   gobject_class->finalize = gtk_settings_finalize;
327   gobject_class->get_property = gtk_settings_get_property;
328   gobject_class->set_property = gtk_settings_set_property;
329   gobject_class->notify = gtk_settings_notify;
330
331   quark_property_parser = g_quark_from_static_string ("gtk-rc-property-parser");
332   result = settings_install_property_parser (class,
333                                              g_param_spec_int ("gtk-double-click-time",
334                                                                P_("Double Click Time"),
335                                                                P_("Maximum time allowed between two clicks for them to be considered a double click (in milliseconds)"),
336                                                                0, G_MAXINT, 250,
337                                                                GTK_PARAM_READWRITE),
338                                              NULL);
339   g_assert (result == PROP_DOUBLE_CLICK_TIME);
340   result = settings_install_property_parser (class,
341                                              g_param_spec_int ("gtk-double-click-distance",
342                                                                P_("Double Click Distance"),
343                                                                P_("Maximum distance allowed between two clicks for them to be considered a double click (in pixels)"),
344                                                                0, G_MAXINT, 5,
345                                                                GTK_PARAM_READWRITE),
346                                              NULL);
347   g_assert (result == PROP_DOUBLE_CLICK_DISTANCE);
348
349   /**
350    * GtkSettings:gtk-cursor-blink:
351    *
352    * Whether the cursor should blink.
353    *
354    * Also see the #GtkSettings:gtk-cursor-blink-timeout setting,
355    * which allows more flexible control over cursor blinking.
356    */
357   result = settings_install_property_parser (class,
358                                              g_param_spec_boolean ("gtk-cursor-blink",
359                                                                    P_("Cursor Blink"),
360                                                                    P_("Whether the cursor should blink"),
361                                                                    TRUE,
362                                                                    GTK_PARAM_READWRITE),
363                                              NULL);
364   g_assert (result == PROP_CURSOR_BLINK);
365   result = settings_install_property_parser (class,
366                                              g_param_spec_int ("gtk-cursor-blink-time",
367                                                                P_("Cursor Blink Time"),
368                                                                P_("Length of the cursor blink cycle, in milliseconds"),
369                                                                100, G_MAXINT, 1200,
370                                                                GTK_PARAM_READWRITE),
371                                              NULL);
372   g_assert (result == PROP_CURSOR_BLINK_TIME);
373
374   /**
375    * GtkSettings:gtk-cursor-blink-timeout:
376    *
377    * Time after which the cursor stops blinking, in seconds.
378    * The timer is reset after each user interaction.
379    *
380    * Setting this to zero has the same effect as setting
381    * #GtkSettings:gtk-cursor-blink to %FALSE.
382    *
383    * Since: 2.12
384    */
385   result = settings_install_property_parser (class,
386                                              g_param_spec_int ("gtk-cursor-blink-timeout",
387                                                                P_("Cursor Blink Timeout"),
388                                                                P_("Time after which the cursor stops blinking, in seconds"),
389                                                                1, G_MAXINT, G_MAXINT,
390                                                                GTK_PARAM_READWRITE),
391                                              NULL);
392   g_assert (result == PROP_CURSOR_BLINK_TIMEOUT);
393   result = settings_install_property_parser (class,
394                                              g_param_spec_boolean ("gtk-split-cursor",
395                                                                    P_("Split Cursor"),
396                                                                    P_("Whether two cursors should be displayed for mixed left-to-right and right-to-left text"),
397                                                                    TRUE,
398                                                                    GTK_PARAM_READWRITE),
399                                              NULL);
400   g_assert (result == PROP_SPLIT_CURSOR);
401   result = settings_install_property_parser (class,
402                                              g_param_spec_string ("gtk-theme-name",
403                                                                    P_("Theme Name"),
404                                                                    P_("Name of theme to load"),
405 #ifdef G_OS_WIN32
406                                                                   "gtk-win32",
407 #else
408                                                                   "Raleigh",
409 #endif
410                                                                   GTK_PARAM_READWRITE),
411                                              NULL);
412   g_assert (result == PROP_THEME_NAME);
413
414   result = settings_install_property_parser (class,
415                                              g_param_spec_string ("gtk-icon-theme-name",
416                                                                   P_("Icon Theme Name"),
417                                                                   P_("Name of icon theme to use"),
418                                                                   "hicolor",
419                                                                   GTK_PARAM_READWRITE),
420                                              NULL);
421   g_assert (result == PROP_ICON_THEME_NAME);
422
423   result = settings_install_property_parser (class,
424                                              g_param_spec_string ("gtk-fallback-icon-theme",
425                                                                   P_("Fallback Icon Theme Name"),
426                                                                   P_("Name of a icon theme to fall back to"),
427                                                                   NULL,
428                                                                   GTK_PARAM_READWRITE),
429                                              NULL);
430   g_assert (result == PROP_FALLBACK_ICON_THEME);
431
432   result = settings_install_property_parser (class,
433                                              g_param_spec_string ("gtk-key-theme-name",
434                                                                   P_("Key Theme Name"),
435                                                                   P_("Name of key theme to load"),
436                                                                   NULL,
437                                                                   GTK_PARAM_READWRITE),
438                                              NULL);
439   g_assert (result == PROP_KEY_THEME_NAME);
440
441   result = settings_install_property_parser (class,
442                                              g_param_spec_string ("gtk-menu-bar-accel",
443                                                                   P_("Menu bar accelerator"),
444                                                                   P_("Keybinding to activate the menu bar"),
445                                                                   "F10",
446                                                                   GTK_PARAM_READWRITE),
447                                              NULL);
448   g_assert (result == PROP_MENU_BAR_ACCEL);
449
450   result = settings_install_property_parser (class,
451                                              g_param_spec_int ("gtk-dnd-drag-threshold",
452                                                                P_("Drag threshold"),
453                                                                P_("Number of pixels the cursor can move before dragging"),
454                                                                1, G_MAXINT, 8,
455                                                                GTK_PARAM_READWRITE),
456                                              NULL);
457   g_assert (result == PROP_DND_DRAG_THRESHOLD);
458
459   result = settings_install_property_parser (class,
460                                              g_param_spec_string ("gtk-font-name",
461                                                                    P_("Font Name"),
462                                                                    P_("Name of default font to use"),
463                                                                   "Sans 10",
464                                                                   GTK_PARAM_READWRITE),
465                                              NULL);
466   g_assert (result == PROP_FONT_NAME);
467
468   /**
469    * GtkSettings:gtk-icon-sizes:
470    *
471    * A list of icon sizes. The list is separated by colons, and
472    * item has the form:
473    *
474    * <replaceable>size-name</replaceable> = <replaceable>width</replaceable> , <replaceable>height</replaceable>
475    *
476    * E.g. "gtk-menu=16,16:gtk-button=20,20:gtk-dialog=48,48".
477    * GTK+ itself use the following named icon sizes: gtk-menu,
478    * gtk-button, gtk-small-toolbar, gtk-large-toolbar, gtk-dnd,
479    * gtk-dialog. Applications can register their own named icon
480    * sizes with gtk_icon_size_register().
481    */
482   result = settings_install_property_parser (class,
483                                              g_param_spec_string ("gtk-icon-sizes",
484                                                                    P_("Icon Sizes"),
485                                                                    P_("List of icon sizes (gtk-menu=16,16:gtk-button=20,20..."),
486                                                                   NULL,
487                                                                   GTK_PARAM_READWRITE),
488                                              NULL);
489   g_assert (result == PROP_ICON_SIZES);
490
491   result = settings_install_property_parser (class,
492                                              g_param_spec_string ("gtk-modules",
493                                                                   P_("GTK Modules"),
494                                                                   P_("List of currently active GTK modules"),
495                                                                   NULL,
496                                                                   GTK_PARAM_READWRITE),
497                                              NULL);
498   g_assert (result == PROP_MODULES);
499
500   result = settings_install_property_parser (class,
501                                              g_param_spec_int ("gtk-xft-antialias",
502                                                                P_("Xft Antialias"),
503                                                                P_("Whether to antialias Xft fonts; 0=no, 1=yes, -1=default"),
504                                                                -1, 1, -1,
505                                                                GTK_PARAM_READWRITE),
506                                              NULL);
507
508   g_assert (result == PROP_XFT_ANTIALIAS);
509
510   result = settings_install_property_parser (class,
511                                              g_param_spec_int ("gtk-xft-hinting",
512                                                                P_("Xft Hinting"),
513                                                                P_("Whether to hint Xft fonts; 0=no, 1=yes, -1=default"),
514                                                                -1, 1, -1,
515                                                                GTK_PARAM_READWRITE),
516                                              NULL);
517
518   g_assert (result == PROP_XFT_HINTING);
519
520   result = settings_install_property_parser (class,
521                                              g_param_spec_string ("gtk-xft-hintstyle",
522                                                                   P_("Xft Hint Style"),
523                                                                   P_("What degree of hinting to use; hintnone, hintslight, hintmedium, or hintfull"),
524                                                                   NULL,
525                                                                   GTK_PARAM_READWRITE),
526                                               NULL);
527
528   g_assert (result == PROP_XFT_HINTSTYLE);
529
530   result = settings_install_property_parser (class,
531                                              g_param_spec_string ("gtk-xft-rgba",
532                                                                   P_("Xft RGBA"),
533                                                                   P_("Type of subpixel antialiasing; none, rgb, bgr, vrgb, vbgr"),
534                                                                   NULL,
535                                                                   GTK_PARAM_READWRITE),
536                                              NULL);
537
538   g_assert (result == PROP_XFT_RGBA);
539
540   result = settings_install_property_parser (class,
541                                              g_param_spec_int ("gtk-xft-dpi",
542                                                                P_("Xft DPI"),
543                                                                P_("Resolution for Xft, in 1024 * dots/inch. -1 to use default value"),
544                                                                -1, 1024*1024, -1,
545                                                                GTK_PARAM_READWRITE),
546                                              NULL);
547
548   g_assert (result == PROP_XFT_DPI);
549
550   result = settings_install_property_parser (class,
551                                              g_param_spec_string ("gtk-cursor-theme-name",
552                                                                   P_("Cursor theme name"),
553                                                                   P_("Name of the cursor theme to use, or NULL to use the default theme"),
554                                                                   NULL,
555                                                                   GTK_PARAM_READWRITE),
556                                              NULL);
557   g_assert (result == PROP_CURSOR_THEME_NAME);
558
559   result = settings_install_property_parser (class,
560                                              g_param_spec_int ("gtk-cursor-theme-size",
561                                                                P_("Cursor theme size"),
562                                                                P_("Size to use for cursors, or 0 to use the default size"),
563                                                                0, 128, 0,
564                                                                GTK_PARAM_READWRITE),
565                                              NULL);
566
567   g_assert (result == PROP_CURSOR_THEME_SIZE);
568
569   result = settings_install_property_parser (class,
570                                              g_param_spec_boolean ("gtk-alternative-button-order",
571                                                                    P_("Alternative button order"),
572                                                                    P_("Whether buttons in dialogs should use the alternative button order"),
573                                                                    FALSE,
574                                                                    GTK_PARAM_READWRITE),
575                                              NULL);
576   g_assert (result == PROP_ALTERNATIVE_BUTTON_ORDER);
577
578   /**
579    * GtkSettings:gtk-alternative-sort-arrows:
580    *
581    * Controls the direction of the sort indicators in sorted list and tree
582    * views. By default an arrow pointing down means the column is sorted
583    * in ascending order. When set to %TRUE, this order will be inverted.
584    *
585    * Since: 2.12
586    */
587   result = settings_install_property_parser (class,
588                                              g_param_spec_boolean ("gtk-alternative-sort-arrows",
589                                                                    P_("Alternative sort indicator direction"),
590                                                                    P_("Whether the direction of the sort indicators in list and tree views is inverted compared to the default (where down means ascending)"),
591                                                                    FALSE,
592                                                                    GTK_PARAM_READWRITE),
593                                              NULL);
594   g_assert (result == PROP_ALTERNATIVE_SORT_ARROWS);
595
596   result = settings_install_property_parser (class,
597                                              g_param_spec_boolean ("gtk-show-input-method-menu",
598                                                                    P_("Show the 'Input Methods' menu"),
599                                                                    P_("Whether the context menus of entries and text views should offer to change the input method"),
600                                                                    TRUE,
601                                                                    GTK_PARAM_READWRITE),
602                                              NULL);
603   g_assert (result == PROP_SHOW_INPUT_METHOD_MENU);
604
605   result = settings_install_property_parser (class,
606                                              g_param_spec_boolean ("gtk-show-unicode-menu",
607                                                                    P_("Show the 'Insert Unicode Control Character' menu"),
608                                                                    P_("Whether the context menus of entries and text views should offer to insert control characters"),
609                                                                    TRUE,
610                                                                    GTK_PARAM_READWRITE),
611                                              NULL);
612   g_assert (result == PROP_SHOW_UNICODE_MENU);
613
614   result = settings_install_property_parser (class,
615                                              g_param_spec_int ("gtk-timeout-initial",
616                                                                P_("Start timeout"),
617                                                                P_("Starting value for timeouts, when button is pressed"),
618                                                                0, G_MAXINT, DEFAULT_TIMEOUT_INITIAL,
619                                                                GTK_PARAM_READWRITE),
620                                              NULL);
621
622   g_assert (result == PROP_TIMEOUT_INITIAL);
623
624   result = settings_install_property_parser (class,
625                                              g_param_spec_int ("gtk-timeout-repeat",
626                                                                P_("Repeat timeout"),
627                                                                P_("Repeat value for timeouts, when button is pressed"),
628                                                                0, G_MAXINT, DEFAULT_TIMEOUT_REPEAT,
629                                                                GTK_PARAM_READWRITE),
630                                              NULL);
631
632   g_assert (result == PROP_TIMEOUT_REPEAT);
633
634   result = settings_install_property_parser (class,
635                                              g_param_spec_int ("gtk-timeout-expand",
636                                                                P_("Expand timeout"),
637                                                                P_("Expand value for timeouts, when a widget is expanding a new region"),
638                                                                0, G_MAXINT, DEFAULT_TIMEOUT_EXPAND,
639                                                                GTK_PARAM_READWRITE),
640                                              NULL);
641
642   g_assert (result == PROP_TIMEOUT_EXPAND);
643
644   /**
645    * GtkSettings:gtk-color-scheme:
646    *
647    * A palette of named colors for use in themes. The format of the string is
648    * <programlisting>
649    * name1: color1
650    * name2: color2
651    * ...
652    * </programlisting>
653    * Color names must be acceptable as identifiers in the
654    * <link linkend="gtk-Resource-Files">gtkrc</link> syntax, and
655    * color specifications must be in the format accepted by
656    * gdk_color_parse().
657    *
658    * Note that due to the way the color tables from different sources are
659    * merged, color specifications will be converted to hexadecimal form
660    * when getting this property.
661    *
662    * Starting with GTK+ 2.12, the entries can alternatively be separated
663    * by ';' instead of newlines:
664    * <programlisting>
665    * name1: color1; name2: color2; ...
666    * </programlisting>
667    *
668    * Since: 2.10
669    */
670   result = settings_install_property_parser (class,
671                                              g_param_spec_string ("gtk-color-scheme",
672                                                                   P_("Color scheme"),
673                                                                   P_("A palette of named colors for use in themes"),
674                                                                   "",
675                                                                   GTK_PARAM_READWRITE),
676                                              NULL);
677
678   g_assert (result == PROP_COLOR_SCHEME);
679
680   result = settings_install_property_parser (class,
681                                              g_param_spec_boolean ("gtk-enable-animations",
682                                                                    P_("Enable Animations"),
683                                                                    P_("Whether to enable toolkit-wide animations."),
684                                                                    TRUE,
685                                                                    GTK_PARAM_READWRITE),
686                                              NULL);
687
688   g_assert (result == PROP_ENABLE_ANIMATIONS);
689
690   /**
691    * GtkSettings:gtk-touchscreen-mode:
692    *
693    * When %TRUE, there are no motion notify events delivered on this screen,
694    * and widgets can't use the pointer hovering them for any essential
695    * functionality.
696    *
697    * Since: 2.10
698    */
699   result = settings_install_property_parser (class,
700                                              g_param_spec_boolean ("gtk-touchscreen-mode",
701                                                                    P_("Enable Touchscreen Mode"),
702                                                                    P_("When TRUE, there are no motion notify events delivered on this screen"),
703                                                                    FALSE,
704                                                                    GTK_PARAM_READWRITE),
705                                              NULL);
706
707   g_assert (result == PROP_TOUCHSCREEN_MODE);
708
709   /**
710    * GtkSettings:gtk-tooltip-timeout:
711    *
712    * Time, in milliseconds, after which a tooltip could appear if the
713    * cursor is hovering on top of a widget.
714    *
715    * Since: 2.12
716    */
717   result = settings_install_property_parser (class,
718                                              g_param_spec_int ("gtk-tooltip-timeout",
719                                                                P_("Tooltip timeout"),
720                                                                P_("Timeout before tooltip is shown"),
721                                                                0, G_MAXINT,
722                                                                500,
723                                                                GTK_PARAM_READWRITE),
724                                              NULL);
725
726   g_assert (result == PROP_TOOLTIP_TIMEOUT);
727
728   /**
729    * GtkSettings:gtk-tooltip-browse-timeout:
730    *
731    * Controls the time after which tooltips will appear when
732    * browse mode is enabled, in milliseconds.
733    *
734    * Browse mode is enabled when the mouse pointer moves off an object
735    * where a tooltip was currently being displayed. If the mouse pointer
736    * hits another object before the browse mode timeout expires (see
737    * #GtkSettings:gtk-tooltip-browse-mode-timeout), it will take the
738    * amount of milliseconds specified by this setting to popup the tooltip
739    * for the new object.
740    *
741    * Since: 2.12
742    */
743   result = settings_install_property_parser (class,
744                                              g_param_spec_int ("gtk-tooltip-browse-timeout",
745                                                                P_("Tooltip browse timeout"),
746                                                                P_("Timeout before tooltip is shown when browse mode is enabled"),
747                                                                0, G_MAXINT,
748                                                                60,
749                                                                GTK_PARAM_READWRITE),
750                                              NULL);
751
752   g_assert (result == PROP_TOOLTIP_BROWSE_TIMEOUT);
753
754   /**
755    * GtkSettings:gtk-tooltip-browse-mode-timeout:
756    *
757    * Amount of time, in milliseconds, after which the browse mode
758    * will be disabled.
759    *
760    * See #GtkSettings:gtk-tooltip-browse-timeout for more information
761    * about browse mode.
762    *
763    * Since: 2.12
764    */
765   result = settings_install_property_parser (class,
766                                              g_param_spec_int ("gtk-tooltip-browse-mode-timeout",
767                                                                P_("Tooltip browse mode timeout"),
768                                                                P_("Timeout after which browse mode is disabled"),
769                                                                0, G_MAXINT,
770                                                                500,
771                                                                GTK_PARAM_READWRITE),
772                                              NULL);
773
774   g_assert (result == PROP_TOOLTIP_BROWSE_MODE_TIMEOUT);
775
776   /**
777    * GtkSettings:gtk-keynav-cursor-only:
778    *
779    * When %TRUE, keyboard navigation should be able to reach all widgets
780    * by using the cursor keys only. Tab, Shift etc. keys can't be expected
781    * to be present on the used input device.
782    *
783    * Since: 2.12
784    */
785   result = settings_install_property_parser (class,
786                                              g_param_spec_boolean ("gtk-keynav-cursor-only",
787                                                                    P_("Keynav Cursor Only"),
788                                                                    P_("When TRUE, there are only cursor keys available to navigate widgets"),
789                                                                    FALSE,
790                                                                    GTK_PARAM_READWRITE),
791                                              NULL);
792
793   g_assert (result == PROP_KEYNAV_CURSOR_ONLY);
794
795   /**
796    * GtkSettings:gtk-keynav-wrap-around:
797    *
798    * When %TRUE, some widgets will wrap around when doing keyboard
799    * navigation, such as menus, menubars and notebooks.
800    *
801    * Since: 2.12
802    */
803   result = settings_install_property_parser (class,
804                                              g_param_spec_boolean ("gtk-keynav-wrap-around",
805                                                                    P_("Keynav Wrap Around"),
806                                                                    P_("Whether to wrap around when keyboard-navigating widgets"),
807                                                                    TRUE,
808                                                                    GTK_PARAM_READWRITE),
809                                              NULL);
810
811   g_assert (result == PROP_KEYNAV_WRAP_AROUND);
812
813   /**
814    * GtkSettings:gtk-error-bell:
815    *
816    * When %TRUE, keyboard navigation and other input-related errors
817    * will cause a beep. Since the error bell is implemented using
818    * gdk_window_beep(), the windowing system may offer ways to
819    * configure the error bell in many ways, such as flashing the
820    * window or similar visual effects.
821    *
822    * Since: 2.12
823    */
824   result = settings_install_property_parser (class,
825                                              g_param_spec_boolean ("gtk-error-bell",
826                                                                    P_("Error Bell"),
827                                                                    P_("When TRUE, keyboard navigation and other errors will cause a beep"),
828                                                                    TRUE,
829                                                                    GTK_PARAM_READWRITE),
830                                              NULL);
831
832   g_assert (result == PROP_ERROR_BELL);
833
834   /**
835    * GtkSettings:color-hash:
836    *
837    * Holds a hash table representation of the #GtkSettings:gtk-color-scheme
838    * setting, mapping color names to #GdkColor<!-- -->s.
839    *
840    * Since: 2.10
841    */
842   result = settings_install_property_parser (class,
843                                              g_param_spec_boxed ("color-hash",
844                                                                  P_("Color Hash"),
845                                                                  P_("A hash table representation of the color scheme."),
846                                                                  G_TYPE_HASH_TABLE,
847                                                                  GTK_PARAM_READABLE),
848                                              NULL);
849   g_assert (result == PROP_COLOR_HASH);
850
851   result = settings_install_property_parser (class,
852                                              g_param_spec_string ("gtk-file-chooser-backend",
853                                                                   P_("Default file chooser backend"),
854                                                                   P_("Name of the GtkFileChooser backend to use by default"),
855                                                                   NULL,
856                                                                   GTK_PARAM_READWRITE),
857                                              NULL);
858   g_assert (result == PROP_FILE_CHOOSER_BACKEND);
859
860   /**
861    * GtkSettings:gtk-print-backends:
862    *
863    * A comma-separated list of print backends to use in the print
864    * dialog. Available print backends depend on the GTK+ installation,
865    * and may include "file", "cups", "lpr" or "papi".
866    *
867    * Since: 2.10
868    */
869   result = settings_install_property_parser (class,
870                                              g_param_spec_string ("gtk-print-backends",
871                                                                   P_("Default print backend"),
872                                                                   P_("List of the GtkPrintBackend backends to use by default"),
873                                                                   GTK_PRINT_BACKENDS,
874                                                                   GTK_PARAM_READWRITE),
875                                              NULL);
876   g_assert (result == PROP_PRINT_BACKENDS);
877
878   /**
879    * GtkSettings:gtk-print-preview-command:
880    *
881    * A command to run for displaying the print preview. The command
882    * should contain a %f placeholder, which will get replaced by
883    * the path to the pdf file. The command may also contain a %s
884    * placeholder, which will get replaced by the path to a file
885    * containing the print settings in the format produced by
886    * gtk_print_settings_to_file().
887    *
888    * The preview application is responsible for removing the pdf file
889    * and the print settings file when it is done.
890    *
891    * Since: 2.10
892    */
893   result = settings_install_property_parser (class,
894                                              g_param_spec_string ("gtk-print-preview-command",
895                                                                   P_("Default command to run when displaying a print preview"),
896                                                                   P_("Command to run when displaying a print preview"),
897                                                                   GTK_PRINT_PREVIEW_COMMAND,
898                                                                   GTK_PARAM_READWRITE),
899                                              NULL);
900   g_assert (result == PROP_PRINT_PREVIEW_COMMAND);
901
902   /**
903    * GtkSettings:gtk-enable-mnemonics:
904    *
905    * Whether labels and menu items should have visible mnemonics which
906    * can be activated.
907    *
908    * Since: 2.12
909    */
910   result = settings_install_property_parser (class,
911                                              g_param_spec_boolean ("gtk-enable-mnemonics",
912                                                                    P_("Enable Mnemonics"),
913                                                                    P_("Whether labels should have mnemonics"),
914                                                                    TRUE,
915                                                                    GTK_PARAM_READWRITE),
916                                              NULL);
917   g_assert (result == PROP_ENABLE_MNEMONICS);
918
919   /**
920    * GtkSettings:gtk-enable-accels:
921    *
922    * Whether menu items should have visible accelerators which can be
923    * activated.
924    *
925    * Since: 2.12
926    */
927   result = settings_install_property_parser (class,
928                                              g_param_spec_boolean ("gtk-enable-accels",
929                                                                    P_("Enable Accelerators"),
930                                                                    P_("Whether menu items should have accelerators"),
931                                                                    TRUE,
932                                                                    GTK_PARAM_READWRITE),
933                                              NULL);
934   g_assert (result == PROP_ENABLE_ACCELS);
935
936   /**
937    * GtkSettings:gtk-recent-files-limit:
938    *
939    * The number of recently used files that should be displayed by default by
940    * #GtkRecentChooser implementations and by the #GtkFileChooser. A value of
941    * -1 means every recently used file stored.
942    *
943    * Since: 2.12
944    */
945   result = settings_install_property_parser (class,
946                                              g_param_spec_int ("gtk-recent-files-limit",
947                                                                P_("Recent Files Limit"),
948                                                                P_("Number of recently used files"),
949                                                                -1, G_MAXINT,
950                                                                50,
951                                                                GTK_PARAM_READWRITE),
952                                              NULL);
953   g_assert (result == PROP_RECENT_FILES_LIMIT);
954
955   /**
956    * GtkSettings:gtk-im-module:
957    *
958    * Which IM (input method) module should be used by default. This is the
959    * input method that will be used if the user has not explicitly chosen
960    * another input method from the IM context menu.
961    * This also can be a colon-separated list of input methods, which GTK+
962    * will try in turn until it finds one available on the system.
963    *
964    * See #GtkIMContext and see the #GtkSettings:gtk-show-input-method-menu property.
965    */
966   result = settings_install_property_parser (class,
967                                              g_param_spec_string ("gtk-im-module",
968                                                                   P_("Default IM module"),
969                                                                   P_("Which IM module should be used by default"),
970                                                                   NULL,
971                                                                   GTK_PARAM_READWRITE),
972                                              NULL);
973   g_assert (result == PROP_IM_MODULE);
974
975   /**
976    * GtkSettings:gtk-recent-files-max-age:
977    *
978    * The maximum age, in days, of the items inside the recently used
979    * resources list. Items older than this setting will be excised
980    * from the list. If set to 0, the list will always be empty; if
981    * set to -1, no item will be removed.
982    *
983    * Since: 2.14
984    */
985   result = settings_install_property_parser (class,
986                                              g_param_spec_int ("gtk-recent-files-max-age",
987                                                                P_("Recent Files Max Age"),
988                                                                P_("Maximum age of recently used files, in days"),
989                                                                -1, G_MAXINT,
990                                                                30,
991                                                                GTK_PARAM_READWRITE),
992                                              NULL);
993   g_assert (result == PROP_RECENT_FILES_MAX_AGE);
994
995   result = settings_install_property_parser (class,
996                                              g_param_spec_uint ("gtk-fontconfig-timestamp",
997                                                                 P_("Fontconfig configuration timestamp"),
998                                                                 P_("Timestamp of current fontconfig configuration"),
999                                                                 0, G_MAXUINT, 0,
1000                                                                 GTK_PARAM_READWRITE),
1001                                              NULL);
1002
1003   g_assert (result == PROP_FONTCONFIG_TIMESTAMP);
1004
1005   /**
1006    * GtkSettings:gtk-sound-theme-name:
1007    *
1008    * The XDG sound theme to use for event sounds.
1009    *
1010    * See the <ulink url="http://www.freedesktop.org/wiki/Specifications/sound-theme-spec">Sound Theme spec</ulink>
1011    * for more information on event sounds and sound themes.
1012    *
1013    * GTK+ itself does not support event sounds, you have to use a loadable
1014    * module like the one that comes with libcanberra.
1015    *
1016    * Since: 2.14
1017    */
1018   result = settings_install_property_parser (class,
1019                                              g_param_spec_string ("gtk-sound-theme-name",
1020                                                                   P_("Sound Theme Name"),
1021                                                                   P_("XDG sound theme name"),
1022                                                                   "freedesktop",
1023                                                                   GTK_PARAM_READWRITE),
1024                                              NULL);
1025   g_assert (result == PROP_SOUND_THEME_NAME);
1026
1027   /**
1028    * GtkSettings:gtk-enable-input-feedback-sounds:
1029    *
1030    * Whether to play event sounds as feedback to user input.
1031    *
1032    * See the <ulink url="http://www.freedesktop.org/wiki/Specifications/sound-theme-spec">Sound Theme spec</ulink>
1033    * for more information on event sounds and sound themes.
1034    *
1035    * GTK+ itself does not support event sounds, you have to use a loadable
1036    * module like the one that comes with libcanberra.
1037    *
1038    * Since: 2.14
1039    */
1040   result = settings_install_property_parser (class,
1041                                              g_param_spec_boolean ("gtk-enable-input-feedback-sounds",
1042                                                                    /* Translators: this means sounds that are played as feedback to user input */
1043                                                                    P_("Audible Input Feedback"),
1044                                                                    P_("Whether to play event sounds as feedback to user input"),
1045                                                                    TRUE,
1046                                                                    GTK_PARAM_READWRITE),
1047                                              NULL);
1048   g_assert (result == PROP_ENABLE_INPUT_FEEDBACK_SOUNDS);
1049
1050   /**
1051    * GtkSettings:gtk-enable-event-sounds:
1052    *
1053    * Whether to play any event sounds at all.
1054    *
1055    * See the <ulink url="http://www.freedesktop.org/wiki/Specifications/sound-theme-spec">Sound Theme spec</ulink>
1056    * for more information on event sounds and sound themes.
1057    *
1058    * GTK+ itself does not support event sounds, you have to use a loadable
1059    * module like the one that comes with libcanberra.
1060    *
1061    * Since: 2.14
1062    */
1063   result = settings_install_property_parser (class,
1064                                              g_param_spec_boolean ("gtk-enable-event-sounds",
1065                                                                    P_("Enable Event Sounds"),
1066                                                                    P_("Whether to play any event sounds at all"),
1067                                                                    TRUE,
1068                                                                    GTK_PARAM_READWRITE),
1069                                              NULL);
1070   g_assert (result == PROP_ENABLE_EVENT_SOUNDS);
1071
1072   /**
1073    * GtkSettings:gtk-enable-tooltips:
1074    *
1075    * Whether tooltips should be shown on widgets.
1076    *
1077    * Since: 2.14
1078    */
1079   result = settings_install_property_parser (class,
1080                                              g_param_spec_boolean ("gtk-enable-tooltips",
1081                                                                    P_("Enable Tooltips"),
1082                                                                    P_("Whether tooltips should be shown on widgets"),
1083                                                                    TRUE,
1084                                                                    GTK_PARAM_READWRITE),
1085                                              NULL);
1086   g_assert (result == PROP_ENABLE_TOOLTIPS);
1087
1088   /**
1089    * GtkSettings:gtk-toolbar-style:
1090    *
1091    * The size of icons in default toolbars.
1092    */
1093   result = settings_install_property_parser (class,
1094                                              g_param_spec_enum ("gtk-toolbar-style",
1095                                                                    P_("Toolbar style"),
1096                                                                    P_("Whether default toolbars have text only, text and icons, icons only, etc."),
1097                                                                    GTK_TYPE_TOOLBAR_STYLE,
1098                                                                    GTK_TOOLBAR_BOTH,
1099                                                                    GTK_PARAM_READWRITE),
1100                                              gtk_rc_property_parse_enum);
1101   g_assert (result == PROP_TOOLBAR_STYLE);
1102
1103   /**
1104    * GtkSettings:gtk-toolbar-icon-size:
1105    *
1106    * The size of icons in default toolbars.
1107    */
1108   result = settings_install_property_parser (class,
1109                                              g_param_spec_enum ("gtk-toolbar-icon-size",
1110                                                                    P_("Toolbar Icon Size"),
1111                                                                    P_("The size of icons in default toolbars."),
1112                                                                    GTK_TYPE_ICON_SIZE,
1113                                                                    GTK_ICON_SIZE_LARGE_TOOLBAR,
1114                                                                    GTK_PARAM_READWRITE),
1115                                              gtk_rc_property_parse_enum);
1116   g_assert (result == PROP_TOOLBAR_ICON_SIZE);
1117
1118   /**
1119    * GtkSettings:gtk-auto-mnemonics:
1120    *
1121    * Whether mnemonics should be automatically shown and hidden when the user
1122    * presses the mnemonic activator.
1123    *
1124    * Since: 2.20
1125    */
1126   result = settings_install_property_parser (class,
1127                                              g_param_spec_boolean ("gtk-auto-mnemonics",
1128                                                                    P_("Auto Mnemonics"),
1129                                                                    P_("Whether mnemonics should be automatically shown and hidden when the user presses the mnemonic activator."),
1130                                                                    FALSE,
1131                                                                    GTK_PARAM_READWRITE),
1132                                              NULL);
1133   g_assert (result == PROP_AUTO_MNEMONICS);
1134
1135   /**
1136    * GtkSettings:gtk-visible-focus:
1137    *
1138    * Whether 'focus rectangles' should be always visible, never visible,
1139    * or hidden until the user starts to use the keyboard.
1140    *
1141    * Since: 3.2
1142    */
1143   result = settings_install_property_parser (class,
1144                                              g_param_spec_enum ("gtk-visible-focus",
1145                                                                 P_("Visible Focus"),
1146                                                                 P_("Whether 'focus rectangles' should be hidden until the user starts to use the keyboard."),
1147                                                                 GTK_TYPE_POLICY_TYPE,
1148                                                                 GTK_POLICY_ALWAYS,
1149                                                                 GTK_PARAM_READWRITE),
1150                                              gtk_rc_property_parse_enum);
1151   g_assert (result == PROP_VISIBLE_FOCUS);
1152
1153   /**
1154    * GtkSettings:gtk-application-prefer-dark-theme:
1155    *
1156    * Whether the application prefers to use a dark theme. If a GTK+ theme
1157    * includes a dark variant, it will be used instead of the configured
1158    * theme.
1159    *
1160    * Some applications benefit from minimizing the amount of light pollution that
1161    * interferes with the content. Good candidates for dark themes are photo and
1162    * video editors that make the actual content get all the attention and minimize
1163    * the distraction of the chrome.
1164    *
1165    * Dark themes should not be used for documents, where large spaces are white/light
1166    * and the dark chrome creates too much contrast (web browser, text editor...).
1167    *
1168    * Since: 2.22
1169    */
1170   result = settings_install_property_parser (class,
1171                                              g_param_spec_boolean ("gtk-application-prefer-dark-theme",
1172                                                                  P_("Application prefers a dark theme"),
1173                                                                  P_("Whether the application prefers to have a dark theme."),
1174                                                                  FALSE,
1175                                                                  GTK_PARAM_READWRITE),
1176                                              NULL);
1177   g_assert (result == PROP_APPLICATION_PREFER_DARK_THEME);
1178
1179   /**
1180    * GtkSettings::gtk-button-images:
1181    *
1182    * Whether images should be shown on buttons
1183    *
1184    * Since: 2.4
1185    */
1186   result = settings_install_property_parser (class,
1187                                              g_param_spec_boolean ("gtk-button-images",
1188                                                                    P_("Show button images"),
1189                                                                    P_("Whether images should be shown on buttons"),
1190                                                                    TRUE,
1191                                                                    GTK_PARAM_READWRITE),
1192                                              NULL);
1193   g_assert (result == PROP_BUTTON_IMAGES);
1194
1195   result = settings_install_property_parser (class,
1196                                              g_param_spec_boolean ("gtk-entry-select-on-focus",
1197                                                                    P_("Select on focus"),
1198                                                                    P_("Whether to select the contents of an entry when it is focused"),
1199                                                                    TRUE,
1200                                                                    GTK_PARAM_READWRITE),
1201                                              NULL);
1202   g_assert (result == PROP_ENTRY_SELECT_ON_FOCUS);
1203
1204   /**
1205    * GtkSettings:gtk-entry-password-hint-timeout:
1206    *
1207    * How long to show the last input character in hidden
1208    * entries. This value is in milliseconds. 0 disables showing the
1209    * last char. 600 is a good value for enabling it.
1210    *
1211    * Since: 2.10
1212    */
1213   result = settings_install_property_parser (class,
1214                                              g_param_spec_uint ("gtk-entry-password-hint-timeout",
1215                                                                 P_("Password Hint Timeout"),
1216                                                                 P_("How long to show the last input character in hidden entries"),
1217                                                                 0, G_MAXUINT,
1218                                                                 0,
1219                                                                 GTK_PARAM_READWRITE),
1220                                              NULL);
1221   g_assert (result == PROP_ENTRY_PASSWORD_HINT_TIMEOUT);
1222
1223   result = settings_install_property_parser (class,
1224                                              g_param_spec_boolean ("gtk-menu-images",
1225                                                                    P_("Show menu images"),
1226                                                                    P_("Whether images should be shown in menus"),
1227                                                                    TRUE,
1228                                                                    GTK_PARAM_READWRITE),
1229                                              NULL);
1230   g_assert (result == PROP_MENU_IMAGES);
1231
1232   result = settings_install_property_parser (class,
1233                                              g_param_spec_int ("gtk-menu-bar-popup-delay",
1234                                                                P_("Delay before drop down menus appear"),
1235                                                                P_("Delay before the submenus of a menu bar appear"),
1236                                                                0, G_MAXINT,
1237                                                                0,
1238                                                                GTK_PARAM_READWRITE),
1239                                              NULL);
1240   g_assert (result == PROP_MENU_BAR_POPUP_DELAY);
1241
1242   /**
1243    * GtkSettings:gtk-scrolled-window-placement:
1244    *
1245    * Where the contents of scrolled windows are located with respect to the
1246    * scrollbars, if not overridden by the scrolled window's own placement.
1247    *
1248    * Since: 2.10
1249    */
1250   result = settings_install_property_parser (class,
1251                                              g_param_spec_enum ("gtk-scrolled-window-placement",
1252                                                                 P_("Scrolled Window Placement"),
1253                                                                 P_("Where the contents of scrolled windows are located with respect to the scrollbars, if not overridden by the scrolled window's own placement."),
1254                                                                 GTK_TYPE_CORNER_TYPE,
1255                                                                 GTK_CORNER_TOP_LEFT,
1256                                                                 GTK_PARAM_READWRITE),
1257                                              gtk_rc_property_parse_enum);
1258   g_assert (result == PROP_SCROLLED_WINDOW_PLACEMENT);
1259
1260   result = settings_install_property_parser (class,
1261                                              g_param_spec_boolean ("gtk-can-change-accels",
1262                                                                    P_("Can change accelerators"),
1263                                                                    P_("Whether menu accelerators can be changed by pressing a key over the menu item"),
1264                                                                    FALSE,
1265                                                                    GTK_PARAM_READWRITE),
1266                                              NULL);
1267   g_assert (result == PROP_CAN_CHANGE_ACCELS);
1268
1269   result = settings_install_property_parser (class,
1270                                              g_param_spec_int ("gtk-menu-popup-delay",
1271                                                                P_("Delay before submenus appear"),
1272                                                                P_("Minimum time the pointer must stay over a menu item before the submenu appear"),
1273                                                                0, G_MAXINT,
1274                                                                225,
1275                                                                GTK_PARAM_READWRITE),
1276                                              NULL);
1277   g_assert (result == PROP_MENU_POPUP_DELAY);
1278
1279   result = settings_install_property_parser (class,
1280                                              g_param_spec_int ("gtk-menu-popdown-delay",
1281                                                                P_("Delay before hiding a submenu"),
1282                                                                P_("The time before hiding a submenu when the pointer is moving towards the submenu"),
1283                                                                0, G_MAXINT,
1284                                                                1000,
1285                                                                GTK_PARAM_READWRITE),
1286                                              NULL);
1287   g_assert (result == PROP_MENU_POPDOWN_DELAY);
1288
1289   result = settings_install_property_parser (class,
1290                                              g_param_spec_boolean ("gtk-label-select-on-focus",
1291                                                                    P_("Select on focus"),
1292                                                                    P_("Whether to select the contents of a selectable label when it is focused"),
1293                                                                    TRUE,
1294                                                                    GTK_PARAM_READWRITE),
1295                                              NULL);
1296   g_assert (result == PROP_LABEL_SELECT_ON_FOCUS);
1297
1298   result = settings_install_property_parser (class,
1299                                              g_param_spec_string ("gtk-color-palette",
1300                                                                   P_("Custom palette"),
1301                                                                   P_("Palette to use in the color selector"),
1302                                                                   default_color_palette,
1303                                                                   GTK_PARAM_READWRITE),
1304                                              NULL);
1305   g_assert (result == PROP_COLOR_PALETTE);
1306
1307   result = settings_install_property_parser (class,
1308                                              g_param_spec_enum ("gtk-im-preedit-style",
1309                                                                 P_("IM Preedit style"),
1310                                                                 P_("How to draw the input method preedit string"),
1311                                                                 GTK_TYPE_IM_PREEDIT_STYLE,
1312                                                                 GTK_IM_PREEDIT_CALLBACK,
1313                                                                 GTK_PARAM_READWRITE),
1314                                              gtk_rc_property_parse_enum);
1315   g_assert (result == PROP_IM_PREEDIT_STYLE);
1316
1317   result = settings_install_property_parser (class,
1318                                              g_param_spec_enum ("gtk-im-status-style",
1319                                                                 P_("IM Status style"),
1320                                                                 P_("How to draw the input method statusbar"),
1321                                                                 GTK_TYPE_IM_STATUS_STYLE,
1322                                                                 GTK_IM_STATUS_CALLBACK,
1323                                                                 GTK_PARAM_READWRITE),
1324                                              gtk_rc_property_parse_enum);
1325   g_assert (result == PROP_IM_STATUS_STYLE);
1326
1327   result = settings_install_property_parser (class,
1328                                              g_param_spec_boolean ("gtk-shell-shows-app-menu",
1329                                                                    P_("Desktop shell shows app menu"),
1330                                                                    P_("Set to TRUE if the desktop environment "
1331                                                                       "is displaying the app menu, FALSE if "
1332                                                                       "the app should display it itself."),
1333                                                                    FALSE, GTK_PARAM_READWRITE),
1334                                              NULL);
1335   g_assert (result == PROP_SHELL_SHOWS_APP_MENU);
1336
1337
1338   g_type_class_add_private (class, sizeof (GtkSettingsPrivate));
1339 }
1340
1341 static GtkStyleProperties *
1342 gtk_settings_get_style (GtkStyleProvider *provider,
1343                         GtkWidgetPath    *path)
1344 {
1345   PangoFontDescription *font_desc;
1346   gchar *font_name, *color_scheme;
1347   GtkSettings *settings;
1348   GtkStyleProperties *props;
1349   gchar **colors;
1350   guint i;
1351
1352   settings = GTK_SETTINGS (provider);
1353   props = gtk_style_properties_new ();
1354
1355   g_object_get (settings,
1356                 "gtk-font-name", &font_name,
1357                 "gtk-color-scheme", &color_scheme,
1358                 NULL);
1359
1360   colors = g_strsplit_set (color_scheme, "\n;", -1);
1361
1362   for (i = 0; colors[i]; i++)
1363     {
1364       GtkSymbolicColor *color;
1365       gchar *name, *pos;
1366       GdkRGBA col;
1367
1368       if (!*colors[i])
1369         continue;
1370
1371       name = colors[i];
1372       pos = strchr (colors[i], ':');
1373
1374       if (!pos)
1375         continue;
1376
1377       /* Set NUL after color name */
1378       *pos = '\0';
1379       pos++;
1380
1381       /* Find start of color string */
1382       while (*pos == ' ')
1383         pos++;
1384
1385       if (!*pos || !gdk_rgba_parse (&col, pos))
1386         continue;
1387
1388       color = gtk_symbolic_color_new_literal (&col);
1389       gtk_style_properties_map_color (props, name, color);
1390       gtk_symbolic_color_unref (color);
1391     }
1392
1393   font_desc = pango_font_description_from_string (font_name);
1394
1395   /* Unset normal attributes from this description,
1396    * so they do not override theme values */
1397   if (pango_font_description_get_weight (font_desc) == PANGO_WEIGHT_NORMAL)
1398     pango_font_description_unset_fields (font_desc,
1399                                          PANGO_FONT_MASK_WEIGHT);
1400
1401   if (pango_font_description_get_stretch (font_desc) == PANGO_STRETCH_NORMAL)
1402     pango_font_description_unset_fields (font_desc,
1403                                          PANGO_FONT_MASK_STRETCH);
1404
1405   if (pango_font_description_get_variant (font_desc) == PANGO_VARIANT_NORMAL)
1406     pango_font_description_unset_fields (font_desc,
1407                                          PANGO_FONT_MASK_VARIANT);
1408
1409   if (pango_font_description_get_style (font_desc) == PANGO_STYLE_NORMAL)
1410     pango_font_description_unset_fields (font_desc,
1411                                          PANGO_FONT_MASK_STYLE);
1412
1413   gtk_style_properties_set (props, 0,
1414                             "font", font_desc,
1415                             NULL);
1416
1417   pango_font_description_free (font_desc);
1418   g_strfreev (colors);
1419   g_free (color_scheme);
1420   g_free (font_name);
1421
1422   return props;
1423 }
1424
1425 static void
1426 gtk_settings_provider_iface_init (GtkStyleProviderIface *iface)
1427 {
1428   iface->get_style = gtk_settings_get_style;
1429 }
1430
1431 static void
1432 gtk_settings_finalize (GObject *object)
1433 {
1434   GtkSettings *settings = GTK_SETTINGS (object);
1435   GtkSettingsPrivate *priv = settings->priv;
1436   guint i;
1437
1438   object_list = g_slist_remove (object_list, settings);
1439
1440   for (i = 0; i < class_n_properties; i++)
1441     g_value_unset (&priv->property_values[i].value);
1442   g_free (priv->property_values);
1443
1444   g_datalist_clear (&priv->queued_settings);
1445
1446   if (priv->theme_provider)
1447     g_object_unref (priv->theme_provider);
1448
1449   if (priv->key_theme_provider)
1450     g_object_unref (priv->key_theme_provider);
1451
1452   G_OBJECT_CLASS (gtk_settings_parent_class)->finalize (object);
1453 }
1454
1455 static void
1456 settings_init_style (GtkSettings *settings)
1457 {
1458   static GtkCssProvider *css_provider = NULL;
1459
1460   GdkScreen *screen = settings->priv->screen;
1461   GtkCssProvider *default_provider;
1462
1463   /* Add provider for user file */
1464   if (G_UNLIKELY (!css_provider))
1465     {
1466       gchar *css_path;
1467
1468       css_provider = gtk_css_provider_new ();
1469       css_path = g_build_filename (g_get_user_config_dir (),
1470                                    "gtk-3.0",
1471                                    "gtk.css",
1472                                    NULL);
1473
1474       if (g_file_test (css_path,
1475                        G_FILE_TEST_IS_REGULAR))
1476         gtk_css_provider_load_from_path (css_provider, css_path, NULL);
1477
1478       g_free (css_path);
1479     }
1480
1481   gtk_style_context_add_provider_for_screen (screen,
1482                                              GTK_STYLE_PROVIDER (css_provider),
1483                                              GTK_STYLE_PROVIDER_PRIORITY_USER);
1484
1485   default_provider = gtk_css_provider_get_default ();
1486   gtk_style_context_add_provider_for_screen (screen,
1487                                              GTK_STYLE_PROVIDER (default_provider),
1488                                              GTK_STYLE_PROVIDER_PRIORITY_FALLBACK);
1489
1490   gtk_style_context_add_provider_for_screen (screen,
1491                                              GTK_STYLE_PROVIDER (settings),
1492                                              GTK_STYLE_PROVIDER_PRIORITY_SETTINGS);
1493
1494   settings_update_theme (settings);
1495   settings_update_key_theme (settings);
1496 }
1497
1498 /**
1499  * gtk_settings_get_for_screen:
1500  * @screen: a #GdkScreen.
1501  *
1502  * Gets the #GtkSettings object for @screen, creating it if necessary.
1503  *
1504  * Return value: (transfer none): a #GtkSettings object.
1505  *
1506  * Since: 2.2
1507  */
1508 GtkSettings*
1509 gtk_settings_get_for_screen (GdkScreen *screen)
1510 {
1511   GtkSettings *settings;
1512
1513   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
1514
1515   settings = g_object_get_data (G_OBJECT (screen), "gtk-settings");
1516   if (!settings)
1517     {
1518 #ifdef GDK_WINDOWING_QUARTZ
1519       if (GDK_IS_QUARTZ_SCREEN (screen))
1520         settings = g_object_new (GTK_TYPE_SETTINGS, "gtk-key-theme-name", "Mac", NULL);
1521       else
1522 #endif
1523         settings = g_object_new (GTK_TYPE_SETTINGS, NULL);
1524       settings->priv->screen = screen;
1525       g_object_set_data_full (G_OBJECT (screen), I_("gtk-settings"),
1526                               settings, g_object_unref);
1527
1528       settings_init_style (settings);
1529       settings_update_double_click (settings);
1530       settings_update_cursor_theme (settings);
1531       settings_update_resolution (settings);
1532       settings_update_font_options (settings);
1533       settings_update_color_scheme (settings);
1534     }
1535
1536   return settings;
1537 }
1538
1539 /**
1540  * gtk_settings_get_default:
1541  *
1542  * Gets the #GtkSettings object for the default GDK screen, creating
1543  * it if necessary. See gtk_settings_get_for_screen().
1544  *
1545  * Return value: (transfer none): a #GtkSettings object. If there is no default
1546  *  screen, then returns %NULL.
1547  **/
1548 GtkSettings*
1549 gtk_settings_get_default (void)
1550 {
1551   GdkScreen *screen = gdk_screen_get_default ();
1552
1553   if (screen)
1554     return gtk_settings_get_for_screen (screen);
1555   else
1556     return NULL;
1557 }
1558
1559 static void
1560 gtk_settings_set_property (GObject      *object,
1561                            guint         property_id,
1562                            const GValue *value,
1563                            GParamSpec   *pspec)
1564 {
1565   GtkSettings *settings = GTK_SETTINGS (object);
1566   GtkSettingsPrivate *priv = settings->priv;
1567
1568   g_value_copy (value, &priv->property_values[property_id - 1].value);
1569   priv->property_values[property_id - 1].source = GTK_SETTINGS_SOURCE_APPLICATION;
1570
1571   if (pspec->param_id == PROP_COLOR_SCHEME)
1572     merge_color_scheme (settings, value, GTK_SETTINGS_SOURCE_APPLICATION);
1573 }
1574
1575 static void
1576 gtk_settings_get_property (GObject     *object,
1577                            guint        property_id,
1578                            GValue      *value,
1579                            GParamSpec  *pspec)
1580 {
1581   GtkSettings *settings = GTK_SETTINGS (object);
1582   GtkSettingsPrivate *priv = settings->priv;
1583   GType value_type = G_VALUE_TYPE (value);
1584   GType fundamental_type = G_TYPE_FUNDAMENTAL (value_type);
1585
1586   /* handle internal properties */
1587   switch (property_id)
1588     {
1589     case PROP_COLOR_HASH:
1590       g_value_set_boxed (value, get_color_hash (settings));
1591       return;
1592     case PROP_COLOR_SCHEME:
1593       g_value_take_string (value, get_color_scheme (settings));
1594       return;
1595     default: ;
1596     }
1597
1598   /* For enums and strings, we need to get the value as a string,
1599    * not as an int, since we support using names/nicks as the setting
1600    * value.
1601    */
1602   if ((g_value_type_transformable (G_TYPE_INT, value_type) &&
1603        !(fundamental_type == G_TYPE_ENUM || fundamental_type == G_TYPE_FLAGS)) ||
1604       g_value_type_transformable (G_TYPE_STRING, G_VALUE_TYPE (value)) ||
1605       g_value_type_transformable (GDK_TYPE_COLOR, G_VALUE_TYPE (value)))
1606     {
1607       if (priv->property_values[property_id - 1].source == GTK_SETTINGS_SOURCE_APPLICATION ||
1608           !gdk_screen_get_setting (priv->screen, pspec->name, value))
1609         g_value_copy (&priv->property_values[property_id - 1].value, value);
1610       else
1611         g_param_value_validate (pspec, value);
1612     }
1613   else
1614     {
1615       GValue val = G_VALUE_INIT;
1616
1617       /* Try to get xsetting as a string and parse it. */
1618
1619       g_value_init (&val, G_TYPE_STRING);
1620
1621       if (priv->property_values[property_id - 1].source == GTK_SETTINGS_SOURCE_APPLICATION ||
1622           !gdk_screen_get_setting (priv->screen, pspec->name, &val))
1623         {
1624           g_value_copy (&priv->property_values[property_id - 1].value, value);
1625         }
1626       else
1627         {
1628           GValue tmp_value = G_VALUE_INIT;
1629           GValue gstring_value = G_VALUE_INIT;
1630           GtkRcPropertyParser parser = (GtkRcPropertyParser) g_param_spec_get_qdata (pspec, quark_property_parser);
1631
1632           g_value_init (&gstring_value, G_TYPE_GSTRING);
1633           g_value_take_boxed (&gstring_value,
1634                               g_string_new (g_value_get_string (&val)));
1635
1636           g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1637
1638           if (parser && _gtk_settings_parse_convert (parser, &gstring_value,
1639                                                      pspec, &tmp_value))
1640             {
1641               g_value_copy (&tmp_value, value);
1642               g_param_value_validate (pspec, value);
1643             }
1644           else
1645             {
1646               g_value_copy (&priv->property_values[property_id - 1].value, value);
1647             }
1648
1649           g_value_unset (&gstring_value);
1650           g_value_unset (&tmp_value);
1651         }
1652
1653       g_value_unset (&val);
1654     }
1655 }
1656
1657 static void
1658 gtk_settings_notify (GObject    *object,
1659                      GParamSpec *pspec)
1660 {
1661   GtkSettings *settings = GTK_SETTINGS (object);
1662   GtkSettingsPrivate *priv = settings->priv;
1663   guint property_id = pspec->param_id;
1664
1665   if (priv->screen == NULL) /* initialization */
1666     return;
1667
1668   switch (property_id)
1669     {
1670     case PROP_MODULES:
1671       settings_update_modules (settings);
1672       break;
1673     case PROP_DOUBLE_CLICK_TIME:
1674     case PROP_DOUBLE_CLICK_DISTANCE:
1675       settings_update_double_click (settings);
1676       break;
1677     case PROP_COLOR_SCHEME:
1678       settings_update_color_scheme (settings);
1679       gtk_style_context_reset_widgets (priv->screen);
1680       break;
1681     case PROP_FONT_NAME:
1682       gtk_style_context_reset_widgets (priv->screen);
1683       break;
1684     case PROP_KEY_THEME_NAME:
1685       settings_update_key_theme (settings);
1686       break;
1687     case PROP_THEME_NAME:
1688     case PROP_APPLICATION_PREFER_DARK_THEME:
1689       settings_update_theme (settings);
1690       break;
1691     case PROP_XFT_DPI:
1692       settings_update_resolution (settings);
1693       /* This is a hack because with gtk_rc_reset_styles() doesn't get
1694        * widgets with gtk_widget_style_set(), and also causes more
1695        * recomputation than necessary.
1696        */
1697       gtk_style_context_reset_widgets (priv->screen);
1698       break;
1699     case PROP_XFT_ANTIALIAS:
1700     case PROP_XFT_HINTING:
1701     case PROP_XFT_HINTSTYLE:
1702     case PROP_XFT_RGBA:
1703       settings_update_font_options (settings);
1704       gtk_style_context_reset_widgets (priv->screen);
1705       break;
1706     case PROP_FONTCONFIG_TIMESTAMP:
1707       if (settings_update_fontconfig (settings))
1708         gtk_style_context_reset_widgets (priv->screen);
1709       break;
1710     case PROP_CURSOR_THEME_NAME:
1711     case PROP_CURSOR_THEME_SIZE:
1712       settings_update_cursor_theme (settings);
1713       break;
1714     }
1715 }
1716
1717 gboolean
1718 _gtk_settings_parse_convert (GtkRcPropertyParser parser,
1719                              const GValue       *src_value,
1720                              GParamSpec         *pspec,
1721                              GValue             *dest_value)
1722 {
1723   gboolean success = FALSE;
1724
1725   g_return_val_if_fail (G_VALUE_HOLDS (dest_value, G_PARAM_SPEC_VALUE_TYPE (pspec)), FALSE);
1726
1727   if (parser)
1728     {
1729       GString *gstring;
1730       gboolean free_gstring = TRUE;
1731
1732       if (G_VALUE_HOLDS (src_value, G_TYPE_GSTRING))
1733         {
1734           gstring = g_value_get_boxed (src_value);
1735           free_gstring = FALSE;
1736         }
1737       else if (G_VALUE_HOLDS_LONG (src_value))
1738         {
1739           gstring = g_string_new (NULL);
1740           g_string_append_printf (gstring, "%ld", g_value_get_long (src_value));
1741         }
1742       else if (G_VALUE_HOLDS_DOUBLE (src_value))
1743         {
1744           gstring = g_string_new (NULL);
1745           g_string_append_printf (gstring, "%f", g_value_get_double (src_value));
1746         }
1747       else if (G_VALUE_HOLDS_STRING (src_value))
1748         {
1749           gchar *tstr = g_strescape (g_value_get_string (src_value), NULL);
1750
1751           gstring = g_string_new (NULL);
1752           g_string_append_c (gstring, '\"');
1753           g_string_append (gstring, tstr);
1754           g_string_append_c (gstring, '\"');
1755           g_free (tstr);
1756         }
1757       else
1758         {
1759           g_return_val_if_fail (G_VALUE_HOLDS (src_value, G_TYPE_GSTRING), FALSE);
1760           gstring = NULL; /* silence compiler */
1761         }
1762
1763       success = (parser (pspec, gstring, dest_value) &&
1764                  !g_param_value_validate (pspec, dest_value));
1765
1766       if (free_gstring)
1767         g_string_free (gstring, TRUE);
1768     }
1769   else if (G_VALUE_HOLDS (src_value, G_TYPE_GSTRING))
1770     {
1771       if (G_VALUE_HOLDS (dest_value, G_TYPE_STRING))
1772         {
1773           GString *gstring = g_value_get_boxed (src_value);
1774
1775           g_value_set_string (dest_value, gstring ? gstring->str : NULL);
1776           success = !g_param_value_validate (pspec, dest_value);
1777         }
1778     }
1779   else if (g_value_type_transformable (G_VALUE_TYPE (src_value), G_VALUE_TYPE (dest_value)))
1780     success = g_param_value_convert (pspec, src_value, dest_value, TRUE);
1781
1782   return success;
1783 }
1784
1785 static void
1786 apply_queued_setting (GtkSettings             *settings,
1787                       GParamSpec              *pspec,
1788                       GtkSettingsValuePrivate *qvalue)
1789 {
1790   GtkSettingsPrivate *priv = settings->priv;
1791   GValue tmp_value = G_VALUE_INIT;
1792   GtkRcPropertyParser parser = (GtkRcPropertyParser) g_param_spec_get_qdata (pspec, quark_property_parser);
1793
1794   g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1795   if (_gtk_settings_parse_convert (parser, &qvalue->public.value,
1796                                    pspec, &tmp_value))
1797     {
1798       if (pspec->param_id == PROP_COLOR_SCHEME)
1799         merge_color_scheme (settings, &tmp_value, qvalue->source);
1800
1801       if (priv->property_values[pspec->param_id - 1].source <= qvalue->source)
1802         {
1803           g_value_copy (&tmp_value, &priv->property_values[pspec->param_id - 1].value);
1804           priv->property_values[pspec->param_id - 1].source = qvalue->source;
1805           g_object_notify (G_OBJECT (settings), g_param_spec_get_name (pspec));
1806         }
1807
1808     }
1809   else
1810     {
1811       gchar *debug = g_strdup_value_contents (&qvalue->public.value);
1812
1813       g_message ("%s: failed to retrieve property `%s' of type `%s' from rc file value \"%s\" of type `%s'",
1814                  qvalue->public.origin ? qvalue->public.origin : "(for origin information, set GTK_DEBUG)",
1815                  pspec->name,
1816                  g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1817                  debug,
1818                  G_VALUE_TYPE_NAME (&tmp_value));
1819       g_free (debug);
1820     }
1821   g_value_unset (&tmp_value);
1822 }
1823
1824 static guint
1825 settings_install_property_parser (GtkSettingsClass   *class,
1826                                   GParamSpec         *pspec,
1827                                   GtkRcPropertyParser parser)
1828 {
1829   GSList *node, *next;
1830
1831   switch (G_TYPE_FUNDAMENTAL (G_PARAM_SPEC_VALUE_TYPE (pspec)))
1832     {
1833     case G_TYPE_BOOLEAN:
1834     case G_TYPE_UCHAR:
1835     case G_TYPE_CHAR:
1836     case G_TYPE_UINT:
1837     case G_TYPE_INT:
1838     case G_TYPE_ULONG:
1839     case G_TYPE_LONG:
1840     case G_TYPE_FLOAT:
1841     case G_TYPE_DOUBLE:
1842     case G_TYPE_STRING:
1843     case G_TYPE_ENUM:
1844       break;
1845     case G_TYPE_BOXED:
1846       if (strcmp (g_param_spec_get_name (pspec), "color-hash") == 0)
1847         {
1848           break;
1849         }
1850       /* fall through */
1851     default:
1852       if (!parser)
1853         {
1854           g_warning (G_STRLOC ": parser needs to be specified for property \"%s\" of type `%s'",
1855                      pspec->name, g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
1856           return 0;
1857         }
1858     }
1859   if (g_object_class_find_property (G_OBJECT_CLASS (class), pspec->name))
1860     {
1861       g_warning (G_STRLOC ": an rc-data property \"%s\" already exists",
1862                  pspec->name);
1863       return 0;
1864     }
1865
1866   for (node = object_list; node; node = node->next)
1867     g_object_freeze_notify (node->data);
1868
1869   g_object_class_install_property (G_OBJECT_CLASS (class), ++class_n_properties, pspec);
1870   g_param_spec_set_qdata (pspec, quark_property_parser, (gpointer) parser);
1871
1872   for (node = object_list; node; node = node->next)
1873     {
1874       GtkSettings *settings = node->data;
1875       GtkSettingsPrivate *priv = settings->priv;
1876       GtkSettingsValuePrivate *qvalue;
1877
1878       priv->property_values = g_renew (GtkSettingsPropertyValue, priv->property_values, class_n_properties);
1879       priv->property_values[class_n_properties - 1].value.g_type = 0;
1880       g_value_init (&priv->property_values[class_n_properties - 1].value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1881       g_param_value_set_default (pspec, &priv->property_values[class_n_properties - 1].value);
1882       priv->property_values[class_n_properties - 1].source = GTK_SETTINGS_SOURCE_DEFAULT;
1883       g_object_notify (G_OBJECT (settings), pspec->name);
1884
1885       qvalue = g_datalist_get_data (&priv->queued_settings, pspec->name);
1886       if (qvalue)
1887         apply_queued_setting (settings, pspec, qvalue);
1888     }
1889
1890   for (node = object_list; node; node = next)
1891     {
1892       next = node->next;
1893       g_object_thaw_notify (node->data);
1894     }
1895
1896   return class_n_properties;
1897 }
1898
1899 GtkRcPropertyParser
1900 _gtk_rc_property_parser_from_type (GType type)
1901 {
1902   if (type == GDK_TYPE_COLOR)
1903     return gtk_rc_property_parse_color;
1904   else if (type == GTK_TYPE_REQUISITION)
1905     return gtk_rc_property_parse_requisition;
1906   else if (type == GTK_TYPE_BORDER)
1907     return gtk_rc_property_parse_border;
1908   else if (G_TYPE_FUNDAMENTAL (type) == G_TYPE_ENUM && G_TYPE_IS_DERIVED (type))
1909     return gtk_rc_property_parse_enum;
1910   else if (G_TYPE_FUNDAMENTAL (type) == G_TYPE_FLAGS && G_TYPE_IS_DERIVED (type))
1911     return gtk_rc_property_parse_flags;
1912   else
1913     return NULL;
1914 }
1915
1916 void
1917 gtk_settings_install_property (GParamSpec *pspec)
1918 {
1919   static GtkSettingsClass *klass = NULL;
1920
1921   GtkRcPropertyParser parser;
1922
1923   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1924
1925   if (! klass)
1926     klass = g_type_class_ref (GTK_TYPE_SETTINGS);
1927
1928   parser = _gtk_rc_property_parser_from_type (G_PARAM_SPEC_VALUE_TYPE (pspec));
1929
1930   settings_install_property_parser (klass, pspec, parser);
1931 }
1932
1933 /**
1934  * gtk_settings_install_property_parser:
1935  * @pspec:
1936  * @parser: (scope call):
1937  */
1938 void
1939 gtk_settings_install_property_parser (GParamSpec          *pspec,
1940                                       GtkRcPropertyParser  parser)
1941 {
1942   static GtkSettingsClass *klass = NULL;
1943
1944   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1945   g_return_if_fail (parser != NULL);
1946
1947   if (! klass)
1948     klass = g_type_class_ref (GTK_TYPE_SETTINGS);
1949
1950   settings_install_property_parser (klass, pspec, parser);
1951 }
1952
1953 static void
1954 free_value (gpointer data)
1955 {
1956   GtkSettingsValuePrivate *qvalue = data;
1957
1958   g_value_unset (&qvalue->public.value);
1959   g_free (qvalue->public.origin);
1960   g_slice_free (GtkSettingsValuePrivate, qvalue);
1961 }
1962
1963 static void
1964 gtk_settings_set_property_value_internal (GtkSettings            *settings,
1965                                           const gchar            *prop_name,
1966                                           const GtkSettingsValue *new_value,
1967                                           GtkSettingsSource       source)
1968 {
1969   GtkSettingsPrivate *priv = settings->priv;
1970   GtkSettingsValuePrivate *qvalue;
1971   GParamSpec *pspec;
1972   gchar *name;
1973   GQuark name_quark;
1974
1975   if (!G_VALUE_HOLDS_LONG (&new_value->value) &&
1976       !G_VALUE_HOLDS_DOUBLE (&new_value->value) &&
1977       !G_VALUE_HOLDS_STRING (&new_value->value) &&
1978       !G_VALUE_HOLDS (&new_value->value, G_TYPE_GSTRING))
1979     {
1980       g_warning (G_STRLOC ": value type invalid (%s)", g_type_name (G_VALUE_TYPE (&new_value->value)));
1981       return;
1982     }
1983
1984   name = g_strdup (prop_name);
1985   g_strcanon (name, G_CSET_DIGITS "-" G_CSET_a_2_z G_CSET_A_2_Z, '-');
1986   name_quark = g_quark_from_string (name);
1987   g_free (name);
1988
1989   qvalue = g_datalist_id_get_data (&priv->queued_settings, name_quark);
1990   if (!qvalue)
1991     {
1992       qvalue = g_slice_new0 (GtkSettingsValuePrivate);
1993       g_datalist_id_set_data_full (&priv->queued_settings, name_quark, qvalue, free_value);
1994     }
1995   else
1996     {
1997       g_free (qvalue->public.origin);
1998       g_value_unset (&qvalue->public.value);
1999     }
2000   qvalue->public.origin = g_strdup (new_value->origin);
2001   g_value_init (&qvalue->public.value, G_VALUE_TYPE (&new_value->value));
2002   g_value_copy (&new_value->value, &qvalue->public.value);
2003   qvalue->source = source;
2004   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (settings), g_quark_to_string (name_quark));
2005   if (pspec)
2006     apply_queued_setting (settings, pspec, qvalue);
2007 }
2008
2009 void
2010 gtk_settings_set_property_value (GtkSettings            *settings,
2011                                  const gchar            *prop_name,
2012                                  const GtkSettingsValue *new_value)
2013 {
2014   g_return_if_fail (GTK_SETTINGS (settings));
2015   g_return_if_fail (prop_name != NULL);
2016   g_return_if_fail (new_value != NULL);
2017
2018   gtk_settings_set_property_value_internal (settings, prop_name, new_value,
2019                                             GTK_SETTINGS_SOURCE_APPLICATION);
2020 }
2021
2022 void
2023 _gtk_settings_set_property_value_from_rc (GtkSettings            *settings,
2024                                           const gchar            *prop_name,
2025                                           const GtkSettingsValue *new_value)
2026 {
2027   g_return_if_fail (GTK_SETTINGS (settings));
2028   g_return_if_fail (prop_name != NULL);
2029   g_return_if_fail (new_value != NULL);
2030
2031   gtk_settings_set_property_value_internal (settings, prop_name, new_value,
2032                                             GTK_SETTINGS_SOURCE_THEME);
2033 }
2034
2035 void
2036 gtk_settings_set_string_property (GtkSettings *settings,
2037                                   const gchar *name,
2038                                   const gchar *v_string,
2039                                   const gchar *origin)
2040 {
2041   GtkSettingsValue svalue = { NULL, { 0, }, };
2042
2043   g_return_if_fail (GTK_SETTINGS (settings));
2044   g_return_if_fail (name != NULL);
2045   g_return_if_fail (v_string != NULL);
2046
2047   svalue.origin = (gchar*) origin;
2048   g_value_init (&svalue.value, G_TYPE_STRING);
2049   g_value_set_static_string (&svalue.value, v_string);
2050   gtk_settings_set_property_value (settings, name, &svalue);
2051   g_value_unset (&svalue.value);
2052 }
2053
2054 void
2055 gtk_settings_set_long_property (GtkSettings *settings,
2056                                 const gchar *name,
2057                                 glong        v_long,
2058                                 const gchar *origin)
2059 {
2060   GtkSettingsValue svalue = { NULL, { 0, }, };
2061
2062   g_return_if_fail (GTK_SETTINGS (settings));
2063   g_return_if_fail (name != NULL);
2064
2065   svalue.origin = (gchar*) origin;
2066   g_value_init (&svalue.value, G_TYPE_LONG);
2067   g_value_set_long (&svalue.value, v_long);
2068   gtk_settings_set_property_value (settings, name, &svalue);
2069   g_value_unset (&svalue.value);
2070 }
2071
2072 void
2073 gtk_settings_set_double_property (GtkSettings *settings,
2074                                   const gchar *name,
2075                                   gdouble      v_double,
2076                                   const gchar *origin)
2077 {
2078   GtkSettingsValue svalue = { NULL, { 0, }, };
2079
2080   g_return_if_fail (GTK_SETTINGS (settings));
2081   g_return_if_fail (name != NULL);
2082
2083   svalue.origin = (gchar*) origin;
2084   g_value_init (&svalue.value, G_TYPE_DOUBLE);
2085   g_value_set_double (&svalue.value, v_double);
2086   gtk_settings_set_property_value (settings, name, &svalue);
2087   g_value_unset (&svalue.value);
2088 }
2089
2090 /**
2091  * gtk_rc_property_parse_color:
2092  * @pspec: a #GParamSpec
2093  * @gstring: the #GString to be parsed
2094  * @property_value: a #GValue which must hold #GdkColor values.
2095  *
2096  * A #GtkRcPropertyParser for use with gtk_settings_install_property_parser()
2097  * or gtk_widget_class_install_style_property_parser() which parses a
2098  * color given either by its name or in the form
2099  * <literal>{ red, green, blue }</literal> where %red, %green and
2100  * %blue are integers between 0 and 65535 or floating-point numbers
2101  * between 0 and 1.
2102  *
2103  * Return value: %TRUE if @gstring could be parsed and @property_value
2104  * has been set to the resulting #GdkColor.
2105  **/
2106 gboolean
2107 gtk_rc_property_parse_color (const GParamSpec *pspec,
2108                              const GString    *gstring,
2109                              GValue           *property_value)
2110 {
2111   GdkColor color = { 0, 0, 0, 0, };
2112   GScanner *scanner;
2113   gboolean success;
2114
2115   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
2116   g_return_val_if_fail (G_VALUE_HOLDS (property_value, GDK_TYPE_COLOR), FALSE);
2117
2118   scanner = gtk_rc_scanner_new ();
2119   g_scanner_input_text (scanner, gstring->str, gstring->len);
2120   if (gtk_rc_parse_color (scanner, &color) == G_TOKEN_NONE &&
2121       g_scanner_get_next_token (scanner) == G_TOKEN_EOF)
2122     {
2123       g_value_set_boxed (property_value, &color);
2124       success = TRUE;
2125     }
2126   else
2127     success = FALSE;
2128   g_scanner_destroy (scanner);
2129
2130   return success;
2131 }
2132
2133 /**
2134  * gtk_rc_property_parse_enum:
2135  * @pspec: a #GParamSpec
2136  * @gstring: the #GString to be parsed
2137  * @property_value: a #GValue which must hold enum values.
2138  *
2139  * A #GtkRcPropertyParser for use with gtk_settings_install_property_parser()
2140  * or gtk_widget_class_install_style_property_parser() which parses a single
2141  * enumeration value.
2142  *
2143  * The enumeration value can be specified by its name, its nickname or
2144  * its numeric value. For consistency with flags parsing, the value
2145  * may be surrounded by parentheses.
2146  *
2147  * Return value: %TRUE if @gstring could be parsed and @property_value
2148  * has been set to the resulting #GEnumValue.
2149  **/
2150 gboolean
2151 gtk_rc_property_parse_enum (const GParamSpec *pspec,
2152                             const GString    *gstring,
2153                             GValue           *property_value)
2154 {
2155   gboolean need_closing_brace = FALSE, success = FALSE;
2156   GScanner *scanner;
2157   GEnumValue *enum_value = NULL;
2158
2159   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
2160   g_return_val_if_fail (G_VALUE_HOLDS_ENUM (property_value), FALSE);
2161
2162   scanner = gtk_rc_scanner_new ();
2163   g_scanner_input_text (scanner, gstring->str, gstring->len);
2164
2165   /* we just want to parse _one_ value, but for consistency with flags parsing
2166    * we support optional parenthesis
2167    */
2168   g_scanner_get_next_token (scanner);
2169   if (scanner->token == '(')
2170     {
2171       need_closing_brace = TRUE;
2172       g_scanner_get_next_token (scanner);
2173     }
2174   if (scanner->token == G_TOKEN_IDENTIFIER)
2175     {
2176       GEnumClass *class = G_PARAM_SPEC_ENUM (pspec)->enum_class;
2177
2178       enum_value = g_enum_get_value_by_name (class, scanner->value.v_identifier);
2179       if (!enum_value)
2180         enum_value = g_enum_get_value_by_nick (class, scanner->value.v_identifier);
2181       if (enum_value)
2182         {
2183           g_value_set_enum (property_value, enum_value->value);
2184           success = TRUE;
2185         }
2186     }
2187   else if (scanner->token == G_TOKEN_INT)
2188     {
2189       g_value_set_enum (property_value, scanner->value.v_int);
2190       success = TRUE;
2191     }
2192   if (need_closing_brace && g_scanner_get_next_token (scanner) != ')')
2193     success = FALSE;
2194   if (g_scanner_get_next_token (scanner) != G_TOKEN_EOF)
2195     success = FALSE;
2196
2197   g_scanner_destroy (scanner);
2198
2199   return success;
2200 }
2201
2202 static guint
2203 parse_flags_value (GScanner    *scanner,
2204                    GFlagsClass *class,
2205                    guint       *number)
2206 {
2207   g_scanner_get_next_token (scanner);
2208   if (scanner->token == G_TOKEN_IDENTIFIER)
2209     {
2210       GFlagsValue *flags_value;
2211
2212       flags_value = g_flags_get_value_by_name (class, scanner->value.v_identifier);
2213       if (!flags_value)
2214         flags_value = g_flags_get_value_by_nick (class, scanner->value.v_identifier);
2215       if (flags_value)
2216         {
2217           *number |= flags_value->value;
2218           return G_TOKEN_NONE;
2219         }
2220     }
2221   else if (scanner->token == G_TOKEN_INT)
2222     {
2223       *number |= scanner->value.v_int;
2224       return G_TOKEN_NONE;
2225     }
2226   return G_TOKEN_IDENTIFIER;
2227 }
2228
2229 /**
2230  * gtk_rc_property_parse_flags:
2231  * @pspec: a #GParamSpec
2232  * @gstring: the #GString to be parsed
2233  * @property_value: a #GValue which must hold flags values.
2234  *
2235  * A #GtkRcPropertyParser for use with gtk_settings_install_property_parser()
2236  * or gtk_widget_class_install_style_property_parser() which parses flags.
2237  *
2238  * Flags can be specified by their name, their nickname or
2239  * numerically. Multiple flags can be specified in the form
2240  * <literal>"( flag1 | flag2 | ... )"</literal>.
2241  *
2242  * Return value: %TRUE if @gstring could be parsed and @property_value
2243  * has been set to the resulting flags value.
2244  **/
2245 gboolean
2246 gtk_rc_property_parse_flags (const GParamSpec *pspec,
2247                              const GString    *gstring,
2248                              GValue           *property_value)
2249 {
2250   GFlagsClass *class;
2251    gboolean success = FALSE;
2252   GScanner *scanner;
2253
2254   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
2255   g_return_val_if_fail (G_VALUE_HOLDS_FLAGS (property_value), FALSE);
2256
2257   class = G_PARAM_SPEC_FLAGS (pspec)->flags_class;
2258   scanner = gtk_rc_scanner_new ();
2259   g_scanner_input_text (scanner, gstring->str, gstring->len);
2260
2261   /* parse either a single flags value or a "\( ... [ \| ... ] \)" compound */
2262   if (g_scanner_peek_next_token (scanner) == G_TOKEN_IDENTIFIER ||
2263       scanner->next_token == G_TOKEN_INT)
2264     {
2265       guint token, flags_value = 0;
2266
2267       token = parse_flags_value (scanner, class, &flags_value);
2268
2269       if (token == G_TOKEN_NONE && g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
2270         {
2271           success = TRUE;
2272           g_value_set_flags (property_value, flags_value);
2273         }
2274
2275     }
2276   else if (g_scanner_get_next_token (scanner) == '(')
2277     {
2278       guint token, flags_value = 0;
2279
2280       /* parse first value */
2281       token = parse_flags_value (scanner, class, &flags_value);
2282
2283       /* parse nth values, preceeded by '|' */
2284       while (token == G_TOKEN_NONE && g_scanner_get_next_token (scanner) == '|')
2285         token = parse_flags_value (scanner, class, &flags_value);
2286
2287       /* done, last token must have closed expression */
2288       if (token == G_TOKEN_NONE && scanner->token == ')' &&
2289           g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
2290         {
2291           g_value_set_flags (property_value, flags_value);
2292           success = TRUE;
2293         }
2294     }
2295   g_scanner_destroy (scanner);
2296
2297   return success;
2298 }
2299
2300 static gboolean
2301 get_braced_int (GScanner *scanner,
2302                 gboolean  first,
2303                 gboolean  last,
2304                 gint     *value)
2305 {
2306   if (first)
2307     {
2308       g_scanner_get_next_token (scanner);
2309       if (scanner->token != '{')
2310         return FALSE;
2311     }
2312
2313   g_scanner_get_next_token (scanner);
2314   if (scanner->token != G_TOKEN_INT)
2315     return FALSE;
2316
2317   *value = scanner->value.v_int;
2318
2319   if (last)
2320     {
2321       g_scanner_get_next_token (scanner);
2322       if (scanner->token != '}')
2323         return FALSE;
2324     }
2325   else
2326     {
2327       g_scanner_get_next_token (scanner);
2328       if (scanner->token != ',')
2329         return FALSE;
2330     }
2331
2332   return TRUE;
2333 }
2334
2335 /**
2336  * gtk_rc_property_parse_requisition:
2337  * @pspec: a #GParamSpec
2338  * @gstring: the #GString to be parsed
2339  * @property_value: a #GValue which must hold boxed values.
2340  *
2341  * A #GtkRcPropertyParser for use with gtk_settings_install_property_parser()
2342  * or gtk_widget_class_install_style_property_parser() which parses a
2343  * requisition in the form
2344  * <literal>"{ width, height }"</literal> for integers %width and %height.
2345  *
2346  * Return value: %TRUE if @gstring could be parsed and @property_value
2347  * has been set to the resulting #GtkRequisition.
2348  **/
2349 gboolean
2350 gtk_rc_property_parse_requisition  (const GParamSpec *pspec,
2351                                     const GString    *gstring,
2352                                     GValue           *property_value)
2353 {
2354   GtkRequisition requisition;
2355   GScanner *scanner;
2356   gboolean success = FALSE;
2357
2358   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
2359   g_return_val_if_fail (G_VALUE_HOLDS_BOXED (property_value), FALSE);
2360
2361   scanner = gtk_rc_scanner_new ();
2362   g_scanner_input_text (scanner, gstring->str, gstring->len);
2363
2364   if (get_braced_int (scanner, TRUE, FALSE, &requisition.width) &&
2365       get_braced_int (scanner, FALSE, TRUE, &requisition.height))
2366     {
2367       g_value_set_boxed (property_value, &requisition);
2368       success = TRUE;
2369     }
2370
2371   g_scanner_destroy (scanner);
2372
2373   return success;
2374 }
2375
2376 /**
2377  * gtk_rc_property_parse_border:
2378  * @pspec: a #GParamSpec
2379  * @gstring: the #GString to be parsed
2380  * @property_value: a #GValue which must hold boxed values.
2381  *
2382  * A #GtkRcPropertyParser for use with gtk_settings_install_property_parser()
2383  * or gtk_widget_class_install_style_property_parser() which parses
2384  * borders in the form
2385  * <literal>"{ left, right, top, bottom }"</literal> for integers
2386  * %left, %right, %top and %bottom.
2387  *
2388  * Return value: %TRUE if @gstring could be parsed and @property_value
2389  * has been set to the resulting #GtkBorder.
2390  **/
2391 gboolean
2392 gtk_rc_property_parse_border (const GParamSpec *pspec,
2393                               const GString    *gstring,
2394                               GValue           *property_value)
2395 {
2396   GtkBorder border;
2397   GScanner *scanner;
2398   gboolean success = FALSE;
2399   int left, right, top, bottom;
2400
2401   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
2402   g_return_val_if_fail (G_VALUE_HOLDS_BOXED (property_value), FALSE);
2403
2404   scanner = gtk_rc_scanner_new ();
2405   g_scanner_input_text (scanner, gstring->str, gstring->len);
2406
2407   if (get_braced_int (scanner, TRUE, FALSE, &left) &&
2408       get_braced_int (scanner, FALSE, FALSE, &right) &&
2409       get_braced_int (scanner, FALSE, FALSE, &top) &&
2410       get_braced_int (scanner, FALSE, TRUE, &bottom))
2411     {
2412       border.left = left;
2413       border.right = right;
2414       border.top = top;
2415       border.bottom = bottom;
2416       g_value_set_boxed (property_value, &border);
2417       success = TRUE;
2418     }
2419
2420   g_scanner_destroy (scanner);
2421
2422   return success;
2423 }
2424
2425 void
2426 _gtk_settings_handle_event (GdkEventSetting *event)
2427 {
2428   GdkScreen *screen;
2429   GtkSettings *settings;
2430   GParamSpec *pspec;
2431   guint property_id;
2432
2433   screen = gdk_window_get_screen (event->window);
2434   settings = gtk_settings_get_for_screen (screen);
2435   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (settings), event->name);
2436
2437   if (pspec)
2438     {
2439       property_id = pspec->param_id;
2440
2441       if (property_id == PROP_COLOR_SCHEME)
2442         {
2443           GValue value = G_VALUE_INIT;
2444
2445           g_value_init (&value, G_TYPE_STRING);
2446           if (!gdk_screen_get_setting (screen, pspec->name, &value))
2447             g_value_set_static_string (&value, "");
2448           merge_color_scheme (settings, &value, GTK_SETTINGS_SOURCE_XSETTING);
2449           g_value_unset (&value);
2450         }
2451       g_object_notify (G_OBJECT (settings), pspec->name);
2452    }
2453 }
2454
2455 static void
2456 reset_rc_values_foreach (GQuark   key_id,
2457                          gpointer data,
2458                          gpointer user_data)
2459 {
2460   GtkSettingsValuePrivate *qvalue = data;
2461   GSList **to_reset = user_data;
2462
2463   if (qvalue->source == GTK_SETTINGS_SOURCE_THEME)
2464     *to_reset = g_slist_prepend (*to_reset, GUINT_TO_POINTER (key_id));
2465 }
2466
2467 void
2468 _gtk_settings_reset_rc_values (GtkSettings *settings)
2469 {
2470   GtkSettingsPrivate *priv = settings->priv;
2471   GSList *to_reset = NULL;
2472   GSList *tmp_list;
2473   GParamSpec **pspecs, **p;
2474   gint i;
2475
2476   /* Remove any queued settings */
2477   g_datalist_foreach (&priv->queued_settings,
2478                       reset_rc_values_foreach,
2479                       &to_reset);
2480
2481   for (tmp_list = to_reset; tmp_list; tmp_list = tmp_list->next)
2482     {
2483       GQuark key_id = GPOINTER_TO_UINT (tmp_list->data);
2484       g_datalist_id_remove_data (&priv->queued_settings, key_id);
2485     }
2486
2487    g_slist_free (to_reset);
2488
2489   /* Now reset the active settings
2490    */
2491   pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (settings), NULL);
2492   i = 0;
2493
2494   g_object_freeze_notify (G_OBJECT (settings));
2495   for (p = pspecs; *p; p++)
2496     {
2497       if (priv->property_values[i].source == GTK_SETTINGS_SOURCE_THEME)
2498         {
2499           GParamSpec *pspec = *p;
2500
2501           g_param_value_set_default (pspec, &priv->property_values[i].value);
2502           g_object_notify (G_OBJECT (settings), pspec->name);
2503         }
2504       i++;
2505     }
2506   g_object_thaw_notify (G_OBJECT (settings));
2507   g_free (pspecs);
2508 }
2509
2510 static void
2511 settings_update_double_click (GtkSettings *settings)
2512 {
2513   GtkSettingsPrivate *priv = settings->priv;
2514
2515   if (gdk_screen_get_number (priv->screen) == 0)
2516     {
2517       GdkDisplay *display = gdk_screen_get_display (priv->screen);
2518       gint double_click_time;
2519       gint double_click_distance;
2520
2521       g_object_get (settings,
2522                     "gtk-double-click-time", &double_click_time,
2523                     "gtk-double-click-distance", &double_click_distance,
2524                     NULL);
2525
2526       gdk_display_set_double_click_time (display, double_click_time);
2527       gdk_display_set_double_click_distance (display, double_click_distance);
2528     }
2529 }
2530
2531 static void
2532 settings_update_modules (GtkSettings *settings)
2533 {
2534   gchar *modules;
2535
2536   g_object_get (settings,
2537                 "gtk-modules", &modules,
2538                 NULL);
2539
2540   _gtk_modules_settings_changed (settings, modules);
2541
2542   g_free (modules);
2543 }
2544
2545 static void
2546 settings_update_cursor_theme (GtkSettings *settings)
2547 {
2548 #ifdef GDK_WINDOWING_X11
2549   GdkDisplay *display = gdk_screen_get_display (settings->priv->screen);
2550   gchar *theme = NULL;
2551   gint size = 0;
2552
2553   if (GDK_IS_X11_DISPLAY (display))
2554     {
2555       g_object_get (settings,
2556                     "gtk-cursor-theme-name", &theme,
2557                     "gtk-cursor-theme-size", &size,
2558                     NULL);
2559
2560       gdk_x11_display_set_cursor_theme (display, theme, size);
2561
2562       g_free (theme);
2563     }
2564 #endif
2565 }
2566
2567 static void
2568 settings_update_font_options (GtkSettings *settings)
2569 {
2570   GtkSettingsPrivate *priv = settings->priv;
2571   gint hinting;
2572   gchar *hint_style_str;
2573   cairo_hint_style_t hint_style = CAIRO_HINT_STYLE_NONE;
2574   gint antialias;
2575   cairo_antialias_t antialias_mode = CAIRO_ANTIALIAS_GRAY;
2576   gchar *rgba_str;
2577   cairo_subpixel_order_t subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
2578   cairo_font_options_t *options;
2579
2580   g_object_get (settings,
2581                 "gtk-xft-antialias", &antialias,
2582                 "gtk-xft-hinting", &hinting,
2583                 "gtk-xft-hintstyle", &hint_style_str,
2584                 "gtk-xft-rgba", &rgba_str,
2585                 NULL);
2586
2587   options = cairo_font_options_create ();
2588
2589   cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
2590
2591   if (hinting >= 0 && !hinting)
2592     {
2593       hint_style = CAIRO_HINT_STYLE_NONE;
2594     }
2595   else if (hint_style_str)
2596     {
2597       if (strcmp (hint_style_str, "hintnone") == 0)
2598         hint_style = CAIRO_HINT_STYLE_NONE;
2599       else if (strcmp (hint_style_str, "hintslight") == 0)
2600         hint_style = CAIRO_HINT_STYLE_SLIGHT;
2601       else if (strcmp (hint_style_str, "hintmedium") == 0)
2602         hint_style = CAIRO_HINT_STYLE_MEDIUM;
2603       else if (strcmp (hint_style_str, "hintfull") == 0)
2604         hint_style = CAIRO_HINT_STYLE_FULL;
2605     }
2606
2607   g_free (hint_style_str);
2608
2609   cairo_font_options_set_hint_style (options, hint_style);
2610
2611   if (rgba_str)
2612     {
2613       if (strcmp (rgba_str, "rgb") == 0)
2614         subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB;
2615       else if (strcmp (rgba_str, "bgr") == 0)
2616         subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR;
2617       else if (strcmp (rgba_str, "vrgb") == 0)
2618         subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB;
2619       else if (strcmp (rgba_str, "vbgr") == 0)
2620         subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR;
2621
2622       g_free (rgba_str);
2623     }
2624
2625   cairo_font_options_set_subpixel_order (options, subpixel_order);
2626
2627   if (antialias >= 0 && !antialias)
2628     antialias_mode = CAIRO_ANTIALIAS_NONE;
2629   else if (subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT)
2630     antialias_mode = CAIRO_ANTIALIAS_SUBPIXEL;
2631   else if (antialias >= 0)
2632     antialias_mode = CAIRO_ANTIALIAS_GRAY;
2633
2634   cairo_font_options_set_antialias (options, antialias_mode);
2635
2636   gdk_screen_set_font_options (priv->screen, options);
2637
2638   cairo_font_options_destroy (options);
2639 }
2640
2641 static gboolean
2642 settings_update_fontconfig (GtkSettings *settings)
2643 {
2644 #ifdef GDK_WINDOWING_X11
2645   static guint    last_update_timestamp;
2646   static gboolean last_update_needed;
2647
2648   guint timestamp;
2649
2650   g_object_get (settings,
2651                 "gtk-fontconfig-timestamp", &timestamp,
2652                 NULL);
2653
2654   /* if timestamp is the same as last_update_timestamp, we already have
2655    * updated fontconig on this timestamp (another screen requested it perhaps?),
2656    * just return the cached result.*/
2657
2658   if (timestamp != last_update_timestamp)
2659     {
2660       PangoFontMap *fontmap = pango_cairo_font_map_get_default ();
2661       gboolean update_needed = FALSE;
2662
2663       /* bug 547680 */
2664       if (PANGO_IS_FC_FONT_MAP (fontmap) && !FcConfigUptoDate (NULL))
2665         {
2666           pango_fc_font_map_cache_clear (PANGO_FC_FONT_MAP (fontmap));
2667           if (FcInitReinitialize ())
2668             update_needed = TRUE;
2669         }
2670
2671       last_update_timestamp = timestamp;
2672       last_update_needed = update_needed;
2673     }
2674
2675   return last_update_needed;
2676 #else
2677   return FALSE;
2678 #endif /* GDK_WINDOWING_X11 */
2679 }
2680
2681 static void
2682 settings_update_resolution (GtkSettings *settings)
2683 {
2684   GtkSettingsPrivate *priv = settings->priv;
2685   gint dpi_int;
2686   gdouble dpi;
2687
2688   g_object_get (settings,
2689                 "gtk-xft-dpi", &dpi_int,
2690                 NULL);
2691
2692   if (dpi_int > 0)
2693     dpi = dpi_int / 1024.;
2694   else
2695     dpi = -1.;
2696
2697   gdk_screen_set_resolution (priv->screen, dpi);
2698 }
2699
2700 typedef struct
2701 {
2702   GHashTable *color_hash;
2703   GHashTable *tables[GTK_SETTINGS_SOURCE_APPLICATION + 1];
2704   gchar *lastentry[GTK_SETTINGS_SOURCE_APPLICATION + 1];
2705 } ColorSchemeData;
2706
2707 static void
2708 color_scheme_data_free (ColorSchemeData *data)
2709 {
2710   gint i;
2711
2712   g_hash_table_unref (data->color_hash);
2713
2714   for (i = 0; i <= GTK_SETTINGS_SOURCE_APPLICATION; i++)
2715     {
2716       if (data->tables[i])
2717         g_hash_table_unref (data->tables[i]);
2718       g_free (data->lastentry[i]);
2719     }
2720
2721   g_slice_free (ColorSchemeData, data);
2722 }
2723
2724 static void
2725 settings_update_color_scheme (GtkSettings *settings)
2726 {
2727   if (!g_object_get_data (G_OBJECT (settings), "gtk-color-scheme"))
2728     {
2729       GtkSettingsPrivate *priv = settings->priv;
2730       ColorSchemeData *data;
2731       GValue value = G_VALUE_INIT;
2732
2733       data = g_slice_new0 (ColorSchemeData);
2734       data->color_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
2735                                                 (GDestroyNotify) gdk_color_free);
2736       g_object_set_data_full (G_OBJECT (settings), "gtk-color-scheme",
2737                               data, (GDestroyNotify) color_scheme_data_free);
2738
2739       g_value_init (&value, G_TYPE_STRING);
2740       if (priv->screen && gdk_screen_get_setting (priv->screen, "gtk-color-scheme", &value))
2741         {
2742           merge_color_scheme (settings, &value, GTK_SETTINGS_SOURCE_XSETTING);
2743           g_value_unset (&value);
2744         }
2745    }
2746 }
2747
2748 static void
2749 settings_update_provider (GdkScreen       *screen,
2750                           GtkCssProvider **old,
2751                           GtkCssProvider  *new)
2752 {
2753   if (*old != new)
2754     {
2755       if (*old)
2756         {
2757           gtk_style_context_remove_provider_for_screen (screen,
2758                                                         GTK_STYLE_PROVIDER (*old));
2759           g_object_unref (*old);
2760           *old = NULL;
2761         }
2762
2763       if (new)
2764         {
2765           gtk_style_context_add_provider_for_screen (screen,
2766                                                      GTK_STYLE_PROVIDER (new),
2767                                                      GTK_STYLE_PROVIDER_PRIORITY_THEME);
2768           *old = g_object_ref (new);
2769         }
2770     }
2771 }
2772
2773 static void
2774 settings_update_theme (GtkSettings *settings)
2775 {
2776   GtkSettingsPrivate *priv = settings->priv;
2777   GtkCssProvider *provider = NULL;
2778   gboolean prefer_dark_theme;
2779   gchar *theme_name;
2780
2781   g_object_get (settings,
2782                 "gtk-theme-name", &theme_name,
2783                 "gtk-application-prefer-dark-theme", &prefer_dark_theme,
2784                 NULL);
2785
2786   if (theme_name && *theme_name)
2787     {
2788       if (prefer_dark_theme)
2789         provider = gtk_css_provider_get_named (theme_name, "dark");
2790
2791       if (!provider)
2792         provider = gtk_css_provider_get_named (theme_name, NULL);
2793     }
2794
2795   settings_update_provider (priv->screen, &priv->theme_provider, provider);
2796
2797   if (theme_name && *theme_name)
2798     {
2799       gchar *theme_dir;
2800       gchar *path;
2801
2802       /* reload per-theme settings */
2803       theme_dir = _gtk_css_provider_get_theme_dir ();
2804       path = g_build_filename (theme_dir, theme_name, "gtk-3.0", "settings.ini", NULL);
2805
2806      if (g_file_test (path, G_FILE_TEST_EXISTS))
2807        gtk_settings_load_from_key_file (settings, path, GTK_SETTINGS_SOURCE_THEME);
2808
2809       g_free (theme_dir);
2810       g_free (path);
2811     }
2812
2813   g_free (theme_name);
2814 }
2815
2816 static void
2817 settings_update_key_theme (GtkSettings *settings)
2818 {
2819   GtkSettingsPrivate *priv = settings->priv;
2820   GtkCssProvider *provider = NULL;
2821   gchar *key_theme_name;
2822
2823   g_object_get (settings,
2824                 "gtk-key-theme-name", &key_theme_name,
2825                 NULL);
2826
2827   if (key_theme_name && *key_theme_name)
2828     provider = gtk_css_provider_get_named (key_theme_name, "keys");
2829
2830   settings_update_provider (priv->screen, &priv->key_theme_provider, provider);
2831   g_free (key_theme_name);
2832 }
2833
2834 static gboolean
2835 add_color_to_hash (gchar      *name,
2836                    GdkColor   *color,
2837                    GHashTable *target)
2838 {
2839   GdkColor *old;
2840
2841   old = g_hash_table_lookup (target, name);
2842   if (!old || !gdk_color_equal (old, color))
2843     {
2844       g_hash_table_insert (target, g_strdup (name), gdk_color_copy (color));
2845
2846       return TRUE;
2847     }
2848
2849   return FALSE;
2850 }
2851
2852 static gboolean
2853 add_colors_to_hash_from_string (GHashTable  *hash,
2854                                 const gchar *colors)
2855 {
2856   gchar *s, *p, *name;
2857   GdkColor color;
2858   gboolean changed = FALSE;
2859   gchar *copy;
2860
2861   copy = g_strdup (colors);
2862   s = copy;
2863   while (s && *s)
2864     {
2865       name = s;
2866       p = strchr (s, ':');
2867       if (p)
2868         {
2869           *p = '\0';
2870           p++;
2871         }
2872       else
2873         break;
2874
2875       while (*p == ' ')
2876         p++;
2877
2878       s = p;
2879       while (*s)
2880         {
2881           if (*s == '\n' || *s == ';')
2882             {
2883               *s = '\0';
2884               s++;
2885               break;
2886             }
2887           s++;
2888         }
2889
2890       if (gdk_color_parse (p, &color))
2891         changed |= add_color_to_hash (name, &color, hash);
2892     }
2893
2894   g_free (copy);
2895
2896   return changed;
2897 }
2898
2899 static gboolean
2900 update_color_hash (ColorSchemeData   *data,
2901                    const gchar       *str,
2902                    GtkSettingsSource  source)
2903 {
2904   gboolean changed = FALSE;
2905   gint i;
2906   GHashTable *old_hash;
2907   GHashTableIter iter;
2908   gpointer name;
2909   gpointer color;
2910
2911   if ((str == NULL || *str == '\0') &&
2912       (data->lastentry[source] == NULL || data->lastentry[source][0] == '\0'))
2913     return FALSE;
2914
2915   if (str && data->lastentry[source] && strcmp (str, data->lastentry[source]) == 0)
2916     return FALSE;
2917
2918   /* For the THEME source we merge the values rather than over-writing
2919    * them, since multiple rc files might define independent sets of colors
2920    */
2921   if ((source != GTK_SETTINGS_SOURCE_THEME) &&
2922       data->tables[source] && g_hash_table_size (data->tables[source]) > 0)
2923     {
2924       g_hash_table_unref (data->tables[source]);
2925       data->tables[source] = NULL;
2926       changed = TRUE; /* We can't rely on the code below since str might be "" */
2927     }
2928
2929   if (data->tables[source] == NULL)
2930     data->tables[source] = g_hash_table_new_full (g_str_hash, g_str_equal,
2931                                                   g_free,
2932                                                   (GDestroyNotify) gdk_color_free);
2933
2934   g_free (data->lastentry[source]);
2935   data->lastentry[source] = g_strdup (str);
2936
2937   changed |= add_colors_to_hash_from_string (data->tables[source], str);
2938
2939   if (!changed)
2940     return FALSE;
2941
2942   /* Rebuild the merged hash table. */
2943   if (data->color_hash)
2944     {
2945       old_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
2946                                         (GDestroyNotify) gdk_color_free);
2947
2948       g_hash_table_iter_init (&iter, data->color_hash);
2949       while (g_hash_table_iter_next (&iter, &name, &color))
2950         {
2951           g_hash_table_insert (old_hash, name, color);
2952           g_hash_table_iter_steal (&iter);
2953         }
2954     }
2955   else
2956     {
2957       old_hash = NULL;
2958     }
2959
2960   for (i = 0; i <= GTK_SETTINGS_SOURCE_APPLICATION; i++)
2961     {
2962       if (data->tables[i])
2963         g_hash_table_foreach (data->tables[i], (GHFunc) add_color_to_hash,
2964                               data->color_hash);
2965     }
2966
2967   if (old_hash)
2968     {
2969       /* now check if the merged hash has changed */
2970       changed = FALSE;
2971       if (g_hash_table_size (old_hash) != g_hash_table_size (data->color_hash))
2972         changed = TRUE;
2973       else
2974         {
2975           GHashTableIter iter;
2976           gpointer key, value, new_value;
2977
2978           g_hash_table_iter_init (&iter, old_hash);
2979           while (g_hash_table_iter_next (&iter, &key, &value))
2980             {
2981               new_value = g_hash_table_lookup (data->color_hash, key);
2982               if (!new_value || !gdk_color_equal (value, new_value))
2983                 {
2984                   changed = TRUE;
2985                   break;
2986                 }
2987             }
2988         }
2989
2990       g_hash_table_unref (old_hash);
2991     }
2992   else
2993     changed = TRUE;
2994
2995   return changed;
2996 }
2997
2998 static void
2999 merge_color_scheme (GtkSettings       *settings,
3000                     const GValue      *value,
3001                     GtkSettingsSource  source)
3002 {
3003   ColorSchemeData *data;
3004   const gchar *colors;
3005
3006   g_object_freeze_notify (G_OBJECT (settings));
3007
3008   colors = g_value_get_string (value);
3009
3010   settings_update_color_scheme (settings);
3011
3012   data = (ColorSchemeData *) g_object_get_data (G_OBJECT (settings),
3013                                                 "gtk-color-scheme");
3014
3015   if (update_color_hash (data, colors, source))
3016     g_object_notify (G_OBJECT (settings), "color-hash");
3017
3018   g_object_thaw_notify (G_OBJECT (settings));
3019 }
3020
3021 static GHashTable *
3022 get_color_hash (GtkSettings *settings)
3023 {
3024   ColorSchemeData *data;
3025
3026   settings_update_color_scheme (settings);
3027
3028   data = (ColorSchemeData *)g_object_get_data (G_OBJECT (settings),
3029                                                "gtk-color-scheme");
3030
3031   return data->color_hash;
3032 }
3033
3034 static void
3035 append_color_scheme (gpointer key,
3036                      gpointer value,
3037                      gpointer data)
3038 {
3039   gchar *name = (gchar *)key;
3040   GdkColor *color = (GdkColor *)value;
3041   GString *string = (GString *)data;
3042
3043   g_string_append_printf (string, "%s: #%04x%04x%04x\n",
3044                           name, color->red, color->green, color->blue);
3045 }
3046
3047 static gchar *
3048 get_color_scheme (GtkSettings *settings)
3049 {
3050   ColorSchemeData *data;
3051   GString *string;
3052
3053   settings_update_color_scheme (settings);
3054
3055   data = (ColorSchemeData *) g_object_get_data (G_OBJECT (settings),
3056                                                 "gtk-color-scheme");
3057
3058   string = g_string_new ("");
3059
3060   g_hash_table_foreach (data->color_hash, append_color_scheme, string);
3061
3062   return g_string_free (string, FALSE);
3063 }
3064
3065 GdkScreen *
3066 _gtk_settings_get_screen (GtkSettings *settings)
3067 {
3068   return settings->priv->screen;
3069 }
3070
3071
3072 static void
3073 gtk_settings_load_from_key_file (GtkSettings       *settings,
3074                                  const gchar       *path,
3075                                  GtkSettingsSource  source)
3076 {
3077   GError *error;
3078   GKeyFile *keyfile;
3079   gchar **keys;
3080   gsize n_keys;
3081   gint i;
3082
3083   error = NULL;
3084   keys = NULL;
3085
3086   keyfile = g_key_file_new ();
3087
3088   if (!g_key_file_load_from_file (keyfile, path, G_KEY_FILE_NONE, &error))
3089     {
3090       g_warning ("Failed to parse %s: %s", path, error->message);
3091
3092       g_error_free (error);
3093
3094       goto out;
3095     }
3096
3097   keys = g_key_file_get_keys (keyfile, "Settings", &n_keys, &error);
3098   if (error)
3099     {
3100       g_warning ("Failed to parse %s: %s", path, error->message);
3101       g_error_free (error);
3102       goto out;
3103     }
3104
3105   for (i = 0; i < n_keys; i++)
3106     {
3107       gchar *key;
3108       GParamSpec *pspec;
3109       GType value_type;
3110       GtkSettingsValue svalue = { NULL, { 0, }, };
3111
3112       key = keys[i];
3113       pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (settings), key);
3114       if (!pspec)
3115         {
3116           g_warning ("Unknown key %s in %s", key, path);
3117           continue;
3118         }
3119
3120       if (pspec->owner_type != G_OBJECT_TYPE (settings))
3121         continue;
3122
3123       value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
3124       switch (value_type)
3125         {
3126         case G_TYPE_BOOLEAN:
3127           {
3128             gboolean b_val;
3129
3130             g_value_init (&svalue.value, G_TYPE_LONG);
3131             b_val = g_key_file_get_boolean (keyfile, "Settings", key, &error);
3132             if (!error)
3133               g_value_set_long (&svalue.value, b_val);
3134             break;
3135           }
3136
3137         case G_TYPE_INT:
3138           {
3139             gint i_val;
3140
3141             g_value_init (&svalue.value, G_TYPE_LONG);
3142             i_val = g_key_file_get_integer (keyfile, "Settings", key, &error);
3143             if (!error)
3144               g_value_set_long (&svalue.value, i_val);
3145             break;
3146           }
3147
3148         case G_TYPE_DOUBLE:
3149           {
3150             gdouble d_val;
3151
3152             g_value_init (&svalue.value, G_TYPE_DOUBLE);
3153             d_val = g_key_file_get_double (keyfile, "Settings", key, &error);
3154             if (!error)
3155               g_value_set_double (&svalue.value, d_val);
3156             break;
3157           }
3158
3159         default:
3160           {
3161             gchar *s_val;
3162
3163             g_value_init (&svalue.value, G_TYPE_GSTRING);
3164             s_val = g_key_file_get_string (keyfile, "Settings", key, &error);
3165             if (!error)
3166               g_value_take_boxed (&svalue.value, g_string_new (s_val));
3167             g_free (s_val);
3168             break;
3169           }
3170         }
3171       if (error)
3172         {
3173           g_warning ("Error setting %s in %s: %s", key, path, error->message);
3174           g_error_free (error);
3175           error = NULL;
3176         }
3177       else
3178         {
3179           if (g_getenv ("GTK_DEBUG"))
3180             svalue.origin = (gchar *)path;
3181           gtk_settings_set_property_value_internal (settings, key, &svalue, source);
3182           g_value_unset (&svalue.value);
3183         }
3184     }
3185
3186  out:
3187   g_strfreev (keys);
3188   g_key_file_free (keyfile);
3189 }