]> Pileus Git - ~andy/gtk/blob - gtk/gtksettings.c
Bug 507389 – use gslice for gtksettings
[~andy/gtk] / gtk / gtksettings.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2000 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <config.h>
20
21 #include <string.h>
22
23 #include "gtkmodules.h"
24 #include "gtksettings.h"
25 #include "gtkrc.h"
26 #include "gtkintl.h"
27 #include "gtkwidget.h"
28 #include "gtkprivate.h"
29 #include "gtkalias.h"
30
31 #ifdef GDK_WINDOWING_X11
32 #include "x11/gdkx.h"
33 #endif
34
35 #define DEFAULT_TIMEOUT_INITIAL 200
36 #define DEFAULT_TIMEOUT_REPEAT   20
37 #define DEFAULT_TIMEOUT_EXPAND  500
38
39 typedef struct _GtkSettingsValuePrivate GtkSettingsValuePrivate;
40
41 typedef enum
42 {
43   GTK_SETTINGS_SOURCE_DEFAULT,
44   GTK_SETTINGS_SOURCE_RC_FILE,
45   GTK_SETTINGS_SOURCE_XSETTING,
46   GTK_SETTINGS_SOURCE_APPLICATION
47 } GtkSettingsSource;
48
49 struct _GtkSettingsValuePrivate
50 {
51   GtkSettingsValue public;
52   GtkSettingsSource source;
53 };
54
55 struct _GtkSettingsPropertyValue
56 {
57   GValue value;
58   GtkSettingsSource source;
59 };
60
61 enum {
62   PROP_0,
63   PROP_DOUBLE_CLICK_TIME,
64   PROP_DOUBLE_CLICK_DISTANCE,
65   PROP_CURSOR_BLINK,
66   PROP_CURSOR_BLINK_TIME,
67   PROP_CURSOR_BLINK_TIMEOUT,
68   PROP_SPLIT_CURSOR,
69   PROP_THEME_NAME,
70   PROP_ICON_THEME_NAME,
71   PROP_FALLBACK_ICON_THEME,
72   PROP_KEY_THEME_NAME,
73   PROP_MENU_BAR_ACCEL,
74   PROP_DND_DRAG_THRESHOLD,
75   PROP_FONT_NAME,
76   PROP_ICON_SIZES,
77   PROP_MODULES,
78 #ifdef GDK_WINDOWING_X11
79   PROP_XFT_ANTIALIAS,
80   PROP_XFT_HINTING,
81   PROP_XFT_HINTSTYLE,
82   PROP_XFT_RGBA,
83   PROP_XFT_DPI,
84   PROP_CURSOR_THEME_NAME,
85   PROP_CURSOR_THEME_SIZE,
86 #endif
87   PROP_ALTERNATIVE_BUTTON_ORDER,
88   PROP_ALTERNATIVE_SORT_ARROWS,
89   PROP_SHOW_INPUT_METHOD_MENU,
90   PROP_SHOW_UNICODE_MENU,
91   PROP_TIMEOUT_INITIAL,
92   PROP_TIMEOUT_REPEAT,
93   PROP_TIMEOUT_EXPAND,
94   PROP_COLOR_SCHEME,
95   PROP_ENABLE_ANIMATIONS,
96   PROP_TOUCHSCREEN_MODE,
97   PROP_TOOLTIP_TIMEOUT,
98   PROP_TOOLTIP_BROWSE_TIMEOUT,
99   PROP_TOOLTIP_BROWSE_MODE_TIMEOUT,
100   PROP_KEYNAV_CURSOR_ONLY,
101   PROP_KEYNAV_WRAP_AROUND,
102   PROP_ERROR_BELL,
103   PROP_COLOR_HASH,
104   PROP_FILE_CHOOSER_BACKEND,
105   PROP_PRINT_BACKENDS,
106   PROP_PRINT_PREVIEW_COMMAND,
107   PROP_ENABLE_MNEMONICS,
108   PROP_ENABLE_ACCELS,
109   PROP_RECENT_FILES_LIMIT,
110   PROP_IM_MODULE,
111   PROP_RECENT_FILES_MAX_AGE
112 };
113
114
115 /* --- prototypes --- */
116 static void     gtk_settings_finalize            (GObject               *object);
117 static void     gtk_settings_get_property        (GObject               *object,
118                                                   guint                  property_id,
119                                                   GValue                *value,
120                                                   GParamSpec            *pspec);
121 static void     gtk_settings_set_property        (GObject               *object,
122                                                   guint                  property_id,
123                                                   const GValue          *value,
124                                                   GParamSpec            *pspec);
125 static void     gtk_settings_notify              (GObject               *object,
126                                                   GParamSpec            *pspec);
127 static guint    settings_install_property_parser (GtkSettingsClass      *class,
128                                                   GParamSpec            *pspec,
129                                                   GtkRcPropertyParser    parser);
130 static void    settings_update_double_click      (GtkSettings           *settings);
131 static void    settings_update_modules           (GtkSettings           *settings);
132
133 #ifdef GDK_WINDOWING_X11
134 static void    settings_update_cursor_theme      (GtkSettings           *settings);
135 static void    settings_update_resolution        (GtkSettings           *settings);
136 static void    settings_update_font_options      (GtkSettings           *settings);
137 #endif
138 static void    settings_update_color_scheme      (GtkSettings *settings);
139
140 static void    merge_color_scheme                (GtkSettings           *settings, 
141                                                   const GValue          *value, 
142                                                   GtkSettingsSource      source);
143 static gchar  *get_color_scheme                  (GtkSettings           *settings);
144 static GHashTable *get_color_hash                (GtkSettings           *settings);
145
146
147 /* --- variables --- */
148 static GQuark            quark_property_parser = 0;
149 static GSList           *object_list = NULL;
150 static guint             class_n_properties = 0;
151
152
153 G_DEFINE_TYPE (GtkSettings, gtk_settings, G_TYPE_OBJECT)
154
155 /* --- functions --- */
156 static void
157 gtk_settings_init (GtkSettings *settings)
158 {
159   GParamSpec **pspecs, **p;
160   guint i = 0;
161   
162   g_datalist_init (&settings->queued_settings);
163   object_list = g_slist_prepend (object_list, settings);
164
165   /* build up property array for all yet existing properties and queue
166    * notification for them (at least notification for internal properties
167    * will instantly be caught)
168    */
169   pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (settings), NULL);
170   for (p = pspecs; *p; p++)
171     if ((*p)->owner_type == G_OBJECT_TYPE (settings))
172       i++;
173   settings->property_values = g_new0 (GtkSettingsPropertyValue, i);
174   i = 0;
175   g_object_freeze_notify (G_OBJECT (settings));
176   for (p = pspecs; *p; p++)
177     {
178       GParamSpec *pspec = *p;
179
180       if (pspec->owner_type != G_OBJECT_TYPE (settings))
181         continue;
182       g_value_init (&settings->property_values[i].value, G_PARAM_SPEC_VALUE_TYPE (pspec));
183       g_param_value_set_default (pspec, &settings->property_values[i].value);
184       g_object_notify (G_OBJECT (settings), pspec->name);
185       settings->property_values[i].source = GTK_SETTINGS_SOURCE_DEFAULT;
186       i++;
187     }
188   g_object_thaw_notify (G_OBJECT (settings));
189   g_free (pspecs);
190 }
191
192 static void
193 gtk_settings_class_init (GtkSettingsClass *class)
194 {
195   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
196   guint result;
197   
198   gobject_class->finalize = gtk_settings_finalize;
199   gobject_class->get_property = gtk_settings_get_property;
200   gobject_class->set_property = gtk_settings_set_property;
201   gobject_class->notify = gtk_settings_notify;
202
203   quark_property_parser = g_quark_from_static_string ("gtk-rc-property-parser");
204   result = settings_install_property_parser (class,
205                                              g_param_spec_int ("gtk-double-click-time",
206                                                                P_("Double Click Time"),
207                                                                P_("Maximum time allowed between two clicks for them to be considered a double click (in milliseconds)"),
208                                                                0, G_MAXINT, 250,
209                                                                GTK_PARAM_READWRITE),
210                                              NULL);
211   g_assert (result == PROP_DOUBLE_CLICK_TIME);
212   result = settings_install_property_parser (class,
213                                              g_param_spec_int ("gtk-double-click-distance",
214                                                                P_("Double Click Distance"),
215                                                                P_("Maximum distance allowed between two clicks for them to be considered a double click (in pixels)"),
216                                                                0, G_MAXINT, 5,
217                                                                GTK_PARAM_READWRITE),
218                                              NULL);
219   g_assert (result == PROP_DOUBLE_CLICK_DISTANCE);
220
221   /**
222    * GtkSettings:gtk-cursor-blink:
223    *
224    * Whether the cursor should blink. 
225    *
226    * Also see the #GtkSettings:gtk-cursor-blink-timeout setting, 
227    * which allows more flexible control over cursor blinking.
228    */
229   result = settings_install_property_parser (class,
230                                              g_param_spec_boolean ("gtk-cursor-blink",
231                                                                    P_("Cursor Blink"),
232                                                                    P_("Whether the cursor should blink"),
233                                                                    TRUE,
234                                                                    GTK_PARAM_READWRITE),
235                                              NULL);
236   g_assert (result == PROP_CURSOR_BLINK);
237   result = settings_install_property_parser (class,
238                                              g_param_spec_int ("gtk-cursor-blink-time",
239                                                                P_("Cursor Blink Time"),
240                                                                P_("Length of the cursor blink cycle, in milliseconds"),
241                                                                100, G_MAXINT, 1200,
242                                                                GTK_PARAM_READWRITE),
243                                              NULL);
244   g_assert (result == PROP_CURSOR_BLINK_TIME);
245  
246   /**
247    * GtkSettings:gtk-cursor-blink-timeout:
248    *
249    * Time after which the cursor stops blinking, in seconds.
250    * The timer is reset after each user interaction.
251    *
252    * Setting this to zero has the same effect as setting
253    * #GtkSettings:gtk-cursor-blink to %FALSE. 
254    *
255    * Since: 2.12
256    */
257   result = settings_install_property_parser (class,
258                                              g_param_spec_int ("gtk-cursor-blink-timeout",
259                                                                P_("Cursor Blink Timeout"),
260                                                                P_("Time after which the cursor stops blinking, in seconds"),
261                                                                1, G_MAXINT, G_MAXINT,
262                                                                GTK_PARAM_READWRITE),
263                                              NULL);
264   g_assert (result == PROP_CURSOR_BLINK_TIMEOUT);
265   result = settings_install_property_parser (class,
266                                              g_param_spec_boolean ("gtk-split-cursor",
267                                                                    P_("Split Cursor"),
268                                                                    P_("Whether two cursors should be displayed for mixed left-to-right and right-to-left text"),
269                                                                    TRUE,
270                                                                    GTK_PARAM_READWRITE),
271                                              NULL);
272   g_assert (result == PROP_SPLIT_CURSOR);
273   result = settings_install_property_parser (class,
274                                              g_param_spec_string ("gtk-theme-name",
275                                                                    P_("Theme Name"),
276                                                                    P_("Name of theme RC file to load"),
277                                                                   "Raleigh",
278                                                                   GTK_PARAM_READWRITE),
279                                              NULL);
280   g_assert (result == PROP_THEME_NAME);
281
282   result = settings_install_property_parser (class,
283                                              g_param_spec_string ("gtk-icon-theme-name",
284                                                                   P_("Icon Theme Name"),
285                                                                   P_("Name of icon theme to use"),
286                                                                   "hicolor",
287                                                                   GTK_PARAM_READWRITE),
288                                              NULL);
289   g_assert (result == PROP_ICON_THEME_NAME);
290
291   result = settings_install_property_parser (class,
292                                              g_param_spec_string ("gtk-fallback-icon-theme",
293                                                                   P_("Fallback Icon Theme Name"),
294                                                                   P_("Name of a icon theme to fall back to"),
295                                                                   NULL,
296                                                                   GTK_PARAM_READWRITE),
297                                              NULL);
298   g_assert (result == PROP_FALLBACK_ICON_THEME);
299   
300   result = settings_install_property_parser (class,
301                                              g_param_spec_string ("gtk-key-theme-name",
302                                                                   P_("Key Theme Name"),
303                                                                   P_("Name of key theme RC file to load"),
304                                                                   NULL,
305                                                                   GTK_PARAM_READWRITE),
306                                              NULL);
307   g_assert (result == PROP_KEY_THEME_NAME);    
308
309   result = settings_install_property_parser (class,
310                                              g_param_spec_string ("gtk-menu-bar-accel",
311                                                                   P_("Menu bar accelerator"),
312                                                                   P_("Keybinding to activate the menu bar"),
313                                                                   "F10",
314                                                                   GTK_PARAM_READWRITE),
315                                              NULL);
316   g_assert (result == PROP_MENU_BAR_ACCEL);
317
318   result = settings_install_property_parser (class,
319                                              g_param_spec_int ("gtk-dnd-drag-threshold",
320                                                                P_("Drag threshold"),
321                                                                P_("Number of pixels the cursor can move before dragging"),
322                                                                1, G_MAXINT, 8,
323                                                                GTK_PARAM_READWRITE),
324                                              NULL);
325   g_assert (result == PROP_DND_DRAG_THRESHOLD);
326
327   result = settings_install_property_parser (class,
328                                              g_param_spec_string ("gtk-font-name",
329                                                                    P_("Font Name"),
330                                                                    P_("Name of default font to use"),
331                                                                   "Sans 10",
332                                                                   GTK_PARAM_READWRITE),
333                                              NULL);
334   g_assert (result == PROP_FONT_NAME);
335
336   result = settings_install_property_parser (class,
337                                              g_param_spec_string ("gtk-icon-sizes",
338                                                                    P_("Icon Sizes"),
339                                                                    P_("List of icon sizes (gtk-menu=16,16:gtk-button=20,20..."),
340                                                                   NULL,
341                                                                   GTK_PARAM_READWRITE),
342                                              NULL);
343   g_assert (result == PROP_ICON_SIZES);
344
345   result = settings_install_property_parser (class,
346                                              g_param_spec_string ("gtk-modules",
347                                                                   P_("GTK Modules"),
348                                                                   P_("List of currently active GTK modules"),
349                                                                   NULL,
350                                                                   GTK_PARAM_READWRITE),
351                                              NULL);
352   g_assert (result == PROP_MODULES);
353
354 #ifdef GDK_WINDOWING_X11
355   result = settings_install_property_parser (class,
356                                              g_param_spec_int ("gtk-xft-antialias",
357                                                                P_("Xft Antialias"),
358                                                                P_("Whether to antialias Xft fonts; 0=no, 1=yes, -1=default"),
359                                                                -1, 1, -1,
360                                                                GTK_PARAM_READWRITE),
361                                              NULL);
362  
363   g_assert (result == PROP_XFT_ANTIALIAS);
364   
365   result = settings_install_property_parser (class,
366                                              g_param_spec_int ("gtk-xft-hinting",
367                                                                P_("Xft Hinting"),
368                                                                P_("Whether to hint Xft fonts; 0=no, 1=yes, -1=default"),
369                                                                -1, 1, -1,
370                                                                GTK_PARAM_READWRITE),
371                                              NULL);
372   
373   g_assert (result == PROP_XFT_HINTING);
374   
375   result = settings_install_property_parser (class,
376                                              g_param_spec_string ("gtk-xft-hintstyle",
377                                                                   P_("Xft Hint Style"),
378                                                                   P_("What degree of hinting to use; hintnone, hintslight, hintmedium, or hintfull"),
379                                                                   NULL,
380                                                                   GTK_PARAM_READWRITE),
381                                               NULL);
382   
383   g_assert (result == PROP_XFT_HINTSTYLE);
384   
385   result = settings_install_property_parser (class,
386                                              g_param_spec_string ("gtk-xft-rgba",
387                                                                   P_("Xft RGBA"),
388                                                                   P_("Type of subpixel antialiasing; none, rgb, bgr, vrgb, vbgr"),
389                                                                   NULL,
390                                                                   GTK_PARAM_READWRITE),
391                                              NULL);
392   
393   g_assert (result == PROP_XFT_RGBA);
394   
395   result = settings_install_property_parser (class,
396                                              g_param_spec_int ("gtk-xft-dpi",
397                                                                P_("Xft DPI"),
398                                                                P_("Resolution for Xft, in 1024 * dots/inch. -1 to use default value"),
399                                                                -1, 1024*1024, -1,
400                                                                GTK_PARAM_READWRITE),
401                                              NULL);
402   
403   g_assert (result == PROP_XFT_DPI);
404
405   result = settings_install_property_parser (class,
406                                              g_param_spec_string ("gtk-cursor-theme-name",
407                                                                   P_("Cursor theme name"),
408                                                                   P_("Name of the cursor theme to use, or NULL to use the default theme"),
409                                                                   NULL,
410                                                                   GTK_PARAM_READWRITE),
411                                              NULL);
412   g_assert (result == PROP_CURSOR_THEME_NAME);
413
414   result = settings_install_property_parser (class,
415                                              g_param_spec_int ("gtk-cursor-theme-size",
416                                                                P_("Cursor theme size"),
417                                                                P_("Size to use for cursors, or 0 to use the default size"),
418                                                                0, 128, 0,
419                                                                GTK_PARAM_READWRITE),
420                                              NULL);
421   
422   g_assert (result == PROP_CURSOR_THEME_SIZE);
423
424 #endif  /* GDK_WINDOWING_X11 */
425   result = settings_install_property_parser (class,
426                                              g_param_spec_boolean ("gtk-alternative-button-order",
427                                                                    P_("Alternative button order"),
428                                                                    P_("Whether buttons in dialogs should use the alternative button order"),
429                                                                    FALSE,
430                                                                    GTK_PARAM_READWRITE),
431                                              NULL);
432   g_assert (result == PROP_ALTERNATIVE_BUTTON_ORDER);
433
434   /**
435    * GtkSettings:gtk-alternative-sort-arrows:
436    *
437    * Controls the direction of the sort indicators in sorted list and tree
438    * views. By default an arrow pointing down means the column is sorted
439    * in ascending order. When set to %TRUE, this order will be inverted.
440    *
441    * Since: 2.12
442    */
443   result = settings_install_property_parser (class,
444                                              g_param_spec_boolean ("gtk-alternative-sort-arrows",
445                                                                    P_("Alternative sort indicator direction"),
446                                                                    P_("Whether the direction of the sort indicators in list and tree views is inverted compared to the default (where down means ascending)"),
447                                                                    FALSE,
448                                                                    GTK_PARAM_READWRITE),
449                                              NULL);
450   g_assert (result == PROP_ALTERNATIVE_SORT_ARROWS);
451
452   result = settings_install_property_parser (class,
453                                              g_param_spec_boolean ("gtk-show-input-method-menu",
454                                                                    P_("Show the 'Input Methods' menu"),
455                                                                    P_("Whether the context menus of entries and text views should offer to change the input method"),
456                                                                    TRUE,
457                                                                    GTK_PARAM_READWRITE),
458                                              NULL);
459   g_assert (result == PROP_SHOW_INPUT_METHOD_MENU);
460
461   result = settings_install_property_parser (class,
462                                              g_param_spec_boolean ("gtk-show-unicode-menu",
463                                                                    P_("Show the 'Insert Unicode Control Character' menu"),
464                                                                    P_("Whether the context menus of entries and text views should offer to insert control characters"),
465                                                                    TRUE,
466                                                                    GTK_PARAM_READWRITE),
467                                              NULL);
468   g_assert (result == PROP_SHOW_UNICODE_MENU);
469
470   result = settings_install_property_parser (class,
471                                              g_param_spec_int ("gtk-timeout-initial",
472                                                                P_("Start timeout"),
473                                                                P_("Starting value for timeouts, when button is pressed"),
474                                                                0, G_MAXINT, DEFAULT_TIMEOUT_INITIAL,
475                                                                GTK_PARAM_READWRITE),
476                                              NULL);
477
478   g_assert (result == PROP_TIMEOUT_INITIAL);
479
480   result = settings_install_property_parser (class,
481                                              g_param_spec_int ("gtk-timeout-repeat",
482                                                                P_("Repeat timeout"),
483                                                                P_("Repeat value for timeouts, when button is pressed"),
484                                                                0, G_MAXINT, DEFAULT_TIMEOUT_REPEAT,
485                                                                GTK_PARAM_READWRITE),
486                                              NULL);
487
488   g_assert (result == PROP_TIMEOUT_REPEAT);
489
490   result = settings_install_property_parser (class,
491                                              g_param_spec_int ("gtk-timeout-expand",
492                                                                P_("Expand timeout"),
493                                                                P_("Expand value for timeouts, when a widget is expanding a new region"),
494                                                                0, G_MAXINT, DEFAULT_TIMEOUT_EXPAND,
495                                                                GTK_PARAM_READWRITE),
496                                              NULL);
497
498   g_assert (result == PROP_TIMEOUT_EXPAND);
499
500   /**
501    * GtkSettings:gtk-color-scheme:
502    *
503    * A palette of named colors for use in themes. The format of the string is
504    * <programlisting>
505    * name1: color1
506    * name2: color2
507    * ...
508    * </programlisting>
509    * Color names must be acceptable as identifiers in the 
510    * <link linkend="gtk-Resource-Files">gtkrc</link> syntax, and
511    * color specifications must be in the format accepted by
512    * gdk_color_parse().
513    * 
514    * Note that due to the way the color tables from different sources are
515    * merged, color specifications will be converted to hexadecimal form
516    * when getting this property.
517    *
518    * Starting with GTK+ 2.12, the entries can alternatively be separated
519    * by ';' instead of newlines:
520    * <programlisting>
521    * name1: color1; name2: color2; ...
522    * </programlisting>
523    *
524    * Since: 2.10
525    */
526   result = settings_install_property_parser (class,
527                                              g_param_spec_string ("gtk-color-scheme",
528                                                                   P_("Color scheme"),
529                                                                   P_("A palette of named colors for use in themes"),
530                                                                   "",
531                                                                   GTK_PARAM_READWRITE),
532                                              NULL);
533
534   g_assert (result == PROP_COLOR_SCHEME);
535
536   result = settings_install_property_parser (class,
537                                              g_param_spec_boolean ("gtk-enable-animations",
538                                                                    P_("Enable Animations"),
539                                                                    P_("Whether to enable toolkit-wide animations."),
540                                                                    TRUE,
541                                                                    GTK_PARAM_READWRITE),
542                                              NULL);
543
544   g_assert (result == PROP_ENABLE_ANIMATIONS);
545
546   /**
547    * GtkSettings:gtk-touchscreen-mode:
548    *
549    * When %TRUE, there are no motion notify events delivered on this screen,
550    * and widgets can't use the pointer hovering them for any essential
551    * functionality.
552    *
553    * Since: 2.10
554    */
555   result = settings_install_property_parser (class,
556                                              g_param_spec_boolean ("gtk-touchscreen-mode",
557                                                                    P_("Enable Touchscreen Mode"),
558                                                                    P_("When TRUE, there are no motion notify events delivered on this screen"),
559                                                                    FALSE,
560                                                                    GTK_PARAM_READWRITE),
561                                              NULL);
562
563   g_assert (result == PROP_TOUCHSCREEN_MODE);
564
565   /**
566    * GtkSettings:gtk-tooltip-timeout:
567    *
568    * Time, in milliseconds, after which a tooltip could appear if the
569    * cursor is hovering on top of a widget.
570    *
571    * Since: 2.12
572    */
573   result = settings_install_property_parser (class,
574                                              g_param_spec_int ("gtk-tooltip-timeout",
575                                                                P_("Tooltip timeout"),
576                                                                P_("Timeout before tooltip is shown"),
577                                                                0, G_MAXINT,
578                                                                500,
579                                                                GTK_PARAM_READWRITE),
580                                              NULL);
581
582   g_assert (result == PROP_TOOLTIP_TIMEOUT);
583
584   /**
585    * GtkSettings:gtk-tooltip-browse-timeout:
586    *
587    * Controls the time after which tooltips will appear when
588    * browse mode is enabled, in milliseconds.
589    *
590    * Browse mode is enabled when the mouse pointer moves off an object
591    * where a tooltip was currently being displayed. If the mouse pointer
592    * hits another object before the browse mode timeout expires (see
593    * #GtkSettings:gtk-tooltip-browse-mode-timeout), it will take the 
594    * amount of milliseconds specified by this setting to popup the tooltip
595    * for the new object.
596    *
597    * Since: 2.12
598    */
599   result = settings_install_property_parser (class,
600                                              g_param_spec_int ("gtk-tooltip-browse-timeout",
601                                                                P_("Tooltip browse timeout"),
602                                                                P_("Timeout before tooltip is shown when browse mode is enabled"),
603                                                                0, G_MAXINT,
604                                                                60,
605                                                                GTK_PARAM_READWRITE),
606                                              NULL);
607
608   g_assert (result == PROP_TOOLTIP_BROWSE_TIMEOUT);
609
610   /**
611    * GtkSettings:gtk-tooltip-browse-mode-timeout:
612    *
613    * Amount of time, in milliseconds, after which the browse mode
614    * will be disabled.
615    *
616    * See #GtkSettings:gtk-tooltip-browse-timeout for more information
617    * about browse mode.
618    *
619    * Since: 2.12
620    */
621   result = settings_install_property_parser (class,
622                                              g_param_spec_int ("gtk-tooltip-browse-mode-timeout",
623                                                                P_("Tooltip browse mode timeout"),
624                                                                P_("Timeout after which browse mode is disabled"),
625                                                                0, G_MAXINT,
626                                                                500,
627                                                                GTK_PARAM_READWRITE),
628                                              NULL);
629
630   g_assert (result == PROP_TOOLTIP_BROWSE_MODE_TIMEOUT);
631
632   /**
633    * GtkSettings:gtk-keynav-cursor-only:
634    *
635    * When %TRUE, keyboard navigation should be able to reach all widgets
636    * by using the cursor keys only. Tab, Shift etc. keys can't be expected
637    * to be present on the used input device.
638    *
639    * Since: 2.12
640    */
641   result = settings_install_property_parser (class,
642                                              g_param_spec_boolean ("gtk-keynav-cursor-only",
643                                                                    P_("Keynav Cursor Only"),
644                                                                    P_("When TRUE, there are only cursor keys available to navigate widgets"),
645                                                                    FALSE,
646                                                                    GTK_PARAM_READWRITE),
647                                              NULL);
648
649   g_assert (result == PROP_KEYNAV_CURSOR_ONLY);
650
651   /**
652    * GtkSettings:gtk-keynav-wrap-around:
653    *
654    * When %TRUE, some widgets will wrap around when doing keyboard
655    * navigation, such as menus, menubars and notebooks.
656    *
657    * Since: 2.12
658    */
659   result = settings_install_property_parser (class,
660                                              g_param_spec_boolean ("gtk-keynav-wrap-around",
661                                                                    P_("Keynav Wrap Around"),
662                                                                    P_("Whether to wrap around when keyboard-navigating widgets"),
663                                                                    TRUE,
664                                                                    GTK_PARAM_READWRITE),
665                                              NULL);
666
667   g_assert (result == PROP_KEYNAV_WRAP_AROUND);
668
669   /**
670    * GtkSettings:gtk-error-bell:
671    *
672    * When %TRUE, keyboard navigation and other input-related errors
673    * will cause a beep. Since the error bell is implemented using
674    * gdk_window_beep(), the windowing system may offer ways to
675    * configure the error bell in many ways, such as flashing the
676    * window or similar visual effects.
677    *
678    * Since: 2.12
679    */
680   result = settings_install_property_parser (class,
681                                              g_param_spec_boolean ("gtk-error-bell",
682                                                                    P_("Error Bell"),
683                                                                    P_("When TRUE, keyboard navigation and other errors will cause a beep"),
684                                                                    TRUE,
685                                                                    GTK_PARAM_READWRITE),
686                                              NULL);
687
688   g_assert (result == PROP_ERROR_BELL);
689
690   /**
691    * GtkSettings:color-hash:
692    *
693    * Holds a hash table representation of the #GtkSettings:gtk-color-scheme 
694    * setting, mapping color names to #GdkColor<!-- -->s. 
695    *
696    * Since: 2.10
697    */
698   result = settings_install_property_parser (class, 
699                                              g_param_spec_boxed ("color-hash",
700                                                                  P_("Color Hash"),
701                                                                  P_("A hash table representation of the color scheme."),
702                                                                  G_TYPE_HASH_TABLE,
703                                                                  GTK_PARAM_READABLE),
704                                              NULL);
705   g_assert (result == PROP_COLOR_HASH);
706
707   result = settings_install_property_parser (class, 
708                                              g_param_spec_string ("gtk-file-chooser-backend",
709                                                                   P_("Default file chooser backend"),
710                                                                   P_("Name of the GtkFileChooser backend to use by default"),
711                                                                   NULL,
712                                                                   GTK_PARAM_READWRITE),
713                                              NULL);
714   g_assert (result == PROP_FILE_CHOOSER_BACKEND);
715
716   /**
717    * GtkSettings:gtk-print-backends:
718    *
719    * A comma-separated list of print backends to use in the print
720    * dialog. Available print backends depend on the GTK+ installation,
721    * and may include "pdf", "cups" or "lpr".
722    *
723    * Since: 2.10
724    */
725   result = settings_install_property_parser (class,
726                                              g_param_spec_string ("gtk-print-backends",
727                                                                   P_("Default print backend"),
728                                                                   P_("List of the GtkPrintBackend backends to use by default"),
729                                                                   GTK_PRINT_BACKENDS,
730                                                                   GTK_PARAM_READWRITE),
731                                              NULL);
732   g_assert (result == PROP_PRINT_BACKENDS);
733
734   /**
735    * GtkSettings:gtk-print-preview-command:
736    *
737    * A command to run for displaying the print preview. The command
738    * should contain a %f placeholder, which will get replaced by
739    * the path to the pdf file. The command may also contain a %s
740    * placeholder, which will get replaced by the path to a file
741    * containing the print settings in the format produced by 
742    * gtk_print_settings_to_file().
743    *
744    * The preview application is responsible for removing the pdf file
745    * and the print settings file when it is done.
746    *
747    * Since: 2.10
748    */
749   result = settings_install_property_parser (class,
750                                              g_param_spec_string ("gtk-print-preview-command",
751                                                                   P_("Default command to run when displaying a print preview"),
752                                                                   P_("Command to run when displaying a print preview"),
753                                                                   GTK_PRINT_PREVIEW_COMMAND,
754                                                                   GTK_PARAM_READWRITE),
755                                              NULL); 
756   g_assert (result == PROP_PRINT_PREVIEW_COMMAND);
757
758   /**
759    * GtkSettings:gtk-enable-mnemonics:
760    *
761    * Whether labels and menu items should have visible mnemonics which
762    * can be activated.
763    *
764    * Since: 2.12
765    */
766   result = settings_install_property_parser (class,
767                                              g_param_spec_boolean ("gtk-enable-mnemonics",
768                                                                    P_("Enable Mnemonics"),
769                                                                    P_("Whether labels should have mnemonics"),
770                                                                    TRUE,
771                                                                    GTK_PARAM_READWRITE),
772                                              NULL);
773   g_assert (result == PROP_ENABLE_MNEMONICS);
774
775   /**
776    * GtkSettings:gtk-enable-accels:
777    *
778    * Whether menu items should have visible accelerators which can be
779    * activated.
780    *
781    * Since: 2.12
782    */
783   result = settings_install_property_parser (class,
784                                              g_param_spec_boolean ("gtk-enable-accels",
785                                                                    P_("Enable Accelerators"),
786                                                                    P_("Whether menu items should have accelerators"),
787                                                                    TRUE,
788                                                                    GTK_PARAM_READWRITE),
789                                              NULL);
790   g_assert (result == PROP_ENABLE_ACCELS);
791
792   /**
793    * GtkSettings:gtk-recent-files-limit:
794    *
795    * The number of recently used files that should be displayed by default by
796    * #GtkRecentChooser implementations and by the #GtkFileChooser. A value of
797    * -1 means every recently used file stored.
798    *
799    * Since: 2.12
800    */
801   result = settings_install_property_parser (class,
802                                              g_param_spec_int ("gtk-recent-files-limit",
803                                                                P_("Recent Files Limit"),
804                                                                P_("Number of recently used files"),
805                                                                -1, G_MAXINT,
806                                                                50,
807                                                                GTK_PARAM_READWRITE),
808                                              NULL);
809   g_assert (result == PROP_RECENT_FILES_LIMIT);
810
811   /**
812    * GtkSettings:gtk-im-module:
813    *
814    * Which IM module should be used by default.
815    */
816   result = settings_install_property_parser (class,
817                                              g_param_spec_string ("gtk-im-module",
818                                                                   P_("Default IM module"),
819                                                                   P_("Which IM module should be used by default"),
820                                                                   NULL,
821                                                                   GTK_PARAM_READWRITE),
822                                              NULL);
823   g_assert (result == PROP_IM_MODULE);
824
825   /**
826    * GtkSettings:gtk-recent-files-max-age:
827    *
828    * The maximum age, in days, of the items inside the recently used
829    * resources list. Items older than this setting will be excised
830    * from the list. If set to 0, the list will always be empty; if
831    * set to -1, no item will be removed.
832    *
833    * Since: 2.14
834    */
835   result = settings_install_property_parser (class,
836                                              g_param_spec_int ("gtk-recent-files-max-age",
837                                                                P_("Recent Files Max Age"),
838                                                                P_("Maximum age of recently used files, in days"),
839                                                                -1, G_MAXINT,
840                                                                30,
841                                                                GTK_PARAM_READWRITE),
842                                              NULL);
843   g_assert (result == PROP_RECENT_FILES_MAX_AGE);
844 }
845
846 static void
847 gtk_settings_finalize (GObject *object)
848 {
849   GtkSettings *settings = GTK_SETTINGS (object);
850   guint i;
851
852   object_list = g_slist_remove (object_list, settings);
853
854   _gtk_rc_context_destroy (settings);
855
856   for (i = 0; i < class_n_properties; i++)
857     g_value_unset (&settings->property_values[i].value);
858   g_free (settings->property_values);
859   
860   g_datalist_clear (&settings->queued_settings);
861
862   G_OBJECT_CLASS (gtk_settings_parent_class)->finalize (object);
863 }
864
865 /**
866  * gtk_settings_get_for_screen:
867  * @screen : a #GdkScreen.
868  * 
869  * Gets the #GtkSettings object for @screen, creating it if necessary.
870  *
871  * Return value: a #GtkSettings object.
872  *
873  * Since: 2.2
874  */
875 GtkSettings*
876 gtk_settings_get_for_screen (GdkScreen *screen)
877 {
878   GtkSettings *settings;
879   
880   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
881   
882   settings = g_object_get_data (G_OBJECT (screen), "gtk-settings");
883   if (!settings)
884     {
885       settings = g_object_new (GTK_TYPE_SETTINGS, NULL);
886       settings->screen = screen;
887       g_object_set_data_full (G_OBJECT (screen), I_("gtk-settings"), 
888                               settings, g_object_unref);
889
890       gtk_rc_reparse_all_for_settings (settings, TRUE);
891       settings_update_double_click (settings);
892 #ifdef GDK_WINDOWING_X11
893       settings_update_cursor_theme (settings);
894       settings_update_resolution (settings);
895       settings_update_font_options (settings);
896 #endif
897       settings_update_color_scheme (settings);
898     }
899   
900   return settings;
901 }
902
903 /**
904  * gtk_settings_get_default:
905  * 
906  * Gets the #GtkSettings object for the default GDK screen, creating
907  * it if necessary. See gtk_settings_get_for_screen().
908  * 
909  * Return value: a #GtkSettings object. If there is no default
910  *  screen, then returns %NULL.
911  **/
912 GtkSettings*
913 gtk_settings_get_default (void)
914 {
915   GdkScreen *screen = gdk_screen_get_default ();
916
917   if (screen)
918     return gtk_settings_get_for_screen (screen);
919   else
920     return NULL;
921 }
922
923 static void
924 gtk_settings_set_property (GObject      *object,
925                            guint         property_id,
926                            const GValue *value,
927                            GParamSpec   *pspec)
928 {
929   GtkSettings *settings = GTK_SETTINGS (object);
930
931   g_value_copy (value, &settings->property_values[property_id - 1].value);
932   settings->property_values[property_id - 1].source = GTK_SETTINGS_SOURCE_APPLICATION;
933   
934   if (pspec->param_id == PROP_COLOR_SCHEME)
935     merge_color_scheme (settings, value, GTK_SETTINGS_SOURCE_APPLICATION);
936 }
937
938 static void
939 gtk_settings_get_property (GObject     *object,
940                            guint        property_id,
941                            GValue      *value,
942                            GParamSpec  *pspec)
943 {
944   GtkSettings *settings = GTK_SETTINGS (object);
945   GType value_type = G_VALUE_TYPE (value);
946   GType fundamental_type = G_TYPE_FUNDAMENTAL (value_type);
947
948   /* handle internal properties */
949   switch (property_id)
950     {
951     case PROP_COLOR_HASH:
952       g_value_set_boxed (value, get_color_hash (settings));
953       return;
954     case PROP_COLOR_SCHEME:
955       g_value_take_string (value, get_color_scheme (settings));
956       return;
957     default: ;
958     }
959
960   /* For enums and strings, we need to get the value as a string,
961    * not as an int, since we support using names/nicks as the setting
962    * value.
963    */
964   if ((g_value_type_transformable (G_TYPE_INT, value_type) &&
965        !(fundamental_type == G_TYPE_ENUM || fundamental_type == G_TYPE_FLAGS)) ||
966       g_value_type_transformable (G_TYPE_STRING, G_VALUE_TYPE (value)) ||
967       g_value_type_transformable (GDK_TYPE_COLOR, G_VALUE_TYPE (value)))
968     {
969       if (settings->property_values[property_id - 1].source == GTK_SETTINGS_SOURCE_APPLICATION ||
970           !gdk_screen_get_setting (settings->screen, pspec->name, value))
971         g_value_copy (&settings->property_values[property_id - 1].value, value);
972       else 
973         g_param_value_validate (pspec, value);
974     }
975   else
976     {
977       GValue val = { 0, };
978
979       /* Try to get xsetting as a string and parse it. */
980       
981       g_value_init (&val, G_TYPE_STRING);
982
983       if (settings->property_values[property_id - 1].source == GTK_SETTINGS_SOURCE_APPLICATION ||
984           !gdk_screen_get_setting (settings->screen, pspec->name, &val))
985         {
986           g_value_copy (&settings->property_values[property_id - 1].value, value);
987         }
988       else
989         {
990           GValue tmp_value = { 0, };
991           GValue gstring_value = { 0, };
992           GtkRcPropertyParser parser = (GtkRcPropertyParser) g_param_spec_get_qdata (pspec, quark_property_parser);
993           
994           g_value_init (&gstring_value, G_TYPE_GSTRING);
995           g_value_take_boxed (&gstring_value,
996                               g_string_new (g_value_get_string (&val)));
997
998           g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
999
1000           if (parser && _gtk_settings_parse_convert (parser, &gstring_value,
1001                                                      pspec, &tmp_value))
1002             {
1003               g_value_copy (&tmp_value, value);
1004               g_param_value_validate (pspec, value);
1005             }
1006           else
1007             {
1008               g_value_copy (&settings->property_values[property_id - 1].value, value);
1009             }
1010
1011           g_value_unset (&gstring_value);
1012           g_value_unset (&tmp_value);
1013         }
1014
1015       g_value_unset (&val);
1016     }
1017 }
1018
1019 static void
1020 gtk_settings_notify (GObject    *object,
1021                      GParamSpec *pspec)
1022 {
1023   GtkSettings *settings = GTK_SETTINGS (object);
1024   guint property_id = pspec->param_id;
1025
1026   if (settings->screen == NULL) /* initialization */
1027     return;
1028
1029   switch (property_id)
1030     {
1031     case PROP_MODULES:
1032       settings_update_modules (settings);
1033       break;
1034     case PROP_DOUBLE_CLICK_TIME:
1035     case PROP_DOUBLE_CLICK_DISTANCE:
1036       settings_update_double_click (settings);
1037       break;
1038     case PROP_COLOR_SCHEME:
1039       settings_update_color_scheme (settings);
1040       break;
1041 #ifdef GDK_WINDOWING_X11
1042     case PROP_XFT_DPI:
1043       settings_update_resolution (settings);
1044       /* This is a hack because with gtk_rc_reset_styles() doesn't get
1045        * widgets with gtk_widget_style_set(), and also causes more
1046        * recomputation than necessary.
1047        */
1048       gtk_rc_reset_styles (GTK_SETTINGS (object));
1049       break;
1050     case PROP_XFT_ANTIALIAS:
1051     case PROP_XFT_HINTING:
1052     case PROP_XFT_HINTSTYLE:
1053     case PROP_XFT_RGBA:
1054       settings_update_font_options (settings);
1055       gtk_rc_reset_styles (GTK_SETTINGS (object));
1056       break;
1057     case PROP_CURSOR_THEME_NAME:
1058     case PROP_CURSOR_THEME_SIZE:
1059       settings_update_cursor_theme (settings);
1060       break;
1061 #endif /* GDK_WINDOWING_X11 */
1062     }
1063 }
1064
1065 gboolean
1066 _gtk_settings_parse_convert (GtkRcPropertyParser parser,
1067                              const GValue       *src_value,
1068                              GParamSpec         *pspec,
1069                              GValue             *dest_value)
1070 {
1071   gboolean success = FALSE;
1072
1073   g_return_val_if_fail (G_VALUE_HOLDS (dest_value, G_PARAM_SPEC_VALUE_TYPE (pspec)), FALSE);
1074
1075   if (parser)
1076     {
1077       GString *gstring;
1078       gboolean free_gstring = TRUE;
1079       
1080       if (G_VALUE_HOLDS (src_value, G_TYPE_GSTRING))
1081         {
1082           gstring = g_value_get_boxed (src_value);
1083           free_gstring = FALSE;
1084         }
1085       else if (G_VALUE_HOLDS_LONG (src_value))
1086         {
1087           gstring = g_string_new (NULL);
1088           g_string_append_printf (gstring, "%ld", g_value_get_long (src_value));
1089         }
1090       else if (G_VALUE_HOLDS_DOUBLE (src_value))
1091         {
1092           gstring = g_string_new (NULL);
1093           g_string_append_printf (gstring, "%f", g_value_get_double (src_value));
1094         }
1095       else if (G_VALUE_HOLDS_STRING (src_value))
1096         {
1097           gchar *tstr = g_strescape (g_value_get_string (src_value), NULL);
1098           
1099           gstring = g_string_new ("\"");
1100           g_string_append (gstring, tstr);
1101           g_string_append_c (gstring, '\"');
1102           g_free (tstr);
1103         }
1104       else
1105         {
1106           g_return_val_if_fail (G_VALUE_HOLDS (src_value, G_TYPE_GSTRING), FALSE);
1107           gstring = NULL; /* silence compiler */
1108         }
1109
1110       success = (parser (pspec, gstring, dest_value) &&
1111                  !g_param_value_validate (pspec, dest_value));
1112
1113       if (free_gstring)
1114         g_string_free (gstring, TRUE);
1115     }
1116   else if (G_VALUE_HOLDS (src_value, G_TYPE_GSTRING))
1117     {
1118       if (G_VALUE_HOLDS (dest_value, G_TYPE_STRING))
1119         {
1120           GString *gstring = g_value_get_boxed (src_value);
1121
1122           g_value_set_string (dest_value, gstring ? gstring->str : NULL);
1123           success = !g_param_value_validate (pspec, dest_value);
1124         }
1125     }
1126   else if (g_value_type_transformable (G_VALUE_TYPE (src_value), G_VALUE_TYPE (dest_value)))
1127     success = g_param_value_convert (pspec, src_value, dest_value, TRUE);
1128
1129   return success;
1130 }
1131
1132 static void
1133 apply_queued_setting (GtkSettings             *data,
1134                       GParamSpec              *pspec,
1135                       GtkSettingsValuePrivate *qvalue)
1136 {
1137   GValue tmp_value = { 0, };
1138   GtkRcPropertyParser parser = (GtkRcPropertyParser) g_param_spec_get_qdata (pspec, quark_property_parser);
1139
1140   g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1141   if (_gtk_settings_parse_convert (parser, &qvalue->public.value,
1142                                    pspec, &tmp_value))
1143     {
1144       if (pspec->param_id == PROP_COLOR_SCHEME) 
1145         merge_color_scheme (data, &tmp_value, qvalue->source);
1146
1147       if (data->property_values[pspec->param_id - 1].source <= qvalue->source)
1148         {
1149           g_value_copy (&tmp_value, &data->property_values[pspec->param_id - 1].value);
1150           data->property_values[pspec->param_id - 1].source = qvalue->source;
1151           g_object_notify (G_OBJECT (data), g_param_spec_get_name (pspec));
1152         }
1153
1154     }
1155   else
1156     {
1157       gchar *debug = g_strdup_value_contents (&qvalue->public.value);
1158       
1159       g_message ("%s: failed to retrieve property `%s' of type `%s' from rc file value \"%s\" of type `%s'",
1160                  qvalue->public.origin ? qvalue->public.origin : "(for origin information, set GTK_DEBUG)",
1161                  pspec->name,
1162                  g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1163                  debug,
1164                  G_VALUE_TYPE_NAME (&tmp_value));
1165       g_free (debug);
1166     }
1167   g_value_unset (&tmp_value);
1168 }
1169
1170 static guint
1171 settings_install_property_parser (GtkSettingsClass   *class,
1172                                   GParamSpec         *pspec,
1173                                   GtkRcPropertyParser parser)
1174 {
1175   GSList *node, *next;
1176
1177   switch (G_TYPE_FUNDAMENTAL (G_PARAM_SPEC_VALUE_TYPE (pspec)))
1178     {
1179     case G_TYPE_BOOLEAN:
1180     case G_TYPE_UCHAR:
1181     case G_TYPE_CHAR:
1182     case G_TYPE_UINT:
1183     case G_TYPE_INT:
1184     case G_TYPE_ULONG:
1185     case G_TYPE_LONG:
1186     case G_TYPE_FLOAT:
1187     case G_TYPE_DOUBLE:
1188     case G_TYPE_STRING:
1189       break;
1190     case G_TYPE_BOXED:
1191       if (strcmp (g_param_spec_get_name (pspec), "color-hash") == 0)
1192         {
1193           break;
1194         }
1195       /* fall through */
1196     default:
1197       if (!parser)
1198         {
1199           g_warning (G_STRLOC ": parser needs to be specified for property \"%s\" of type `%s'",
1200                      pspec->name, g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
1201           return 0;
1202         }
1203     }
1204   if (g_object_class_find_property (G_OBJECT_CLASS (class), pspec->name))
1205     {
1206       g_warning (G_STRLOC ": an rc-data property \"%s\" already exists",
1207                  pspec->name);
1208       return 0;
1209     }
1210   
1211   for (node = object_list; node; node = node->next)
1212     g_object_freeze_notify (node->data);
1213
1214   g_object_class_install_property (G_OBJECT_CLASS (class), ++class_n_properties, pspec);
1215   g_param_spec_set_qdata (pspec, quark_property_parser, (gpointer) parser);
1216
1217   for (node = object_list; node; node = node->next)
1218     {
1219       GtkSettings *settings = node->data;
1220       GtkSettingsValuePrivate *qvalue;
1221       
1222       settings->property_values = g_renew (GtkSettingsPropertyValue, settings->property_values, class_n_properties);
1223       settings->property_values[class_n_properties - 1].value.g_type = 0;
1224       g_value_init (&settings->property_values[class_n_properties - 1].value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1225       g_param_value_set_default (pspec, &settings->property_values[class_n_properties - 1].value);
1226       settings->property_values[class_n_properties - 1].source = GTK_SETTINGS_SOURCE_DEFAULT;
1227       g_object_notify (G_OBJECT (settings), pspec->name);
1228       
1229       qvalue = g_datalist_get_data (&settings->queued_settings, pspec->name);
1230       if (qvalue)
1231         apply_queued_setting (settings, pspec, qvalue);
1232     }
1233
1234   for (node = object_list; node; node = next)
1235     {
1236       next = node->next;
1237       g_object_thaw_notify (node->data);
1238     }
1239
1240   return class_n_properties;
1241 }
1242
1243 GtkRcPropertyParser
1244 _gtk_rc_property_parser_from_type (GType type)
1245 {
1246   if (type == GDK_TYPE_COLOR)
1247     return gtk_rc_property_parse_color;
1248   else if (type == GTK_TYPE_REQUISITION)
1249     return gtk_rc_property_parse_requisition;
1250   else if (type == GTK_TYPE_BORDER)
1251     return gtk_rc_property_parse_border;
1252   else if (G_TYPE_FUNDAMENTAL (type) == G_TYPE_ENUM && G_TYPE_IS_DERIVED (type))
1253     return gtk_rc_property_parse_enum;
1254   else if (G_TYPE_FUNDAMENTAL (type) == G_TYPE_FLAGS && G_TYPE_IS_DERIVED (type))
1255     return gtk_rc_property_parse_flags;
1256   else
1257     return NULL;
1258 }
1259
1260 void
1261 gtk_settings_install_property (GParamSpec *pspec)
1262 {
1263   GtkRcPropertyParser parser;
1264
1265   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1266
1267   parser = _gtk_rc_property_parser_from_type (G_PARAM_SPEC_VALUE_TYPE (pspec));
1268
1269   settings_install_property_parser (gtk_type_class (GTK_TYPE_SETTINGS), pspec, parser);
1270 }
1271
1272 void
1273 gtk_settings_install_property_parser (GParamSpec          *pspec,
1274                                       GtkRcPropertyParser  parser)
1275 {
1276   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1277   g_return_if_fail (parser != NULL);
1278   
1279   settings_install_property_parser (gtk_type_class (GTK_TYPE_SETTINGS), pspec, parser);
1280 }
1281
1282 static void
1283 free_value (gpointer data)
1284 {
1285   GtkSettingsValuePrivate *qvalue = data;
1286   
1287   g_value_unset (&qvalue->public.value);
1288   g_free (qvalue->public.origin);
1289   g_slice_free (GtkSettingsValuePrivate, qvalue);
1290 }
1291
1292 static void
1293 gtk_settings_set_property_value_internal (GtkSettings            *settings,
1294                                           const gchar            *prop_name,
1295                                           const GtkSettingsValue *new_value,
1296                                           GtkSettingsSource       source)
1297 {
1298   GtkSettingsValuePrivate *qvalue;
1299   GParamSpec *pspec;
1300   gchar *name;
1301   GQuark name_quark;
1302
1303   if (!G_VALUE_HOLDS_LONG (&new_value->value) &&
1304       !G_VALUE_HOLDS_DOUBLE (&new_value->value) &&
1305       !G_VALUE_HOLDS_STRING (&new_value->value) &&
1306       !G_VALUE_HOLDS (&new_value->value, G_TYPE_GSTRING))
1307     {
1308       g_warning (G_STRLOC ": value type invalid");
1309       return;
1310     }
1311   
1312   name = g_strdup (prop_name);
1313   g_strcanon (name, G_CSET_DIGITS "-" G_CSET_a_2_z G_CSET_A_2_Z, '-');
1314   name_quark = g_quark_from_string (name);
1315   g_free (name);
1316
1317   qvalue = g_datalist_id_get_data (&settings->queued_settings, name_quark);
1318   if (!qvalue)
1319     {
1320       qvalue = g_slice_new0 (GtkSettingsValuePrivate);
1321       g_datalist_id_set_data_full (&settings->queued_settings, name_quark, qvalue, free_value);
1322     }
1323   else
1324     {
1325       g_free (qvalue->public.origin);
1326       g_value_unset (&qvalue->public.value);
1327     }
1328   qvalue->public.origin = g_strdup (new_value->origin);
1329   g_value_init (&qvalue->public.value, G_VALUE_TYPE (&new_value->value));
1330   g_value_copy (&new_value->value, &qvalue->public.value);
1331   qvalue->source = source;
1332   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (settings), g_quark_to_string (name_quark));
1333   if (pspec)
1334     apply_queued_setting (settings, pspec, qvalue);
1335 }
1336
1337 void
1338 gtk_settings_set_property_value (GtkSettings            *settings,
1339                                  const gchar            *prop_name,
1340                                  const GtkSettingsValue *new_value)
1341 {
1342   g_return_if_fail (GTK_SETTINGS (settings));
1343   g_return_if_fail (prop_name != NULL);
1344   g_return_if_fail (new_value != NULL);
1345
1346   gtk_settings_set_property_value_internal (settings, prop_name, new_value,
1347                                             GTK_SETTINGS_SOURCE_APPLICATION);
1348 }
1349
1350 void
1351 _gtk_settings_set_property_value_from_rc (GtkSettings            *settings,
1352                                           const gchar            *prop_name,
1353                                           const GtkSettingsValue *new_value)
1354 {
1355   g_return_if_fail (GTK_SETTINGS (settings));
1356   g_return_if_fail (prop_name != NULL);
1357   g_return_if_fail (new_value != NULL);
1358
1359   gtk_settings_set_property_value_internal (settings, prop_name, new_value,
1360                                             GTK_SETTINGS_SOURCE_RC_FILE);
1361 }
1362
1363 void
1364 gtk_settings_set_string_property (GtkSettings *settings,
1365                                   const gchar *name,
1366                                   const gchar *v_string,
1367                                   const gchar *origin)
1368 {
1369   GtkSettingsValue svalue = { NULL, { 0, }, };
1370
1371   g_return_if_fail (GTK_SETTINGS (settings));
1372   g_return_if_fail (name != NULL);
1373   g_return_if_fail (v_string != NULL);
1374
1375   svalue.origin = (gchar*) origin;
1376   g_value_init (&svalue.value, G_TYPE_STRING);
1377   g_value_set_static_string (&svalue.value, v_string);
1378   gtk_settings_set_property_value (settings, name, &svalue);
1379   g_value_unset (&svalue.value);
1380 }
1381
1382 void
1383 gtk_settings_set_long_property (GtkSettings *settings,
1384                                 const gchar *name,
1385                                 glong        v_long,
1386                                 const gchar *origin)
1387 {
1388   GtkSettingsValue svalue = { NULL, { 0, }, };
1389   
1390   g_return_if_fail (GTK_SETTINGS (settings));
1391   g_return_if_fail (name != NULL);
1392
1393   svalue.origin = (gchar*) origin;
1394   g_value_init (&svalue.value, G_TYPE_LONG);
1395   g_value_set_long (&svalue.value, v_long);
1396   gtk_settings_set_property_value (settings, name, &svalue);
1397   g_value_unset (&svalue.value);
1398 }
1399
1400 void
1401 gtk_settings_set_double_property (GtkSettings *settings,
1402                                   const gchar *name,
1403                                   gdouble      v_double,
1404                                   const gchar *origin)
1405 {
1406   GtkSettingsValue svalue = { NULL, { 0, }, };
1407
1408   g_return_if_fail (GTK_SETTINGS (settings));
1409   g_return_if_fail (name != NULL);
1410
1411   svalue.origin = (gchar*) origin;
1412   g_value_init (&svalue.value, G_TYPE_DOUBLE);
1413   g_value_set_double (&svalue.value, v_double);
1414   gtk_settings_set_property_value (settings, name, &svalue);
1415   g_value_unset (&svalue.value);
1416 }
1417
1418 /**
1419  * gtk_rc_property_parse_color:
1420  * @pspec: a #GParamSpec
1421  * @gstring: the #GString to be parsed
1422  * @property_value: a #GValue which must hold #GdkColor values.
1423  * 
1424  * A #GtkRcPropertyParser for use with gtk_settings_install_property_parser()
1425  * or gtk_widget_class_install_style_property_parser() which parses a
1426  * color given either by its name or in the form 
1427  * <literal>{ red, green, blue }</literal> where %red, %green and
1428  * %blue are integers between 0 and 65535 or floating-point numbers
1429  * between 0 and 1.
1430  * 
1431  * Return value: %TRUE if @gstring could be parsed and @property_value
1432  * has been set to the resulting #GdkColor.
1433  **/
1434 gboolean
1435 gtk_rc_property_parse_color (const GParamSpec *pspec,
1436                              const GString    *gstring,
1437                              GValue           *property_value)
1438 {
1439   GdkColor color = { 0, 0, 0, 0, };
1440   GScanner *scanner;
1441   gboolean success;
1442
1443   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
1444   g_return_val_if_fail (G_VALUE_HOLDS (property_value, GDK_TYPE_COLOR), FALSE);
1445
1446   scanner = gtk_rc_scanner_new ();
1447   g_scanner_input_text (scanner, gstring->str, gstring->len);
1448   if (gtk_rc_parse_color (scanner, &color) == G_TOKEN_NONE &&
1449       g_scanner_get_next_token (scanner) == G_TOKEN_EOF)
1450     {
1451       g_value_set_boxed (property_value, &color);
1452       success = TRUE;
1453     }
1454   else
1455     success = FALSE;
1456   g_scanner_destroy (scanner);
1457
1458   return success;
1459 }
1460
1461 /**
1462  * gtk_rc_property_parse_enum:
1463  * @pspec: a #GParamSpec
1464  * @gstring: the #GString to be parsed
1465  * @property_value: a #GValue which must hold enum values.
1466  * 
1467  * A #GtkRcPropertyParser for use with gtk_settings_install_property_parser()
1468  * or gtk_widget_class_install_style_property_parser() which parses a single
1469  * enumeration value.
1470  *
1471  * The enumeration value can be specified by its name, its nickname or
1472  * its numeric value. For consistency with flags parsing, the value
1473  * may be surrounded by parentheses.
1474  * 
1475  * Return value: %TRUE if @gstring could be parsed and @property_value
1476  * has been set to the resulting #GEnumValue.
1477  **/
1478 gboolean
1479 gtk_rc_property_parse_enum (const GParamSpec *pspec,
1480                             const GString    *gstring,
1481                             GValue           *property_value)
1482 {
1483   gboolean need_closing_brace = FALSE, success = FALSE;
1484   GScanner *scanner;
1485   GEnumValue *enum_value = NULL;
1486
1487   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
1488   g_return_val_if_fail (G_VALUE_HOLDS_ENUM (property_value), FALSE);
1489
1490   scanner = gtk_rc_scanner_new ();
1491   g_scanner_input_text (scanner, gstring->str, gstring->len);
1492
1493   /* we just want to parse _one_ value, but for consistency with flags parsing
1494    * we support optional parenthesis
1495    */
1496   g_scanner_get_next_token (scanner);
1497   if (scanner->token == '(')
1498     {
1499       need_closing_brace = TRUE;
1500       g_scanner_get_next_token (scanner);
1501     }
1502   if (scanner->token == G_TOKEN_IDENTIFIER)
1503     {
1504       GEnumClass *class = G_PARAM_SPEC_ENUM (pspec)->enum_class;
1505       
1506       enum_value = g_enum_get_value_by_name (class, scanner->value.v_identifier);
1507       if (!enum_value)
1508         enum_value = g_enum_get_value_by_nick (class, scanner->value.v_identifier);
1509       if (enum_value)
1510         {
1511           g_value_set_enum (property_value, enum_value->value);
1512           success = TRUE;
1513         }
1514     }
1515   else if (scanner->token == G_TOKEN_INT)
1516     {
1517       g_value_set_enum (property_value, scanner->value.v_int);
1518       success = TRUE;
1519     }
1520   if (need_closing_brace && g_scanner_get_next_token (scanner) != ')')
1521     success = FALSE;
1522   if (g_scanner_get_next_token (scanner) != G_TOKEN_EOF)
1523     success = FALSE;
1524
1525   g_scanner_destroy (scanner);
1526
1527   return success;
1528 }
1529
1530 static guint
1531 parse_flags_value (GScanner    *scanner,
1532                    GFlagsClass *class,
1533                    guint       *number)
1534 {
1535   g_scanner_get_next_token (scanner);
1536   if (scanner->token == G_TOKEN_IDENTIFIER)
1537     {
1538       GFlagsValue *flags_value;
1539
1540       flags_value = g_flags_get_value_by_name (class, scanner->value.v_identifier);
1541       if (!flags_value)
1542         flags_value = g_flags_get_value_by_nick (class, scanner->value.v_identifier);
1543       if (flags_value)
1544         {
1545           *number |= flags_value->value;
1546           return G_TOKEN_NONE;
1547         }
1548     }
1549   else if (scanner->token == G_TOKEN_INT)
1550     {
1551       *number |= scanner->value.v_int;
1552       return G_TOKEN_NONE;
1553     }
1554   return G_TOKEN_IDENTIFIER;
1555 }
1556
1557 /**
1558  * gtk_rc_property_parse_flags:
1559  * @pspec: a #GParamSpec
1560  * @gstring: the #GString to be parsed
1561  * @property_value: a #GValue which must hold flags values.
1562  * 
1563  * A #GtkRcPropertyParser for use with gtk_settings_install_property_parser()
1564  * or gtk_widget_class_install_style_property_parser() which parses flags. 
1565  * 
1566  * Flags can be specified by their name, their nickname or
1567  * numerically. Multiple flags can be specified in the form 
1568  * <literal>"( flag1 | flag2 | ... )"</literal>.
1569  * 
1570  * Return value: %TRUE if @gstring could be parsed and @property_value
1571  * has been set to the resulting flags value.
1572  **/
1573 gboolean
1574 gtk_rc_property_parse_flags (const GParamSpec *pspec,
1575                              const GString    *gstring,
1576                              GValue           *property_value)
1577 {
1578   GFlagsClass *class;
1579    gboolean success = FALSE;
1580   GScanner *scanner;
1581
1582   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
1583   g_return_val_if_fail (G_VALUE_HOLDS_FLAGS (property_value), FALSE);
1584
1585   class = G_PARAM_SPEC_FLAGS (pspec)->flags_class;
1586   scanner = gtk_rc_scanner_new ();
1587   g_scanner_input_text (scanner, gstring->str, gstring->len);
1588
1589   /* parse either a single flags value or a "\( ... [ \| ... ] \)" compound */
1590   if (g_scanner_peek_next_token (scanner) == G_TOKEN_IDENTIFIER ||
1591       scanner->next_token == G_TOKEN_INT)
1592     {
1593       guint token, flags_value = 0;
1594       
1595       token = parse_flags_value (scanner, class, &flags_value);
1596
1597       if (token == G_TOKEN_NONE && g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
1598         {
1599           success = TRUE;
1600           g_value_set_flags (property_value, flags_value);
1601         }
1602       
1603     }
1604   else if (g_scanner_get_next_token (scanner) == '(')
1605     {
1606       guint token, flags_value = 0;
1607
1608       /* parse first value */
1609       token = parse_flags_value (scanner, class, &flags_value);
1610
1611       /* parse nth values, preceeded by '|' */
1612       while (token == G_TOKEN_NONE && g_scanner_get_next_token (scanner) == '|')
1613         token = parse_flags_value (scanner, class, &flags_value);
1614
1615       /* done, last token must have closed expression */
1616       if (token == G_TOKEN_NONE && scanner->token == ')' &&
1617           g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
1618         {
1619           g_value_set_flags (property_value, flags_value);
1620           success = TRUE;
1621         }
1622     }
1623   g_scanner_destroy (scanner);
1624
1625   return success;
1626 }
1627
1628 static gboolean
1629 get_braced_int (GScanner *scanner,
1630                 gboolean  first,
1631                 gboolean  last,
1632                 gint     *value)
1633 {
1634   if (first)
1635     {
1636       g_scanner_get_next_token (scanner);
1637       if (scanner->token != '{')
1638         return FALSE;
1639     }
1640
1641   g_scanner_get_next_token (scanner);
1642   if (scanner->token != G_TOKEN_INT)
1643     return FALSE;
1644
1645   *value = scanner->value.v_int;
1646
1647   if (last)
1648     {
1649       g_scanner_get_next_token (scanner);
1650       if (scanner->token != '}')
1651         return FALSE;
1652     }
1653   else
1654     {
1655       g_scanner_get_next_token (scanner);
1656       if (scanner->token != ',')
1657         return FALSE;
1658     }
1659
1660   return TRUE;
1661 }
1662
1663 /**
1664  * gtk_rc_property_parse_requisition:
1665  * @pspec: a #GParamSpec
1666  * @gstring: the #GString to be parsed
1667  * @property_value: a #GValue which must hold boxed values.
1668  * 
1669  * A #GtkRcPropertyParser for use with gtk_settings_install_property_parser()
1670  * or gtk_widget_class_install_style_property_parser() which parses a
1671  * requisition in the form 
1672  * <literal>"{ width, height }"</literal> for integers %width and %height.
1673  * 
1674  * Return value: %TRUE if @gstring could be parsed and @property_value
1675  * has been set to the resulting #GtkRequisition.
1676  **/
1677 gboolean
1678 gtk_rc_property_parse_requisition  (const GParamSpec *pspec,
1679                                     const GString    *gstring,
1680                                     GValue           *property_value)
1681 {
1682   GtkRequisition requisition;
1683   GScanner *scanner;
1684   gboolean success = FALSE;
1685
1686   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
1687   g_return_val_if_fail (G_VALUE_HOLDS_BOXED (property_value), FALSE);
1688
1689   scanner = gtk_rc_scanner_new ();
1690   g_scanner_input_text (scanner, gstring->str, gstring->len);
1691
1692   if (get_braced_int (scanner, TRUE, FALSE, &requisition.width) &&
1693       get_braced_int (scanner, FALSE, TRUE, &requisition.height))
1694     {
1695       g_value_set_boxed (property_value, &requisition);
1696       success = TRUE;
1697     }
1698
1699   g_scanner_destroy (scanner);
1700
1701   return success;
1702 }
1703
1704 /**
1705  * gtk_rc_property_parse_border:
1706  * @pspec: a #GParamSpec
1707  * @gstring: the #GString to be parsed
1708  * @property_value: a #GValue which must hold boxed values.
1709  * 
1710  * A #GtkRcPropertyParser for use with gtk_settings_install_property_parser()
1711  * or gtk_widget_class_install_style_property_parser() which parses
1712  * borders in the form 
1713  * <literal>"{ left, right, top, bottom }"</literal> for integers 
1714  * %left, %right, %top and %bottom.
1715  * 
1716  * Return value: %TRUE if @gstring could be parsed and @property_value
1717  * has been set to the resulting #GtkBorder.
1718  **/
1719 gboolean
1720 gtk_rc_property_parse_border (const GParamSpec *pspec,
1721                               const GString    *gstring,
1722                               GValue           *property_value)
1723 {
1724   GtkBorder border;
1725   GScanner *scanner;
1726   gboolean success = FALSE;
1727
1728   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
1729   g_return_val_if_fail (G_VALUE_HOLDS_BOXED (property_value), FALSE);
1730
1731   scanner = gtk_rc_scanner_new ();
1732   g_scanner_input_text (scanner, gstring->str, gstring->len);
1733
1734   if (get_braced_int (scanner, TRUE, FALSE, &border.left) &&
1735       get_braced_int (scanner, FALSE, FALSE, &border.right) &&
1736       get_braced_int (scanner, FALSE, FALSE, &border.top) &&
1737       get_braced_int (scanner, FALSE, TRUE, &border.bottom))
1738     {
1739       g_value_set_boxed (property_value, &border);
1740       success = TRUE;
1741     }
1742
1743   g_scanner_destroy (scanner);
1744
1745   return success;
1746 }
1747
1748 void
1749 _gtk_settings_handle_event (GdkEventSetting *event)
1750 {
1751   GtkSettings *settings;
1752   GParamSpec *pspec;
1753   guint property_id;
1754
1755   settings = gtk_settings_get_for_screen (gdk_drawable_get_screen (event->window));
1756   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (settings), event->name);
1757  
1758   if (pspec) 
1759     {
1760       property_id = pspec->param_id;
1761
1762       if (property_id == PROP_COLOR_SCHEME)
1763         {
1764           GValue value = { 0, };
1765
1766           g_value_init (&value, G_TYPE_STRING);
1767           if (!gdk_screen_get_setting (settings->screen, pspec->name, &value))
1768             g_value_set_static_string (&value, "");
1769           merge_color_scheme (settings, &value, GTK_SETTINGS_SOURCE_XSETTING);
1770           g_value_unset (&value);
1771         }
1772
1773       g_object_notify (G_OBJECT (settings), pspec->name);
1774    }
1775 }
1776
1777 static void
1778 reset_rc_values_foreach (GQuark    key_id,
1779                          gpointer  data,
1780                          gpointer  user_data)
1781 {
1782   GtkSettingsValuePrivate *qvalue = data;
1783   GSList **to_reset = user_data;
1784
1785   if (qvalue->source == GTK_SETTINGS_SOURCE_RC_FILE)
1786     *to_reset = g_slist_prepend (*to_reset, GUINT_TO_POINTER (key_id));
1787 }
1788
1789 void
1790 _gtk_settings_reset_rc_values (GtkSettings *settings)
1791 {
1792   GSList *to_reset = NULL;
1793   GSList *tmp_list;
1794   GParamSpec **pspecs, **p;
1795   gint i;
1796
1797   /* Remove any queued settings
1798    */
1799   g_datalist_foreach (&settings->queued_settings,
1800                       reset_rc_values_foreach,
1801                       &to_reset);
1802
1803   for (tmp_list = to_reset; tmp_list; tmp_list = tmp_list->next)
1804     {
1805       GQuark key_id = GPOINTER_TO_UINT (tmp_list->data);
1806       g_datalist_id_remove_data (&settings->queued_settings, key_id);
1807     }
1808
1809    g_slist_free (to_reset);
1810
1811   /* Now reset the active settings
1812    */
1813   pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (settings), NULL);
1814   i = 0;
1815
1816   g_object_freeze_notify (G_OBJECT (settings));
1817   for (p = pspecs; *p; p++)
1818     {
1819       if (settings->property_values[i].source == GTK_SETTINGS_SOURCE_RC_FILE)
1820         {
1821           GParamSpec *pspec = *p;
1822
1823           g_param_value_set_default (pspec, &settings->property_values[i].value);
1824           g_object_notify (G_OBJECT (settings), pspec->name);
1825         }
1826       i++;
1827     }
1828   g_object_thaw_notify (G_OBJECT (settings));
1829   g_free (pspecs);
1830 }
1831
1832 static void
1833 settings_update_double_click (GtkSettings *settings)
1834 {
1835   if (gdk_screen_get_number (settings->screen) == 0)
1836     {
1837       GdkDisplay *display = gdk_screen_get_display (settings->screen);
1838       gint double_click_time;
1839       gint double_click_distance;
1840   
1841       g_object_get (settings, 
1842                     "gtk-double-click-time", &double_click_time, 
1843                     "gtk-double-click-distance", &double_click_distance,
1844                     NULL);
1845       
1846       gdk_display_set_double_click_time (display, double_click_time);
1847       gdk_display_set_double_click_distance (display, double_click_distance);
1848     }
1849 }
1850
1851 static void
1852 settings_update_modules (GtkSettings *settings)
1853 {
1854   gchar *modules;
1855   
1856   g_object_get (settings, 
1857                 "gtk-modules", &modules,
1858                 NULL);
1859   
1860   _gtk_modules_settings_changed (settings, modules);
1861   
1862   g_free (modules);
1863 }
1864
1865 #ifdef GDK_WINDOWING_X11
1866 static void
1867 settings_update_cursor_theme (GtkSettings *settings)
1868 {
1869   GdkDisplay *display = gdk_screen_get_display (settings->screen);
1870   gchar *theme = NULL;
1871   gint size = 0;
1872   
1873   g_object_get (settings, 
1874                 "gtk-cursor-theme-name", &theme,
1875                 "gtk-cursor-theme-size", &size,
1876                 NULL);
1877   
1878   gdk_x11_display_set_cursor_theme (display, theme, size);
1879
1880   g_free (theme);
1881 }
1882
1883 static void
1884 settings_update_font_options (GtkSettings *settings)
1885 {
1886   gint hinting;
1887   gchar *hint_style_str;
1888   cairo_hint_style_t hint_style = CAIRO_HINT_STYLE_DEFAULT;
1889   gint antialias;
1890   cairo_antialias_t antialias_mode = CAIRO_ANTIALIAS_DEFAULT;
1891   gchar *rgba_str;
1892   cairo_subpixel_order_t subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
1893   cairo_font_options_t *options;
1894   
1895   g_object_get (settings,
1896                 "gtk-xft-antialias", &antialias,
1897                 "gtk-xft-hinting", &hinting,
1898                 "gtk-xft-hintstyle", &hint_style_str,
1899                 "gtk-xft-rgba", &rgba_str,
1900                 NULL);
1901
1902   options = cairo_font_options_create ();
1903   
1904   if (hinting >= 0 && !hinting)
1905     {
1906       hint_style = CAIRO_HINT_STYLE_NONE;
1907     }
1908   else if (hint_style_str)
1909     {
1910       if (strcmp (hint_style_str, "hintnone") == 0)
1911         hint_style = CAIRO_HINT_STYLE_NONE;
1912       else if (strcmp (hint_style_str, "hintslight") == 0)
1913         hint_style = CAIRO_HINT_STYLE_SLIGHT;
1914       else if (strcmp (hint_style_str, "hintmedium") == 0)
1915         hint_style = CAIRO_HINT_STYLE_MEDIUM;
1916       else if (strcmp (hint_style_str, "hintfull") == 0)
1917         hint_style = CAIRO_HINT_STYLE_FULL;
1918     }
1919
1920   g_free (hint_style_str);
1921
1922   cairo_font_options_set_hint_style (options, hint_style);
1923
1924   if (rgba_str)
1925     {
1926       if (strcmp (rgba_str, "rgb") == 0)
1927         subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB;
1928       else if (strcmp (rgba_str, "bgr") == 0)
1929         subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR;
1930       else if (strcmp (rgba_str, "vrgb") == 0)
1931         subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB;
1932       else if (strcmp (rgba_str, "vbgr") == 0)
1933         subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR;
1934
1935       g_free (rgba_str);
1936     }
1937
1938   cairo_font_options_set_subpixel_order (options, subpixel_order);
1939   
1940   if (antialias >= 0 && !antialias)
1941     antialias_mode = CAIRO_ANTIALIAS_NONE;
1942   else if (subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT)
1943     antialias_mode = CAIRO_ANTIALIAS_SUBPIXEL;
1944   else if (antialias >= 0)
1945     antialias_mode = CAIRO_ANTIALIAS_GRAY;
1946   
1947   cairo_font_options_set_antialias (options, antialias_mode);
1948
1949   gdk_screen_set_font_options (settings->screen, options);
1950   
1951   cairo_font_options_destroy (options);
1952 }
1953
1954 static void
1955 settings_update_resolution (GtkSettings *settings)
1956 {
1957   gint dpi_int;
1958   double dpi;
1959   
1960   g_object_get (settings,
1961                 "gtk-xft-dpi", &dpi_int,
1962                 NULL);
1963
1964   if (dpi_int > 0)
1965     dpi = dpi_int / 1024.;
1966   else
1967     dpi = -1.;
1968
1969   gdk_screen_set_resolution (settings->screen, dpi);
1970 }
1971 #endif
1972
1973 typedef struct {
1974   GHashTable *color_hash;
1975   GHashTable *tables[GTK_SETTINGS_SOURCE_APPLICATION + 1];
1976   gchar *lastentry[GTK_SETTINGS_SOURCE_APPLICATION + 1];
1977 } ColorSchemeData;
1978
1979 static void
1980 color_scheme_data_free (ColorSchemeData *data)
1981 {
1982   gint i;
1983
1984   g_hash_table_unref (data->color_hash);
1985
1986   for (i = 0; i <= GTK_SETTINGS_SOURCE_APPLICATION; i++)
1987     {
1988       if (data->tables[i])
1989         g_hash_table_unref (data->tables[i]);
1990       g_free (data->lastentry[i]);
1991     }
1992
1993   g_slice_free (ColorSchemeData, data);
1994 }
1995
1996 static void
1997 settings_update_color_scheme (GtkSettings *settings)
1998 {
1999   if (!g_object_get_data (G_OBJECT (settings), "gtk-color-scheme"))
2000     {
2001       ColorSchemeData *data;
2002       GValue value = { 0, };
2003
2004       data = g_slice_new0 (ColorSchemeData);
2005       data->color_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
2006                                                 (GDestroyNotify) gdk_color_free);
2007       g_object_set_data_full (G_OBJECT (settings), "gtk-color-scheme",
2008                               data, (GDestroyNotify) color_scheme_data_free); 
2009
2010       g_value_init (&value, G_TYPE_STRING);
2011       if (gdk_screen_get_setting (settings->screen, "gtk-color-scheme", &value))
2012         {
2013           merge_color_scheme (settings, &value, GTK_SETTINGS_SOURCE_XSETTING);
2014           g_value_unset (&value);
2015         }
2016    }
2017 }
2018
2019 static gboolean
2020 add_color_to_hash (gchar      *name, 
2021                    GdkColor   *color, 
2022                    GHashTable *target)
2023 {
2024   GdkColor *old;
2025
2026   old = g_hash_table_lookup (target, name);
2027   if (!old || !gdk_color_equal (old, color))
2028     {
2029       g_hash_table_insert (target, g_strdup (name), gdk_color_copy (color));
2030       
2031       return TRUE;
2032     }
2033
2034   return FALSE;
2035 }
2036
2037 static gboolean
2038 add_colors_to_hash_from_string (GHashTable  *hash, 
2039                                 const gchar *colors)
2040 {
2041   gchar *s, *p, *name;
2042   GdkColor color;
2043   gboolean changed = FALSE;
2044   gchar *copy;
2045
2046   copy = g_strdup (colors);
2047   s = copy;
2048   while (s && *s)
2049     {
2050       name = s;
2051       p = strchr (s, ':');
2052       if (p)
2053         {
2054           *p = '\0';
2055           p++;
2056         }
2057       else
2058         break;
2059
2060       while (*p == ' ')
2061         p++;
2062
2063       s = p;
2064       while (*s) 
2065         {
2066           if (*s == '\n' || *s == ';')
2067             {
2068               *s = '\0';
2069               s++;
2070               break;
2071             }
2072           s++;
2073         }
2074
2075       if (gdk_color_parse (p, &color))
2076         changed |= add_color_to_hash (name, &color, hash);
2077     }
2078
2079   g_free (copy);
2080
2081   return changed;
2082 }
2083
2084 static gboolean
2085 update_color_hash (ColorSchemeData   *data,
2086                    const gchar       *str, 
2087                    GtkSettingsSource  source)
2088 {
2089   gboolean changed = FALSE;
2090   gint i;
2091
2092   if ((str == NULL || *str == '\0') && 
2093       (data->lastentry[source] == NULL || data->lastentry[source][0] == '\0'))
2094     return FALSE;
2095
2096   if (str && data->lastentry[source] && strcmp (str, data->lastentry[source]) == 0)
2097     return FALSE;
2098
2099   /* For the RC_FILE source we merge the values rather than over-writing 
2100    * them, since multiple rc files might define independent sets of colors
2101    */
2102   if ((source != GTK_SETTINGS_SOURCE_RC_FILE) && 
2103       data->tables[source] && g_hash_table_size (data->tables[source]) > 0)
2104     {
2105       g_hash_table_unref (data->tables[source]);
2106       data->tables[source] = NULL;
2107       changed = TRUE; /* We can't rely on the code below since str might be "" */
2108     }
2109
2110   if (data->tables[source] == NULL)
2111     data->tables[source] = g_hash_table_new_full (g_str_hash, g_str_equal, 
2112                                                   g_free,
2113                                                   (GDestroyNotify) gdk_color_free);
2114
2115   g_free (data->lastentry[source]);
2116   data->lastentry[source] = g_strdup (str);
2117   
2118   changed |= add_colors_to_hash_from_string (data->tables[source], str);
2119
2120   if (!changed)
2121     return FALSE;
2122     
2123   /* Rebuild the merged hash table. */
2124   if (data->color_hash)
2125     g_hash_table_unref (data->color_hash);
2126   data->color_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
2127                                             (GDestroyNotify) gdk_color_free);
2128   for (i = 0; i <= GTK_SETTINGS_SOURCE_APPLICATION; i++)
2129     {
2130       if (data->tables[i])
2131         g_hash_table_foreach (data->tables[i], (GHFunc) add_color_to_hash,
2132                               data->color_hash);
2133     }
2134
2135   return TRUE;
2136 }
2137
2138 static void
2139 merge_color_scheme (GtkSettings       *settings, 
2140                     const GValue      *value, 
2141                     GtkSettingsSource  source)
2142 {
2143   ColorSchemeData *data;
2144   const gchar *colors;
2145
2146   g_object_freeze_notify (G_OBJECT (settings));
2147
2148   colors = g_value_get_string (value);
2149
2150   settings_update_color_scheme (settings);
2151
2152   data = (ColorSchemeData *) g_object_get_data (G_OBJECT (settings),
2153                                                 "gtk-color-scheme");
2154   
2155   if (update_color_hash (data, colors, source))
2156     g_object_notify (G_OBJECT (settings), "color-hash");
2157
2158   g_object_thaw_notify (G_OBJECT (settings));
2159 }
2160
2161 static GHashTable *
2162 get_color_hash (GtkSettings *settings)
2163 {
2164   ColorSchemeData *data;
2165
2166   settings_update_color_scheme (settings);
2167   
2168   data = (ColorSchemeData *)g_object_get_data (G_OBJECT (settings), 
2169                                                "gtk-color-scheme");
2170
2171   return data->color_hash;
2172 }
2173
2174 static void 
2175 append_color_scheme (gpointer key,
2176                      gpointer value,
2177                      gpointer data)
2178 {
2179   gchar *name = (gchar *)key;
2180   GdkColor *color = (GdkColor *)value;
2181   GString *string = (GString *)data;
2182
2183   g_string_append_printf (string, "%s: #%04x%04x%04x\n",
2184                           name, color->red, color->green, color->blue);
2185 }
2186
2187 static gchar *
2188 get_color_scheme (GtkSettings *settings)
2189 {
2190   ColorSchemeData *data;
2191   GString *string;
2192   
2193   settings_update_color_scheme (settings);
2194
2195   data = (ColorSchemeData *) g_object_get_data (G_OBJECT (settings),
2196                                                 "gtk-color-scheme");
2197
2198   string = g_string_new ("");
2199
2200   g_hash_table_foreach (data->color_hash, append_color_scheme, string);
2201
2202   return g_string_free (string, FALSE);
2203 }
2204
2205
2206 #define __GTK_SETTINGS_C__
2207 #include "gtkaliasdef.c"