]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtksettings.c
Remove GtkObject completely
[~andy/gtk] / gtk / gtksettings.c
index 17f96a6dd2688ff76913eb41073e0b30dcd5bfd9..9152c33f1fd156952a38d2563ad294d9a9d8164f 100644 (file)
@@ -16,7 +16,9 @@
  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <config.h>
+#define PANGO_ENABLE_BACKEND /* for pango_fc_font_map_cache_clear() */
+
+#include "config.h"
 
 #include <string.h>
 
 #include "gtkrc.h"
 #include "gtkintl.h"
 #include "gtkwidget.h"
+#include "gtktypeutils.h"
 #include "gtkprivate.h"
-#include "gtkalias.h"
 
 #ifdef GDK_WINDOWING_X11
 #include "x11/gdkx.h"
+#include <pango/pangofc-fontmap.h>
+#endif
+
+#ifdef GDK_WINDOWING_QUARTZ
+#define DEFAULT_KEY_THEME "Mac"
+#else
+#define DEFAULT_KEY_THEME NULL
 #endif
 
 #define DEFAULT_TIMEOUT_INITIAL 200
@@ -64,6 +73,7 @@ enum {
   PROP_DOUBLE_CLICK_DISTANCE,
   PROP_CURSOR_BLINK,
   PROP_CURSOR_BLINK_TIME,
+  PROP_CURSOR_BLINK_TIMEOUT,
   PROP_SPLIT_CURSOR,
   PROP_THEME_NAME,
   PROP_ICON_THEME_NAME,
@@ -84,6 +94,7 @@ enum {
   PROP_CURSOR_THEME_SIZE,
 #endif
   PROP_ALTERNATIVE_BUTTON_ORDER,
+  PROP_ALTERNATIVE_SORT_ARROWS,
   PROP_SHOW_INPUT_METHOD_MENU,
   PROP_SHOW_UNICODE_MENU,
   PROP_TIMEOUT_INITIAL,
@@ -92,7 +103,30 @@ enum {
   PROP_COLOR_SCHEME,
   PROP_ENABLE_ANIMATIONS,
   PROP_TOUCHSCREEN_MODE,
-  PROP_COLOR_HASH
+  PROP_TOOLTIP_TIMEOUT,
+  PROP_TOOLTIP_BROWSE_TIMEOUT,
+  PROP_TOOLTIP_BROWSE_MODE_TIMEOUT,
+  PROP_KEYNAV_CURSOR_ONLY,
+  PROP_KEYNAV_WRAP_AROUND,
+  PROP_ERROR_BELL,
+  PROP_COLOR_HASH,
+  PROP_FILE_CHOOSER_BACKEND,
+  PROP_PRINT_BACKENDS,
+  PROP_PRINT_PREVIEW_COMMAND,
+  PROP_ENABLE_MNEMONICS,
+  PROP_ENABLE_ACCELS,
+  PROP_RECENT_FILES_LIMIT,
+  PROP_IM_MODULE,
+  PROP_RECENT_FILES_MAX_AGE,
+  PROP_FONTCONFIG_TIMESTAMP,
+  PROP_SOUND_THEME_NAME,
+  PROP_ENABLE_INPUT_FEEDBACK_SOUNDS,
+  PROP_ENABLE_EVENT_SOUNDS,
+  PROP_ENABLE_TOOLTIPS,
+  PROP_TOOLBAR_STYLE,
+  PROP_TOOLBAR_ICON_SIZE,
+  PROP_AUTO_MNEMONICS,
+  PROP_APPLICATION_PREFER_DARK_THEME
 };
 
 
@@ -118,11 +152,12 @@ static void    settings_update_modules           (GtkSettings           *setting
 static void    settings_update_cursor_theme      (GtkSettings           *settings);
 static void    settings_update_resolution        (GtkSettings           *settings);
 static void    settings_update_font_options      (GtkSettings           *settings);
+static gboolean settings_update_fontconfig       (GtkSettings           *settings);
 #endif
 static void    settings_update_color_scheme      (GtkSettings *settings);
 
 static void    merge_color_scheme                (GtkSettings           *settings, 
-                                                 GValue                *value, 
+                                                 const GValue          *value, 
                                                  GtkSettingsSource      source);
 static gchar  *get_color_scheme                  (GtkSettings           *settings);
 static GHashTable *get_color_hash                (GtkSettings           *settings);
@@ -134,7 +169,7 @@ static GSList           *object_list = NULL;
 static guint            class_n_properties = 0;
 
 
-G_DEFINE_TYPE (GtkSettings, gtk_settings, G_TYPE_OBJECT);
+G_DEFINE_TYPE (GtkSettings, gtk_settings, G_TYPE_OBJECT)
 
 /* --- functions --- */
 static void
@@ -201,6 +236,15 @@ gtk_settings_class_init (GtkSettingsClass *class)
                                                                GTK_PARAM_READWRITE),
                                              NULL);
   g_assert (result == PROP_DOUBLE_CLICK_DISTANCE);
+
+  /**
+   * GtkSettings:gtk-cursor-blink:
+   *
+   * Whether the cursor should blink. 
+   *
+   * Also see the #GtkSettings:gtk-cursor-blink-timeout setting, 
+   * which allows more flexible control over cursor blinking.
+   */
   result = settings_install_property_parser (class,
                                              g_param_spec_boolean ("gtk-cursor-blink",
                                                                   P_("Cursor Blink"),
@@ -212,11 +256,31 @@ gtk_settings_class_init (GtkSettingsClass *class)
   result = settings_install_property_parser (class,
                                              g_param_spec_int ("gtk-cursor-blink-time",
                                                                P_("Cursor Blink Time"),
-                                                               P_("Length of the cursor blink cycle, in milleseconds"),
+                                                               P_("Length of the cursor blink cycle, in milliseconds"),
                                                                100, G_MAXINT, 1200,
                                                                GTK_PARAM_READWRITE),
                                              NULL);
   g_assert (result == PROP_CURSOR_BLINK_TIME);
+  /**
+   * GtkSettings:gtk-cursor-blink-timeout:
+   *
+   * Time after which the cursor stops blinking, in seconds.
+   * The timer is reset after each user interaction.
+   *
+   * Setting this to zero has the same effect as setting
+   * #GtkSettings:gtk-cursor-blink to %FALSE. 
+   *
+   * Since: 2.12
+   */
+  result = settings_install_property_parser (class,
+                                             g_param_spec_int ("gtk-cursor-blink-timeout",
+                                                               P_("Cursor Blink Timeout"),
+                                                               P_("Time after which the cursor stops blinking, in seconds"),
+                                                               1, G_MAXINT, G_MAXINT,
+                                                               GTK_PARAM_READWRITE),
+                                             NULL);
+  g_assert (result == PROP_CURSOR_BLINK_TIMEOUT);
   result = settings_install_property_parser (class,
                                              g_param_spec_boolean ("gtk-split-cursor",
                                                                   P_("Split Cursor"),
@@ -256,7 +320,7 @@ gtk_settings_class_init (GtkSettingsClass *class)
                                              g_param_spec_string ("gtk-key-theme-name",
                                                                  P_("Key Theme Name"),
                                                                  P_("Name of key theme RC file to load"),
-                                                                 NULL,
+                                                                 DEFAULT_KEY_THEME,
                                                                  GTK_PARAM_READWRITE),
                                              NULL);
   g_assert (result == PROP_KEY_THEME_NAME);    
@@ -288,6 +352,20 @@ gtk_settings_class_init (GtkSettingsClass *class)
                                              NULL);
   g_assert (result == PROP_FONT_NAME);
 
+  /**
+   * GtkSettings:gtk-icon-sizes:
+   *
+   * A list of icon sizes. The list is separated by colons, and
+   * item has the form:
+   *
+   * <replaceable>size-name</replaceable> = <replaceable>width</replaceable> , <replaceable>height</replaceable>
+   *
+   * E.g. "gtk-menu=16,16:gtk-button=20,20:gtk-dialog=48,48". 
+   * GTK+ itself use the following named icon sizes: gtk-menu, 
+   * gtk-button, gtk-small-toolbar, gtk-large-toolbar, gtk-dnd, 
+   * gtk-dialog. Applications can register their own named icon 
+   * sizes with gtk_icon_size_register().
+   */
   result = settings_install_property_parser (class,
                                              g_param_spec_string ("gtk-icon-sizes",
                                                                   P_("Icon Sizes"),
@@ -386,6 +464,24 @@ gtk_settings_class_init (GtkSettingsClass *class)
                                              NULL);
   g_assert (result == PROP_ALTERNATIVE_BUTTON_ORDER);
 
+  /**
+   * GtkSettings:gtk-alternative-sort-arrows:
+   *
+   * Controls the direction of the sort indicators in sorted list and tree
+   * views. By default an arrow pointing down means the column is sorted
+   * in ascending order. When set to %TRUE, this order will be inverted.
+   *
+   * Since: 2.12
+   */
+  result = settings_install_property_parser (class,
+                                             g_param_spec_boolean ("gtk-alternative-sort-arrows",
+                                                                  P_("Alternative sort indicator direction"),
+                                                                  P_("Whether the direction of the sort indicators in list and tree views is inverted compared to the default (where down means ascending)"),
+                                                                  FALSE,
+                                                                  GTK_PARAM_READWRITE),
+                                             NULL);
+  g_assert (result == PROP_ALTERNATIVE_SORT_ARROWS);
+
   result = settings_install_property_parser (class,
                                             g_param_spec_boolean ("gtk-show-input-method-menu",
                                                                   P_("Show the 'Input Methods' menu"),
@@ -452,6 +548,12 @@ gtk_settings_class_init (GtkSettingsClass *class)
    * merged, color specifications will be converted to hexadecimal form
    * when getting this property.
    *
+   * Starting with GTK+ 2.12, the entries can alternatively be separated
+   * by ';' instead of newlines:
+   * <programlisting>
+   * name1: color1; name2: color2; ...
+   * </programlisting>
+   *
    * Since: 2.10
    */
   result = settings_install_property_parser (class,
@@ -477,7 +579,7 @@ gtk_settings_class_init (GtkSettingsClass *class)
   /**
    * GtkSettings:gtk-touchscreen-mode:
    *
-   * When TRUE, there are no motion notify events delivered on this screen,
+   * When %TRUE, there are no motion notify events delivered on this screen,
    * and widgets can't use the pointer hovering them for any essential
    * functionality.
    *
@@ -493,23 +595,455 @@ gtk_settings_class_init (GtkSettingsClass *class)
 
   g_assert (result == PROP_TOUCHSCREEN_MODE);
 
+  /**
+   * GtkSettings:gtk-tooltip-timeout:
+   *
+   * Time, in milliseconds, after which a tooltip could appear if the
+   * cursor is hovering on top of a widget.
+   *
+   * Since: 2.12
+   */
+  result = settings_install_property_parser (class,
+                                            g_param_spec_int ("gtk-tooltip-timeout",
+                                                              P_("Tooltip timeout"),
+                                                              P_("Timeout before tooltip is shown"),
+                                                              0, G_MAXINT,
+                                                              500,
+                                                              GTK_PARAM_READWRITE),
+                                            NULL);
+
+  g_assert (result == PROP_TOOLTIP_TIMEOUT);
+
+  /**
+   * GtkSettings:gtk-tooltip-browse-timeout:
+   *
+   * Controls the time after which tooltips will appear when
+   * browse mode is enabled, in milliseconds.
+   *
+   * Browse mode is enabled when the mouse pointer moves off an object
+   * where a tooltip was currently being displayed. If the mouse pointer
+   * hits another object before the browse mode timeout expires (see
+   * #GtkSettings:gtk-tooltip-browse-mode-timeout), it will take the 
+   * amount of milliseconds specified by this setting to popup the tooltip
+   * for the new object.
+   *
+   * Since: 2.12
+   */
+  result = settings_install_property_parser (class,
+                                            g_param_spec_int ("gtk-tooltip-browse-timeout",
+                                                              P_("Tooltip browse timeout"),
+                                                              P_("Timeout before tooltip is shown when browse mode is enabled"),
+                                                              0, G_MAXINT,
+                                                              60,
+                                                              GTK_PARAM_READWRITE),
+                                            NULL);
+
+  g_assert (result == PROP_TOOLTIP_BROWSE_TIMEOUT);
+
+  /**
+   * GtkSettings:gtk-tooltip-browse-mode-timeout:
+   *
+   * Amount of time, in milliseconds, after which the browse mode
+   * will be disabled.
+   *
+   * See #GtkSettings:gtk-tooltip-browse-timeout for more information
+   * about browse mode.
+   *
+   * Since: 2.12
+   */
+  result = settings_install_property_parser (class,
+                                            g_param_spec_int ("gtk-tooltip-browse-mode-timeout",
+                                                              P_("Tooltip browse mode timeout"),
+                                                              P_("Timeout after which browse mode is disabled"),
+                                                              0, G_MAXINT,
+                                                              500,
+                                                              GTK_PARAM_READWRITE),
+                                            NULL);
+
+  g_assert (result == PROP_TOOLTIP_BROWSE_MODE_TIMEOUT);
+
+  /**
+   * GtkSettings:gtk-keynav-cursor-only:
+   *
+   * When %TRUE, keyboard navigation should be able to reach all widgets
+   * by using the cursor keys only. Tab, Shift etc. keys can't be expected
+   * to be present on the used input device.
+   *
+   * Since: 2.12
+   */
+  result = settings_install_property_parser (class,
+                                             g_param_spec_boolean ("gtk-keynav-cursor-only",
+                                                                   P_("Keynav Cursor Only"),
+                                                                   P_("When TRUE, there are only cursor keys available to navigate widgets"),
+                                                                   FALSE,
+                                                                   GTK_PARAM_READWRITE),
+                                             NULL);
+
+  g_assert (result == PROP_KEYNAV_CURSOR_ONLY);
+
+  /**
+   * GtkSettings:gtk-keynav-wrap-around:
+   *
+   * When %TRUE, some widgets will wrap around when doing keyboard
+   * navigation, such as menus, menubars and notebooks.
+   *
+   * Since: 2.12
+   */
+  result = settings_install_property_parser (class,
+                                             g_param_spec_boolean ("gtk-keynav-wrap-around",
+                                                                   P_("Keynav Wrap Around"),
+                                                                   P_("Whether to wrap around when keyboard-navigating widgets"),
+                                                                   TRUE,
+                                                                   GTK_PARAM_READWRITE),
+                                             NULL);
+
+  g_assert (result == PROP_KEYNAV_WRAP_AROUND);
+
+  /**
+   * GtkSettings:gtk-error-bell:
+   *
+   * When %TRUE, keyboard navigation and other input-related errors
+   * will cause a beep. Since the error bell is implemented using
+   * gdk_window_beep(), the windowing system may offer ways to
+   * configure the error bell in many ways, such as flashing the
+   * window or similar visual effects.
+   *
+   * Since: 2.12
+   */
+  result = settings_install_property_parser (class,
+                                             g_param_spec_boolean ("gtk-error-bell",
+                                                                   P_("Error Bell"),
+                                                                   P_("When TRUE, keyboard navigation and other errors will cause a beep"),
+                                                                   TRUE,
+                                                                   GTK_PARAM_READWRITE),
+                                             NULL);
+
+  g_assert (result == PROP_ERROR_BELL);
+
   /**
    * GtkSettings:color-hash:
    *
-   * Holds a hash table representation of the gtk-color-scheme setting,
-   * mapping color names to #GdkColor<!-- -->s. 
+   * Holds a hash table representation of the #GtkSettings:gtk-color-scheme 
+   * setting, mapping color names to #GdkColor<!-- -->s. 
+   *
+   * Since: 2.10
+   */
+  result = settings_install_property_parser (class, 
+                                             g_param_spec_boxed ("color-hash",
+                                                                 P_("Color Hash"),
+                                                                 P_("A hash table representation of the color scheme."),
+                                                                 G_TYPE_HASH_TABLE,
+                                                                 GTK_PARAM_READABLE),
+                                             NULL);
+  g_assert (result == PROP_COLOR_HASH);
+
+  result = settings_install_property_parser (class, 
+                                             g_param_spec_string ("gtk-file-chooser-backend",
+                                                                  P_("Default file chooser backend"),
+                                                                  P_("Name of the GtkFileChooser backend to use by default"),
+                                                                  NULL,
+                                                                  GTK_PARAM_READWRITE),
+                                             NULL);
+  g_assert (result == PROP_FILE_CHOOSER_BACKEND);
+
+  /**
+   * GtkSettings:gtk-print-backends:
+   *
+   * A comma-separated list of print backends to use in the print
+   * dialog. Available print backends depend on the GTK+ installation,
+   * and may include "file", "cups", "lpr" or "papi".
    *
    * Since: 2.10
    */
-  g_object_class_install_property (gobject_class,
-                                  PROP_COLOR_HASH,
-                                  g_param_spec_boxed ("color-hash",
-                                                      P_("Color Hash"),
-                                                      P_("A hash table representation of the color scheme."),
-                                                      G_TYPE_HASH_TABLE,
-                                                      GTK_PARAM_READABLE));
-
-  class_n_properties++;
+  result = settings_install_property_parser (class,
+                                             g_param_spec_string ("gtk-print-backends",
+                                                                  P_("Default print backend"),
+                                                                  P_("List of the GtkPrintBackend backends to use by default"),
+                                                                  GTK_PRINT_BACKENDS,
+                                                                  GTK_PARAM_READWRITE),
+                                             NULL);
+  g_assert (result == PROP_PRINT_BACKENDS);
+
+  /**
+   * GtkSettings:gtk-print-preview-command:
+   *
+   * A command to run for displaying the print preview. The command
+   * should contain a %f placeholder, which will get replaced by
+   * the path to the pdf file. The command may also contain a %s
+   * placeholder, which will get replaced by the path to a file
+   * containing the print settings in the format produced by 
+   * gtk_print_settings_to_file().
+   *
+   * The preview application is responsible for removing the pdf file
+   * and the print settings file when it is done.
+   *
+   * Since: 2.10
+   */
+  result = settings_install_property_parser (class,
+                                             g_param_spec_string ("gtk-print-preview-command",
+                                                                  P_("Default command to run when displaying a print preview"),
+                                                                  P_("Command to run when displaying a print preview"),
+                                                                  GTK_PRINT_PREVIEW_COMMAND,
+                                                                  GTK_PARAM_READWRITE),
+                                             NULL); 
+  g_assert (result == PROP_PRINT_PREVIEW_COMMAND);
+
+  /**
+   * GtkSettings:gtk-enable-mnemonics:
+   *
+   * Whether labels and menu items should have visible mnemonics which
+   * can be activated.
+   *
+   * Since: 2.12
+   */
+  result = settings_install_property_parser (class,
+                                             g_param_spec_boolean ("gtk-enable-mnemonics",
+                                                                   P_("Enable Mnemonics"),
+                                                                   P_("Whether labels should have mnemonics"),
+                                                                   TRUE,
+                                                                   GTK_PARAM_READWRITE),
+                                             NULL);
+  g_assert (result == PROP_ENABLE_MNEMONICS);
+
+  /**
+   * GtkSettings:gtk-enable-accels:
+   *
+   * Whether menu items should have visible accelerators which can be
+   * activated.
+   *
+   * Since: 2.12
+   */
+  result = settings_install_property_parser (class,
+                                             g_param_spec_boolean ("gtk-enable-accels",
+                                                                   P_("Enable Accelerators"),
+                                                                   P_("Whether menu items should have accelerators"),
+                                                                   TRUE,
+                                                                   GTK_PARAM_READWRITE),
+                                             NULL);
+  g_assert (result == PROP_ENABLE_ACCELS);
+
+  /**
+   * GtkSettings:gtk-recent-files-limit:
+   *
+   * The number of recently used files that should be displayed by default by
+   * #GtkRecentChooser implementations and by the #GtkFileChooser. A value of
+   * -1 means every recently used file stored.
+   *
+   * Since: 2.12
+   */
+  result = settings_install_property_parser (class,
+                                            g_param_spec_int ("gtk-recent-files-limit",
+                                                              P_("Recent Files Limit"),
+                                                              P_("Number of recently used files"),
+                                                              -1, G_MAXINT,
+                                                              50,
+                                                              GTK_PARAM_READWRITE),
+                                            NULL);
+  g_assert (result == PROP_RECENT_FILES_LIMIT);
+
+  /**
+   * GtkSettings:gtk-im-module:
+   *
+   * Which IM (input method) module should be used by default. This is the 
+   * input method that will be used if the user has not explicitly chosen 
+   * another input method from the IM context menu.  
+   *
+   * See #GtkIMContext and see the #GtkSettings:gtk-show-input-method-menu property.
+   */
+  result = settings_install_property_parser (class,
+                                            g_param_spec_string ("gtk-im-module",
+                                                                 P_("Default IM module"),
+                                                                 P_("Which IM module should be used by default"),
+                                                                 NULL,
+                                                                 GTK_PARAM_READWRITE),
+                                            NULL);
+  g_assert (result == PROP_IM_MODULE);
+
+  /**
+   * GtkSettings:gtk-recent-files-max-age:
+   *
+   * The maximum age, in days, of the items inside the recently used
+   * resources list. Items older than this setting will be excised
+   * from the list. If set to 0, the list will always be empty; if
+   * set to -1, no item will be removed.
+   *
+   * Since: 2.14
+   */
+  result = settings_install_property_parser (class,
+                                            g_param_spec_int ("gtk-recent-files-max-age",
+                                                              P_("Recent Files Max Age"),
+                                                              P_("Maximum age of recently used files, in days"),
+                                                              -1, G_MAXINT,
+                                                              30,
+                                                              GTK_PARAM_READWRITE),
+                                            NULL);
+  g_assert (result == PROP_RECENT_FILES_MAX_AGE);
+
+  result = settings_install_property_parser (class,
+                                            g_param_spec_uint ("gtk-fontconfig-timestamp",
+                                                               P_("Fontconfig configuration timestamp"),
+                                                               P_("Timestamp of current fontconfig configuration"),
+                                                               0, G_MAXUINT, 0,
+                                                               GTK_PARAM_READWRITE),
+                                            NULL);
+  
+  g_assert (result == PROP_FONTCONFIG_TIMESTAMP);
+
+  /**
+   * GtkSettings:gtk-sound-theme-name:
+   *
+   * The XDG sound theme to use for event sounds.
+   *
+   * See the <ulink url="http://www.freedesktop.org/wiki/Specifications/sound-theme-spec">Sound Theme spec</ulink> 
+   * for more information on event sounds and sound themes.
+   *
+   * GTK+ itself does not support event sounds, you have to use a loadable 
+   * module like the one that comes with libcanberra.
+   *
+   * Since: 2.14
+   */
+  result = settings_install_property_parser (class,
+                                             g_param_spec_string ("gtk-sound-theme-name",
+                                                                  P_("Sound Theme Name"),
+                                                                  P_("XDG sound theme name"),
+                                                                  "freedesktop",
+                                                                  GTK_PARAM_READWRITE),
+                                             NULL);
+  g_assert (result == PROP_SOUND_THEME_NAME);
+
+  /**
+   * GtkSettings:gtk-enable-input-feedback-sounds:
+   *
+   * Whether to play event sounds as feedback to user input.
+   *
+   * See the <ulink url="http://www.freedesktop.org/wiki/Specifications/sound-theme-spec">Sound Theme spec</ulink> 
+   * for more information on event sounds and sound themes.
+   *
+   * GTK+ itself does not support event sounds, you have to use a loadable 
+   * module like the one that comes with libcanberra.
+   *
+   * Since: 2.14
+   */
+  result = settings_install_property_parser (class,
+                                             g_param_spec_boolean ("gtk-enable-input-feedback-sounds",
+                                                                   /* Translators: this means sounds that are played as feedback to user input */
+                                                                  P_("Audible Input Feedback"),
+                                                                  P_("Whether to play event sounds as feedback to user input"),
+                                                                  TRUE,
+                                                                  GTK_PARAM_READWRITE),
+                                             NULL);
+  g_assert (result == PROP_ENABLE_INPUT_FEEDBACK_SOUNDS);
+
+  /**
+   * GtkSettings:gtk-enable-event-sounds:
+   *
+   * Whether to play any event sounds at all.
+   *
+   * See the <ulink url="http://www.freedesktop.org/wiki/Specifications/sound-theme-spec">Sound Theme spec</ulink> 
+   * for more information on event sounds and sound themes.
+   *
+   * GTK+ itself does not support event sounds, you have to use a loadable 
+   * module like the one that comes with libcanberra.
+   *
+   * Since: 2.14
+   */
+  result = settings_install_property_parser (class,
+                                             g_param_spec_boolean ("gtk-enable-event-sounds",
+                                                                  P_("Enable Event Sounds"),
+                                                                  P_("Whether to play any event sounds at all"),
+                                                                  TRUE,
+                                                                  GTK_PARAM_READWRITE),
+                                             NULL);
+  g_assert (result == PROP_ENABLE_EVENT_SOUNDS);
+
+  /**
+   * GtkSettings:gtk-enable-tooltips:
+   *
+   * Whether tooltips should be shown on widgets.
+   *
+   * Since: 2.14
+   */
+  result = settings_install_property_parser (class,
+                                             g_param_spec_boolean ("gtk-enable-tooltips",
+                                                                   P_("Enable Tooltips"),
+                                                                   P_("Whether tooltips should be shown on widgets"),
+                                                                   TRUE,
+                                                                   GTK_PARAM_READWRITE),
+                                             NULL);
+  g_assert (result == PROP_ENABLE_TOOLTIPS);
+
+  /**
+   * GtkSettings:toolbar-style:
+   *
+   * The size of icons in default toolbars.
+   */
+  result = settings_install_property_parser (class,
+                                             g_param_spec_enum ("gtk-toolbar-style",
+                                                                   P_("Toolbar style"),
+                                                                   P_("Whether default toolbars have text only, text and icons, icons only, etc."),
+                                                                   GTK_TYPE_TOOLBAR_STYLE,
+                                                                   GTK_TOOLBAR_BOTH,
+                                                                   GTK_PARAM_READWRITE),
+                                             gtk_rc_property_parse_enum);
+  g_assert (result == PROP_TOOLBAR_STYLE);
+
+  /**
+   * GtkSettings:toolbar-icon-size:
+   *
+   * The size of icons in default toolbars.
+   */
+  result = settings_install_property_parser (class,
+                                             g_param_spec_enum ("gtk-toolbar-icon-size",
+                                                                   P_("Toolbar Icon Size"),
+                                                                   P_("The size of icons in default toolbars."),
+                                                                   GTK_TYPE_ICON_SIZE,
+                                                                   GTK_ICON_SIZE_LARGE_TOOLBAR,
+                                                                   GTK_PARAM_READWRITE),
+                                             gtk_rc_property_parse_enum);
+  g_assert (result == PROP_TOOLBAR_ICON_SIZE);
+
+  /**
+   * GtkSettings:gtk-auto-mnemonics:
+   *
+   * Whether mnemonics should be automatically shown and hidden when the user
+   * presses the mnemonic activator.
+   *
+   * Since: 2.20
+   */
+  result = settings_install_property_parser (class,
+                                             g_param_spec_boolean ("gtk-auto-mnemonics",
+                                                                   P_("Auto Mnemonics"),
+                                                                   P_("Whether mnemonics should be automatically shown and hidden when the user presses the mnemonic activator."),
+                                                                   FALSE,
+                                                                   GTK_PARAM_READWRITE),
+                                             NULL);
+  g_assert (result == PROP_AUTO_MNEMONICS);
+
+  /**
+   * GtkSettings:gtk-application-prefer-dark-theme:
+   *
+   * Whether the application prefers to use a dark theme. If a GTK+ theme
+   * includes a dark variant, it will be used instead of the configured
+   * theme.
+   *
+   * Some applications benefit from minimizing the amount of light pollution that
+   * interferes with the content. Good candidates for dark themes are photo and
+   * video editors that make the actual content get all the attention and minimize
+   * the distraction of the chrome.
+   *
+   * Dark themes should not be used for documents, where large spaces are white/light
+   * and the dark chrome creates too much contrast (web browser, text editor...).
+   *
+   * Since: 2.22
+   */
+  result = settings_install_property_parser (class,
+                                             g_param_spec_boolean ("gtk-application-prefer-dark-theme",
+                                                                 P_("Application prefers a dark theme"),
+                                                                 P_("Whether the application prefers to have a dark theme."),
+                                                                 FALSE,
+                                                                 GTK_PARAM_READWRITE),
+                                             NULL);
+  g_assert (result == PROP_APPLICATION_PREFER_DARK_THEME);
 }
 
 static void
@@ -520,10 +1054,12 @@ gtk_settings_finalize (GObject *object)
 
   object_list = g_slist_remove (object_list, settings);
 
+  _gtk_rc_context_destroy (settings);
+
   for (i = 0; i < class_n_properties; i++)
     g_value_unset (&settings->property_values[i].value);
   g_free (settings->property_values);
-
+  
   g_datalist_clear (&settings->queued_settings);
 
   G_OBJECT_CLASS (gtk_settings_parent_class)->finalize (object);
@@ -531,11 +1067,11 @@ gtk_settings_finalize (GObject *object)
 
 /**
  * gtk_settings_get_for_screen:
- * @screen : a #GdkScreen.
- * 
+ * @screen: a #GdkScreen.
+ *
  * Gets the #GtkSettings object for @screen, creating it if necessary.
  *
- * Return value: a #GtkSettings object.
+ * Return value: (transfer none): a #GtkSettings object.
  *
  * Since: 2.2
  */
@@ -543,15 +1079,16 @@ GtkSettings*
 gtk_settings_get_for_screen (GdkScreen *screen)
 {
   GtkSettings *settings;
-  
+
   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
-  
+
   settings = g_object_get_data (G_OBJECT (screen), "gtk-settings");
   if (!settings)
     {
       settings = g_object_new (GTK_TYPE_SETTINGS, NULL);
       settings->screen = screen;
-      g_object_set_data (G_OBJECT (screen), I_("gtk-settings"), settings);
+      g_object_set_data_full (G_OBJECT (screen), I_("gtk-settings"), 
+                             settings, g_object_unref);
 
       gtk_rc_reparse_all_for_settings (settings, TRUE);
       settings_update_double_click (settings);
@@ -571,8 +1108,8 @@ gtk_settings_get_for_screen (GdkScreen *screen)
  * 
  * Gets the #GtkSettings object for the default GDK screen, creating
  * it if necessary. See gtk_settings_get_for_screen().
- * 
- * Return value: a #GtkSettings object. If there is no default
+ *
+ * Return value: (transfer none): a #GtkSettings object. If there is no default
  *  screen, then returns %NULL.
  **/
 GtkSettings*
@@ -596,6 +1133,9 @@ gtk_settings_set_property (GObject      *object,
 
   g_value_copy (value, &settings->property_values[property_id - 1].value);
   settings->property_values[property_id - 1].source = GTK_SETTINGS_SOURCE_APPLICATION;
+  
+  if (pspec->param_id == PROP_COLOR_SCHEME)
+    merge_color_scheme (settings, value, GTK_SETTINGS_SOURCE_APPLICATION);
 }
 
 static void
@@ -608,10 +1148,16 @@ gtk_settings_get_property (GObject     *object,
   GType value_type = G_VALUE_TYPE (value);
   GType fundamental_type = G_TYPE_FUNDAMENTAL (value_type);
 
-  if (property_id == PROP_COLOR_HASH)
+  /* handle internal properties */
+  switch (property_id)
     {
+    case PROP_COLOR_HASH:
       g_value_set_boxed (value, get_color_hash (settings));
       return;
+    case PROP_COLOR_SCHEME:
+      g_value_take_string (value, get_color_scheme (settings));
+      return;
+    default: ;
     }
 
   /* For enums and strings, we need to get the value as a string,
@@ -627,15 +1173,7 @@ gtk_settings_get_property (GObject     *object,
          !gdk_screen_get_setting (settings->screen, pspec->name, value))
         g_value_copy (&settings->property_values[property_id - 1].value, value);
       else 
-       {
-         if (pspec->param_id == PROP_COLOR_SCHEME)
-           {
-             merge_color_scheme (settings, value, GTK_SETTINGS_SOURCE_XSETTING);
-             g_value_take_string (value, get_color_scheme (settings));
-           }
-         
-         g_param_value_validate (pspec, value);
-       }
+        g_param_value_validate (pspec, value);
     }
   else
     {
@@ -719,6 +1257,10 @@ gtk_settings_notify (GObject    *object,
       settings_update_font_options (settings);
       gtk_rc_reset_styles (GTK_SETTINGS (object));
       break;
+    case PROP_FONTCONFIG_TIMESTAMP:
+      if (settings_update_fontconfig (settings))
+       gtk_rc_reset_styles (GTK_SETTINGS (object));
+      break;
     case PROP_CURSOR_THEME_NAME:
     case PROP_CURSOR_THEME_SIZE:
       settings_update_cursor_theme (settings);
@@ -807,24 +1349,22 @@ apply_queued_setting (GtkSettings             *data,
                                   pspec, &tmp_value))
     {
       if (pspec->param_id == PROP_COLOR_SCHEME) 
+        merge_color_scheme (data, &tmp_value, qvalue->source);
+
+      if (data->property_values[pspec->param_id - 1].source <= qvalue->source)
        {
-         merge_color_scheme (data, &tmp_value, qvalue->source);
-         g_object_set_property (G_OBJECT (data), pspec->name, &tmp_value);
-         data->property_values[pspec->param_id - 1].source = GTK_SETTINGS_SOURCE_DEFAULT;
-       }      
-      
-      else if (data->property_values[pspec->param_id - 1].source <= qvalue->source)
-       {
-         g_object_set_property (G_OBJECT (data), pspec->name, &tmp_value);
+          g_value_copy (&tmp_value, &data->property_values[pspec->param_id - 1].value);
          data->property_values[pspec->param_id - 1].source = qvalue->source;
+          g_object_notify (G_OBJECT (data), g_param_spec_get_name (pspec));
        }
+
     }
   else
     {
       gchar *debug = g_strdup_value_contents (&qvalue->public.value);
       
       g_message ("%s: failed to retrieve property `%s' of type `%s' from rc file value \"%s\" of type `%s'",
-                qvalue->public.origin,
+                qvalue->public.origin ? qvalue->public.origin : "(for origin information, set GTK_DEBUG)",
                 pspec->name,
                 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
                 debug,
@@ -853,7 +1393,14 @@ settings_install_property_parser (GtkSettingsClass   *class,
     case G_TYPE_FLOAT:
     case G_TYPE_DOUBLE:
     case G_TYPE_STRING:
+    case G_TYPE_ENUM:
       break;
+    case G_TYPE_BOXED:
+      if (strcmp (g_param_spec_get_name (pspec), "color-hash") == 0)
+        {
+          break;
+        }
+      /* fall through */
     default:
       if (!parser)
         {
@@ -921,23 +1468,33 @@ _gtk_rc_property_parser_from_type (GType type)
 void
 gtk_settings_install_property (GParamSpec *pspec)
 {
+  static GtkSettingsClass *klass = NULL;
+
   GtkRcPropertyParser parser;
 
   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
 
+  if (! klass)
+    klass = g_type_class_ref (GTK_TYPE_SETTINGS);
+
   parser = _gtk_rc_property_parser_from_type (G_PARAM_SPEC_VALUE_TYPE (pspec));
 
-  settings_install_property_parser (gtk_type_class (GTK_TYPE_SETTINGS), pspec, parser);
+  settings_install_property_parser (klass, pspec, parser);
 }
 
 void
 gtk_settings_install_property_parser (GParamSpec          *pspec,
                                      GtkRcPropertyParser  parser)
 {
+  static GtkSettingsClass *klass = NULL;
+
   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
   g_return_if_fail (parser != NULL);
-  
-  settings_install_property_parser (gtk_type_class (GTK_TYPE_SETTINGS), pspec, parser);
+
+  if (! klass)
+    klass = g_type_class_ref (GTK_TYPE_SETTINGS);
+
+  settings_install_property_parser (klass, pspec, parser);
 }
 
 static void
@@ -947,7 +1504,7 @@ free_value (gpointer data)
   
   g_value_unset (&qvalue->public.value);
   g_free (qvalue->public.origin);
-  g_free (qvalue);
+  g_slice_free (GtkSettingsValuePrivate, qvalue);
 }
 
 static void
@@ -971,14 +1528,14 @@ gtk_settings_set_property_value_internal (GtkSettings            *settings,
     }
   
   name = g_strdup (prop_name);
-  g_strcanon (name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-');
+  g_strcanon (name, G_CSET_DIGITS "-" G_CSET_a_2_z G_CSET_A_2_Z, '-');
   name_quark = g_quark_from_string (name);
   g_free (name);
 
   qvalue = g_datalist_id_get_data (&settings->queued_settings, name_quark);
   if (!qvalue)
     {
-      qvalue = g_new0 (GtkSettingsValuePrivate, 1);
+      qvalue = g_slice_new0 (GtkSettingsValuePrivate);
       g_datalist_id_set_data_full (&settings->queued_settings, name_quark, qvalue, free_value);
     }
   else
@@ -1003,7 +1560,6 @@ gtk_settings_set_property_value (GtkSettings            *settings,
   g_return_if_fail (GTK_SETTINGS (settings));
   g_return_if_fail (prop_name != NULL);
   g_return_if_fail (new_value != NULL);
-  g_return_if_fail (new_value->origin != NULL);
 
   gtk_settings_set_property_value_internal (settings, prop_name, new_value,
                                            GTK_SETTINGS_SOURCE_APPLICATION);
@@ -1017,7 +1573,6 @@ _gtk_settings_set_property_value_from_rc (GtkSettings            *settings,
   g_return_if_fail (GTK_SETTINGS (settings));
   g_return_if_fail (prop_name != NULL);
   g_return_if_fail (new_value != NULL);
-  g_return_if_fail (new_value->origin != NULL);
 
   gtk_settings_set_property_value_internal (settings, prop_name, new_value,
                                            GTK_SETTINGS_SOURCE_RC_FILE);
@@ -1034,7 +1589,6 @@ gtk_settings_set_string_property (GtkSettings *settings,
   g_return_if_fail (GTK_SETTINGS (settings));
   g_return_if_fail (name != NULL);
   g_return_if_fail (v_string != NULL);
-  g_return_if_fail (origin != NULL);
 
   svalue.origin = (gchar*) origin;
   g_value_init (&svalue.value, G_TYPE_STRING);
@@ -1053,7 +1607,6 @@ gtk_settings_set_long_property (GtkSettings *settings,
   
   g_return_if_fail (GTK_SETTINGS (settings));
   g_return_if_fail (name != NULL);
-  g_return_if_fail (origin != NULL);
 
   svalue.origin = (gchar*) origin;
   g_value_init (&svalue.value, G_TYPE_LONG);
@@ -1072,7 +1625,6 @@ gtk_settings_set_double_property (GtkSettings *settings,
 
   g_return_if_fail (GTK_SETTINGS (settings));
   g_return_if_fail (name != NULL);
-  g_return_if_fail (origin != NULL);
 
   svalue.origin = (gchar*) origin;
   g_value_init (&svalue.value, G_TYPE_DOUBLE);
@@ -1390,6 +1942,7 @@ gtk_rc_property_parse_border (const GParamSpec *pspec,
   GtkBorder border;
   GScanner *scanner;
   gboolean success = FALSE;
+  int left, right, top, bottom;
 
   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
   g_return_val_if_fail (G_VALUE_HOLDS_BOXED (property_value), FALSE);
@@ -1397,11 +1950,15 @@ gtk_rc_property_parse_border (const GParamSpec *pspec,
   scanner = gtk_rc_scanner_new ();
   g_scanner_input_text (scanner, gstring->str, gstring->len);
 
-  if (get_braced_int (scanner, TRUE, FALSE, &border.left) &&
-      get_braced_int (scanner, FALSE, FALSE, &border.right) &&
-      get_braced_int (scanner, FALSE, FALSE, &border.top) &&
-      get_braced_int (scanner, FALSE, TRUE, &border.bottom))
+  if (get_braced_int (scanner, TRUE, FALSE, &left) &&
+      get_braced_int (scanner, FALSE, FALSE, &right) &&
+      get_braced_int (scanner, FALSE, FALSE, &top) &&
+      get_braced_int (scanner, FALSE, TRUE, &bottom))
     {
+      border.left = left;
+      border.right = right;
+      border.top = top;
+      border.bottom = bottom;
       g_value_set_boxed (property_value, &border);
       success = TRUE;
     }
@@ -1414,10 +1971,29 @@ gtk_rc_property_parse_border (const GParamSpec *pspec,
 void
 _gtk_settings_handle_event (GdkEventSetting *event)
 {
-  GtkSettings *settings = gtk_settings_get_for_screen (gdk_drawable_get_screen (event->window));
-  
-  if (g_object_class_find_property (G_OBJECT_GET_CLASS (settings), event->name))
-    g_object_notify (G_OBJECT (settings), event->name);
+  GtkSettings *settings;
+  GParamSpec *pspec;
+  guint property_id;
+
+  settings = gtk_settings_get_for_screen (gdk_window_get_screen (event->window));
+  pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (settings), event->name);
+  if (pspec) 
+    {
+      property_id = pspec->param_id;
+
+      if (property_id == PROP_COLOR_SCHEME)
+        {
+          GValue value = { 0, };
+          g_value_init (&value, G_TYPE_STRING);
+          if (!gdk_screen_get_setting (settings->screen, pspec->name, &value))
+            g_value_set_static_string (&value, "");
+          merge_color_scheme (settings, &value, GTK_SETTINGS_SOURCE_XSETTING);
+          g_value_unset (&value);
+        }
+      g_object_notify (G_OBJECT (settings), pspec->name);
+   }
 }
 
 static void
@@ -1452,6 +2028,8 @@ _gtk_settings_reset_rc_values (GtkSettings *settings)
       g_datalist_id_remove_data (&settings->queued_settings, key_id);
     }
 
+   g_slist_free (to_reset);
+
   /* Now reset the active settings
    */
   pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (settings), NULL);
@@ -1529,9 +2107,9 @@ settings_update_font_options (GtkSettings *settings)
 {
   gint hinting;
   gchar *hint_style_str;
-  cairo_hint_style_t hint_style = CAIRO_HINT_STYLE_DEFAULT;
+  cairo_hint_style_t hint_style = CAIRO_HINT_STYLE_NONE;
   gint antialias;
-  cairo_antialias_t antialias_mode = CAIRO_ANTIALIAS_DEFAULT;
+  cairo_antialias_t antialias_mode = CAIRO_ANTIALIAS_GRAY;
   gchar *rgba_str;
   cairo_subpixel_order_t subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
   cairo_font_options_t *options;
@@ -1544,11 +2122,9 @@ settings_update_font_options (GtkSettings *settings)
                NULL);
 
   options = cairo_font_options_create ();
-  
-  /* hint_metrics = FALSE should never be set for user interface code.
-   */
-  cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
 
+  cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
+  
   if (hinting >= 0 && !hinting)
     {
       hint_style = CAIRO_HINT_STYLE_NONE;
@@ -1565,8 +2141,7 @@ settings_update_font_options (GtkSettings *settings)
        hint_style = CAIRO_HINT_STYLE_FULL;
     }
 
-  if (hint_style_str)
-    g_free (hint_style_str);
+  g_free (hint_style_str);
 
   cairo_font_options_set_hint_style (options, hint_style);
 
@@ -1600,6 +2175,44 @@ settings_update_font_options (GtkSettings *settings)
   cairo_font_options_destroy (options);
 }
 
+#ifdef GDK_WINDOWING_X11
+static gboolean
+settings_update_fontconfig (GtkSettings *settings)
+{
+  static guint    last_update_timestamp;
+  static gboolean last_update_needed;
+
+  guint timestamp;
+
+  g_object_get (settings,
+               "gtk-fontconfig-timestamp", &timestamp,
+               NULL);
+
+  /* if timestamp is the same as last_update_timestamp, we already have
+   * updated fontconig on this timestamp (another screen requested it perhaps?),
+   * just return the cached result.*/
+
+  if (timestamp != last_update_timestamp)
+    {
+      PangoFontMap *fontmap = pango_cairo_font_map_get_default ();
+      gboolean update_needed = FALSE;
+
+      /* bug 547680 */
+      if (PANGO_IS_FC_FONT_MAP (fontmap) && !FcConfigUptoDate (NULL))
+       {
+         pango_fc_font_map_cache_clear (PANGO_FC_FONT_MAP (fontmap));
+         if (FcInitReinitialize ())
+           update_needed = TRUE;
+       }
+
+      last_update_timestamp = timestamp;
+      last_update_needed = update_needed;
+    }
+
+  return last_update_needed;
+}
+#endif /* GDK_WINDOWING_X11 */
+
 static void
 settings_update_resolution (GtkSettings *settings)
 {
@@ -1619,48 +2232,80 @@ settings_update_resolution (GtkSettings *settings)
 }
 #endif
 
+typedef struct {
+  GHashTable *color_hash;
+  GHashTable *tables[GTK_SETTINGS_SOURCE_APPLICATION + 1];
+  gchar *lastentry[GTK_SETTINGS_SOURCE_APPLICATION + 1];
+} ColorSchemeData;
+
 static void
-settings_update_color_scheme (GtkSettings *settings)
+color_scheme_data_free (ColorSchemeData *data)
 {
-  gchar *dummy;
+  gint i;
 
-  g_object_get (settings, "gtk-color-scheme", &dummy, NULL);
+  g_hash_table_unref (data->color_hash);
 
-  /* nothing to do here, the color hash is updated as a
-   * side effect of getting the color scheme
-   */
+  for (i = 0; i <= GTK_SETTINGS_SOURCE_APPLICATION; i++)
+    {
+      if (data->tables[i])
+       g_hash_table_unref (data->tables[i]);
+      g_free (data->lastentry[i]);
+    }
 
-  g_free (dummy);  
+  g_slice_free (ColorSchemeData, data);
 }
 
+static void
+settings_update_color_scheme (GtkSettings *settings)
+{
+  if (!g_object_get_data (G_OBJECT (settings), "gtk-color-scheme"))
+    {
+      ColorSchemeData *data;
+      GValue value = { 0, };
 
-typedef struct {
-  GHashTable *color_hash;
-  gchar *tables[GTK_SETTINGS_SOURCE_APPLICATION + 1];
-} ColorSchemeData;
+      data = g_slice_new0 (ColorSchemeData);
+      data->color_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+                                               (GDestroyNotify) gdk_color_free);
+      g_object_set_data_full (G_OBJECT (settings), "gtk-color-scheme",
+                             data, (GDestroyNotify) color_scheme_data_free); 
 
+      g_value_init (&value, G_TYPE_STRING);
+      if (gdk_screen_get_setting (settings->screen, "gtk-color-scheme", &value))
+        {
+          merge_color_scheme (settings, &value, GTK_SETTINGS_SOURCE_XSETTING);
+          g_value_unset (&value);
+        }
+   }
+}
 
 static gboolean
-update_color_hash (ColorSchemeData   *data,
-                  const gchar       *str, 
-                  GtkSettingsSource  source)
+add_color_to_hash (gchar      *name,
+                  GdkColor   *color,
+                  GHashTable *target)
 {
-  gchar *copy, *s, *p, *name;
-  GdkColor color;
-  gboolean changed = FALSE;
+  GdkColor *old;
 
-  if (data->tables[source] == NULL && str == NULL)
-    return FALSE;
+  old = g_hash_table_lookup (target, name);
+  if (!old || !gdk_color_equal (old, color))
+    {
+      g_hash_table_insert (target, g_strdup (name), gdk_color_copy (color));
 
-  if (data->tables[source] != NULL && str != NULL &&
-      strcmp (data->tables[source], str) == 0)
-    return FALSE;
+      return TRUE;
+    }
 
-  g_free (data->tables[source]);
-  data->tables[source] = g_strdup (str);
+  return FALSE;
+}
 
-  copy = g_strdup (str);
+static gboolean
+add_colors_to_hash_from_string (GHashTable  *hash,
+                               const gchar *colors)
+{
+  gchar *s, *p, *name;
+  GdkColor color;
+  gboolean changed = FALSE;
+  gchar *copy;
 
+  copy = g_strdup (colors);
   s = copy;
   while (s && *s)
     {
@@ -1680,7 +2325,7 @@ update_color_hash (ColorSchemeData   *data,
       s = p;
       while (*s) 
        {
-         if (*s == '\n')
+         if (*s == '\n' || *s == ';')
            {
              *s = '\0';
              s++;
@@ -1690,23 +2335,7 @@ update_color_hash (ColorSchemeData   *data,
        }
 
       if (gdk_color_parse (p, &color))
-       {
-         GdkColor *old;
-
-         old = g_hash_table_lookup (data->color_hash, name);
-         if (!old || 
-             (old->pixel <= source && !gdk_color_equal (old, &color)))
-           {
-             GdkColor *new;
-             
-             new = gdk_color_copy (&color);
-             new->pixel = source;
-  
-             g_hash_table_insert (data->color_hash, g_strdup (name), new);
-             changed = TRUE;
-           }
-       }
+       changed |= add_color_to_hash (name, &color, hash);
     }
 
   g_free (copy);
@@ -1714,42 +2343,126 @@ update_color_hash (ColorSchemeData   *data,
   return changed;
 }
 
-static void
-color_scheme_data_free (ColorSchemeData *data)
+static gboolean
+update_color_hash (ColorSchemeData   *data,
+                  const gchar       *str,
+                  GtkSettingsSource  source)
 {
+  gboolean changed = FALSE;
   gint i;
+  GHashTable *old_hash;
+  GHashTableIter iter;
+  gpointer name;
+  gpointer color;
 
-  g_hash_table_unref (data->color_hash);
+  if ((str == NULL || *str == '\0') &&
+      (data->lastentry[source] == NULL || data->lastentry[source][0] == '\0'))
+    return FALSE;
+
+  if (str && data->lastentry[source] && strcmp (str, data->lastentry[source]) == 0)
+    return FALSE;
+
+  /* For the RC_FILE source we merge the values rather than over-writing
+   * them, since multiple rc files might define independent sets of colors
+   */
+  if ((source != GTK_SETTINGS_SOURCE_RC_FILE) &&
+      data->tables[source] && g_hash_table_size (data->tables[source]) > 0)
+    {
+      g_hash_table_unref (data->tables[source]);
+      data->tables[source] = NULL;
+      changed = TRUE; /* We can't rely on the code below since str might be "" */
+    }
+
+  if (data->tables[source] == NULL)
+    data->tables[source] = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                 g_free,
+                                                 (GDestroyNotify) gdk_color_free);
+
+  g_free (data->lastentry[source]);
+  data->lastentry[source] = g_strdup (str);
+
+  changed |= add_colors_to_hash_from_string (data->tables[source], str);
+
+  if (!changed)
+    return FALSE;
+
+  /* Rebuild the merged hash table. */
+  if (data->color_hash)
+    {
+      old_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+                                        (GDestroyNotify) gdk_color_free);
+
+      g_hash_table_iter_init (&iter, data->color_hash);
+      while (g_hash_table_iter_next (&iter, &name, &color))
+        {
+          g_hash_table_insert (old_hash, name, color);
+          g_hash_table_iter_steal (&iter);
+        }
+    }
+  else
+    {
+      old_hash = NULL;
+    }
 
   for (i = 0; i <= GTK_SETTINGS_SOURCE_APPLICATION; i++)
-    g_free (data->tables[i]);
+    {
+      if (data->tables[i])
+       g_hash_table_foreach (data->tables[i], (GHFunc) add_color_to_hash,
+                             data->color_hash);
+    }
+
+  if (old_hash)
+    {
+      /* now check if the merged hash has changed */
+      changed = FALSE;
+      if (g_hash_table_size (old_hash) != g_hash_table_size (data->color_hash))
+        changed = TRUE;
+      else
+        {
+          GHashTableIter iter;
+          gpointer key, value, new_value;
 
-  g_free (data);
+          g_hash_table_iter_init (&iter, old_hash);
+          while (g_hash_table_iter_next (&iter, &key, &value))
+            {
+              new_value = g_hash_table_lookup (data->color_hash, key);
+              if (!new_value || !gdk_color_equal (value, new_value))
+                {
+                  changed = TRUE;
+                  break;
+                }
+            }
+        }
+
+      g_hash_table_unref (old_hash);
+    }
+  else
+    changed = TRUE;
+
+  return changed;
 }
 
 static void
 merge_color_scheme (GtkSettings       *settings, 
-                   GValue            *value, 
+                   const GValue      *value, 
                    GtkSettingsSource  source)
 {
   ColorSchemeData *data;
   const gchar *colors;
 
+  g_object_freeze_notify (G_OBJECT (settings));
+
   colors = g_value_get_string (value);
 
+  settings_update_color_scheme (settings);
+
   data = (ColorSchemeData *) g_object_get_data (G_OBJECT (settings),
-                                                "gtk-color-scheme");
-  if (!data)
-    {
-      data = g_new0 (ColorSchemeData, 1);
-      data->color_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
-                                               (GDestroyNotify) gdk_color_free);
-      g_object_set_data_full (G_OBJECT (settings), "gtk-color-scheme",
-                             data, (GDestroyNotify) color_scheme_data_free);
-    }
+                                               "gtk-color-scheme");
   
   if (update_color_hash (data, colors, source))
     g_object_notify (G_OBJECT (settings), "color-hash");
+
+  g_object_thaw_notify (G_OBJECT (settings));
 }
 
 static GHashTable *
@@ -1757,15 +2470,11 @@ get_color_hash (GtkSettings *settings)
 {
   ColorSchemeData *data;
 
-  if (!g_object_get_data (G_OBJECT (settings), "gtk-color-scheme"))
-    settings_update_color_scheme (settings);
+  settings_update_color_scheme (settings);
   
   data = (ColorSchemeData *)g_object_get_data (G_OBJECT (settings), 
                                               "gtk-color-scheme");
 
-  if (!data)
-    return NULL;
-
   return data->color_hash;
 }
 
@@ -1788,6 +2497,8 @@ get_color_scheme (GtkSettings *settings)
   ColorSchemeData *data;
   GString *string;
   
+  settings_update_color_scheme (settings);
+
   data = (ColorSchemeData *) g_object_get_data (G_OBJECT (settings),
                                                "gtk-color-scheme");
 
@@ -1797,7 +2508,3 @@ get_color_scheme (GtkSettings *settings)
 
   return g_string_free (string, FALSE);
 }
-
-
-#define __GTK_SETTINGS_C__
-#include "gtkaliasdef.c"