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