]> Pileus Git - ~andy/gtk/blob - gtk/gtksettings.c
Simplify semantics and check for errors.
[~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 "gtksettings.h"
20 #include "gtkrc.h"
21 #include "gtkintl.h"
22 #include "gtkwidget.h"
23
24 typedef struct _GtkSettingsValuePrivate GtkSettingsValuePrivate;
25
26 typedef enum
27 {
28   GTK_SETTINGS_SOURCE_DEFAULT,
29   GTK_SETTINGS_SOURCE_RC_FILE,
30   GTK_SETTINGS_SOURCE_APPLICATION
31 } GtkSettingsSource;
32
33 struct _GtkSettingsValuePrivate
34 {
35   GtkSettingsValue public;
36   GtkSettingsSource source;
37 };
38
39 struct _GtkSettingsPropertyValue
40 {
41   GValue value;
42   GtkSettingsSource source;
43 };
44
45 #ifdef GDK_WINDOWING_X11
46 #include <X11/Xft/Xft.h>
47 #include <pango/pangoxft.h>
48 #include <gdk/x11/gdkx.h>
49 #endif
50
51 enum {
52   PROP_0,
53   PROP_DOUBLE_CLICK_TIME,
54   PROP_DOUBLE_CLICK_DISTANCE,
55   PROP_CURSOR_BLINK,
56   PROP_CURSOR_BLINK_TIME,
57   PROP_SPLIT_CURSOR,
58   PROP_THEME_NAME,
59   PROP_ICON_THEME_NAME,
60   PROP_KEY_THEME_NAME,
61   PROP_MENU_BAR_ACCEL,
62   PROP_DND_DRAG_THRESHOLD,
63   PROP_FONT_NAME,
64   PROP_ICON_SIZES,
65   PROP_XFT_ANTIALIAS,
66   PROP_XFT_HINTING,
67   PROP_XFT_HINTSTYLE,
68   PROP_XFT_RGBA,
69   PROP_XFT_DPI
70 };
71
72
73 /* --- prototypes --- */
74 static void     gtk_settings_init                (GtkSettings           *settings);
75 static void     gtk_settings_class_init          (GtkSettingsClass      *class);
76 static void     gtk_settings_finalize            (GObject               *object);
77 static void     gtk_settings_get_property        (GObject               *object,
78                                                   guint                  property_id,
79                                                   GValue                *value,
80                                                   GParamSpec            *pspec);
81 static void     gtk_settings_set_property        (GObject               *object,
82                                                   guint                  property_id,
83                                                   const GValue          *value,
84                                                   GParamSpec            *pspec);
85 static void     gtk_settings_notify              (GObject               *object,
86                                                   GParamSpec            *pspec);
87 static guint    settings_install_property_parser (GtkSettingsClass      *class,
88                                                   GParamSpec            *pspec,
89                                                   GtkRcPropertyParser    parser);
90 static void    settings_update_double_click      (GtkSettings           *settings);
91
92
93 /* --- variables --- */
94 static gpointer          parent_class = NULL;
95 static GQuark            quark_property_parser = 0;
96 static GSList           *object_list = NULL;
97 static guint             class_n_properties = 0;
98
99
100 /* --- functions --- */
101 GType
102 gtk_settings_get_type (void)
103 {
104   static GType settings_type = 0;
105   
106   if (!settings_type)
107     {
108       static const GTypeInfo settings_info =
109       {
110         sizeof (GtkSettingsClass),
111         NULL,           /* base_init */
112         NULL,           /* base_finalize */
113         (GClassInitFunc) gtk_settings_class_init,
114         NULL,           /* class_finalize */
115         NULL,           /* class_data */
116         sizeof (GtkSettings),
117         0,              /* n_preallocs */
118         (GInstanceInitFunc) gtk_settings_init,
119       };
120       
121       settings_type = g_type_register_static (G_TYPE_OBJECT, "GtkSettings",
122                                               &settings_info, 0);
123     }
124   
125   return settings_type;
126 }
127
128 #ifdef GDK_WINDOWING_X11
129 static void
130 gtk_default_substitute (FcPattern *pattern,
131                         gpointer   data)
132 {
133   GtkSettings *settings = data;
134   gint antialias;
135   gint hinting;
136   char *rgba;
137   char *hintstyle;
138   gint dpi;
139   FcValue v;
140   
141   g_object_get (G_OBJECT (settings),
142                 "gtk-xft-antialias", &antialias,
143                 "gtk-xft-hinting", &hinting,
144                 "gtk-xft-hintstyle", &hintstyle,
145                 "gtk-xft-rgba", &rgba,
146                 "gtk-xft-dpi", &dpi,
147                 NULL);
148   
149   if (antialias >= 0 &&
150       FcPatternGet (pattern, FC_ANTIALIAS, 0, &v) == FcResultNoMatch)
151     FcPatternAddBool (pattern, FC_ANTIALIAS, antialias != 0);
152   
153   if (hinting >= 0 &&
154       FcPatternGet (pattern, FC_HINTING, 0, &v) == FcResultNoMatch)
155     FcPatternAddBool (pattern, FC_HINTING, hinting != 0);
156  
157 #ifdef FC_HINT_STYLE 
158   if (hintstyle && FcPatternGet (pattern, FC_HINT_STYLE, 0, &v) == FcResultNoMatch)
159     {
160       int val = FC_HINT_FULL;   /* Quiet GCC */
161       gboolean found = TRUE;
162
163       if (strcmp (hintstyle, "hintnone") == 0)
164         val = FC_HINT_NONE;
165       else if (strcmp (hintstyle, "hintslight") == 0)
166         val = FC_HINT_SLIGHT;
167       else if (strcmp (hintstyle, "hintmedium") == 0)
168         val = FC_HINT_MEDIUM;
169       else if (strcmp (hintstyle, "hintfull") == 0)
170         val = FC_HINT_FULL;
171       else
172         found = FALSE;
173
174       if (found)
175         FcPatternAddInteger (pattern, FC_HINT_STYLE, val);
176     }
177 #endif /* FC_HINT_STYLE */
178
179   if (rgba && FcPatternGet (pattern, FC_RGBA, 0, &v) == FcResultNoMatch)
180     {
181       int val = FC_RGBA_NONE;   /* Quiet GCC */
182       gboolean found = TRUE;
183
184       if (strcmp (rgba, "none") == 0)
185         val = FC_RGBA_NONE;
186       else if (strcmp (rgba, "rgb") == 0)
187         val = FC_RGBA_RGB;
188       else if (strcmp (rgba, "bgr") == 0)
189         val = FC_RGBA_BGR;
190       else if (strcmp (rgba, "vrgb") == 0)
191         val = FC_RGBA_VRGB;
192       else if (strcmp (rgba, "vbgr") == 0)
193         val = FC_RGBA_VBGR;
194       else
195         found = FALSE;
196
197       if (found)
198         FcPatternAddInteger (pattern, FC_RGBA, val);
199     }
200
201   if (dpi >= 0 && FcPatternGet (pattern, FC_DPI, 0, &v) == FcResultNoMatch)
202     FcPatternAddDouble (pattern, FC_DPI, dpi / 1024.);
203
204   g_free (hintstyle);
205   g_free (rgba);
206 }
207 #endif /* GDK_WINDOWING_X11 */
208
209 static void
210 gtk_settings_init (GtkSettings *settings)
211 {
212   GParamSpec **pspecs, **p;
213   guint i = 0;
214   
215   g_datalist_init (&settings->queued_settings);
216   object_list = g_slist_prepend (object_list, settings);
217
218   /* build up property array for all yet existing properties and queue
219    * notification for them (at least notification for internal properties
220    * will instantly be caught)
221    */
222   pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (settings), NULL);
223   for (p = pspecs; *p; p++)
224     if ((*p)->owner_type == G_OBJECT_TYPE (settings))
225       i++;
226   settings->property_values = g_new0 (GtkSettingsPropertyValue, i);
227   i = 0;
228   g_object_freeze_notify (G_OBJECT (settings));
229   for (p = pspecs; *p; p++)
230     {
231       GParamSpec *pspec = *p;
232
233       if (pspec->owner_type != G_OBJECT_TYPE (settings))
234         continue;
235       g_value_init (&settings->property_values[i].value, G_PARAM_SPEC_VALUE_TYPE (pspec));
236       g_param_value_set_default (pspec, &settings->property_values[i].value);
237       g_object_notify (G_OBJECT (settings), pspec->name);
238       settings->property_values[i].source = GTK_SETTINGS_SOURCE_DEFAULT;
239       i++;
240     }
241   g_object_thaw_notify (G_OBJECT (settings));
242   g_free (pspecs);
243 }
244
245 static void
246 gtk_settings_class_init (GtkSettingsClass *class)
247 {
248   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
249   guint result;
250   
251   parent_class = g_type_class_peek_parent (class);
252
253   gobject_class->finalize = gtk_settings_finalize;
254   gobject_class->get_property = gtk_settings_get_property;
255   gobject_class->set_property = gtk_settings_set_property;
256   gobject_class->notify = gtk_settings_notify;
257
258   quark_property_parser = g_quark_from_static_string ("gtk-rc-property-parser");
259
260   result = settings_install_property_parser (class,
261                                              g_param_spec_int ("gtk-double-click-time",
262                                                                P_("Double Click Time"),
263                                                                P_("Maximum time allowed between two clicks for them to be considered a double click (in milliseconds)"),
264                                                                0, G_MAXINT, 250,
265                                                                G_PARAM_READWRITE),
266                                              NULL);
267   g_assert (result == PROP_DOUBLE_CLICK_TIME);
268   result = settings_install_property_parser (class,
269                                              g_param_spec_int ("gtk-double-click-distance",
270                                                                P_("Double Click Distance"),
271                                                                P_("Maximum distance allowed between two clicks for them to be considered a double click (in pixels)"),
272                                                                0, G_MAXINT, 5,
273                                                                G_PARAM_READWRITE),
274                                              NULL);
275   g_assert (result == PROP_DOUBLE_CLICK_DISTANCE);
276   result = settings_install_property_parser (class,
277                                              g_param_spec_boolean ("gtk-cursor-blink",
278                                                                    P_("Cursor Blink"),
279                                                                    P_("Whether the cursor should blink"),
280                                                                    TRUE,
281                                                                    G_PARAM_READWRITE),
282                                              NULL);
283   g_assert (result == PROP_CURSOR_BLINK);
284   result = settings_install_property_parser (class,
285                                              g_param_spec_int ("gtk-cursor-blink-time",
286                                                                P_("Cursor Blink Time"),
287                                                                P_("Length of the cursor blink cycle, in milleseconds"),
288                                                                100, G_MAXINT, 1200,
289                                                                G_PARAM_READWRITE),
290                                              NULL);
291   g_assert (result == PROP_CURSOR_BLINK_TIME);
292   result = settings_install_property_parser (class,
293                                              g_param_spec_boolean ("gtk-split-cursor",
294                                                                    P_("Split Cursor"),
295                                                                    P_("Whether two cursors should be displayed for mixed left-to-right and right-to-left text"),
296                                                                    TRUE,
297                                                                    G_PARAM_READWRITE),
298                                              NULL);
299   g_assert (result == PROP_SPLIT_CURSOR);
300   result = settings_install_property_parser (class,
301                                              g_param_spec_string ("gtk-theme-name",
302                                                                    P_("Theme Name"),
303                                                                    P_("Name of theme RC file to load"),
304                                                                   "Default",
305                                                                   G_PARAM_READWRITE),
306                                              NULL);
307   g_assert (result == PROP_THEME_NAME);
308   result = settings_install_property_parser (class,
309                                              g_param_spec_string ("gtk-icon-theme-name",
310                                                                   P_("Icon Theme Name"),
311                                                                   P_("Name of icon theme to use"),
312                                                                   "hicolor",
313                                                                   G_PARAM_READWRITE),
314                                              NULL);
315   g_assert (result == PROP_ICON_THEME_NAME);
316   
317   result = settings_install_property_parser (class,
318                                              g_param_spec_string ("gtk-key-theme-name",
319                                                                   P_("Key Theme Name"),
320                                                                   P_("Name of key theme RC file to load"),
321                                                                   NULL,
322                                                                   G_PARAM_READWRITE),
323                                              NULL);
324   g_assert (result == PROP_KEY_THEME_NAME);    
325
326   result = settings_install_property_parser (class,
327                                              g_param_spec_string ("gtk-menu-bar-accel",
328                                                                   P_("Menu bar accelerator"),
329                                                                   P_("Keybinding to activate the menu bar"),
330                                                                   "F10",
331                                                                   G_PARAM_READWRITE),
332                                              NULL);
333   g_assert (result == PROP_MENU_BAR_ACCEL);
334
335   result = settings_install_property_parser (class,
336                                              g_param_spec_int ("gtk-dnd-drag-threshold",
337                                                                P_("Drag threshold"),
338                                                                P_("Number of pixels the cursor can move before dragging"),
339                                                                1, G_MAXINT, 8,
340                                                                G_PARAM_READWRITE),
341                                              NULL);
342   g_assert (result == PROP_DND_DRAG_THRESHOLD);
343
344   result = settings_install_property_parser (class,
345                                              g_param_spec_string ("gtk-font-name",
346                                                                    P_("Font Name"),
347                                                                    P_("Name of default font to use"),
348                                                                   "Sans 10",
349                                                                   G_PARAM_READWRITE),
350                                              NULL);
351   g_assert (result == PROP_FONT_NAME);
352
353   result = settings_install_property_parser (class,
354                                              g_param_spec_string ("gtk-icon-sizes",
355                                                                    P_("Icon Sizes"),
356                                                                    P_("List of icon sizes (gtk-menu=16,16;gtk-button=20,20..."),
357                                                                   NULL,
358                                                                   G_PARAM_READWRITE),
359                                              NULL);
360   g_assert (result == PROP_ICON_SIZES);
361
362 #ifdef GDK_WINDOWING_X11
363   result = settings_install_property_parser (class,
364                                              g_param_spec_int ("gtk-xft-antialias",
365                                                                P_("Xft Antialias"),
366                                                                P_("Whether to antialias Xft fonts; 0=no, 1=yes, -1=default"),
367                                                                -1, 1, -1,
368                                                                G_PARAM_READWRITE),
369                                              NULL);
370  
371   g_assert (result == PROP_XFT_ANTIALIAS);
372   
373   result = settings_install_property_parser (class,
374                                              g_param_spec_int ("gtk-xft-hinting",
375                                                                P_("Xft Hinting"),
376                                                                P_("Whether to hint Xft fonts; 0=no, 1=yes, -1=default"),
377                                                                -1, 1, -1,
378                                                                G_PARAM_READWRITE),
379                                              NULL);
380   
381   g_assert (result == PROP_XFT_HINTING);
382   
383   result = settings_install_property_parser (class,
384                                              g_param_spec_string ("gtk-xft-hintstyle",
385                                                                   P_("Xft Hint Style"),
386                                                                   P_("What degree of hinting to use; none, slight, medium, or full"),
387                                                                   NULL,
388                                                                   G_PARAM_READWRITE),
389                                               NULL);
390   
391   g_assert (result == PROP_XFT_HINTSTYLE);
392   
393   result = settings_install_property_parser (class,
394                                              g_param_spec_string ("gtk-xft-rgba",
395                                                                   P_("Xft RGBA"),
396                                                                   P_("Type of subpixel antialiasing; none, rgb, bgr, vrgb, vbgr"),
397                                                                   NULL,
398                                                                   G_PARAM_READWRITE),
399                                              NULL);
400   
401   g_assert (result == PROP_XFT_RGBA);
402   
403   result = settings_install_property_parser (class,
404                                              g_param_spec_int ("gtk-xft-dpi",
405                                                                P_("Xft DPI"),
406                                                                P_("Resolution for Xft, in 1024 * dots/inch. -1 to use default value"),
407                                                                -1, 1024*1024, -1,
408                                                                G_PARAM_READWRITE),
409                                              NULL);
410   
411   g_assert (result == PROP_XFT_DPI);
412 #endif  /* GDK_WINDOWING_X11 */
413 }
414
415 static void
416 gtk_settings_finalize (GObject *object)
417 {
418   GtkSettings *settings = GTK_SETTINGS (object);
419   guint i;
420
421   object_list = g_slist_remove (object_list, settings);
422
423   for (i = 0; i < class_n_properties; i++)
424     g_value_unset (&settings->property_values[i].value);
425   g_free (settings->property_values);
426
427   g_datalist_clear (&settings->queued_settings);
428
429   G_OBJECT_CLASS (parent_class)->finalize (object);
430 }
431
432 /**
433  * gtk_settings_get_for_screen:
434  * @screen : a #GdkScreen.
435  * 
436  * Gets the #GtkSettings object for @screen, creating it if necessary.
437  *
438  * Return value: a #GtkSettings object.
439  *
440  * Since: 2.2
441  */
442 GtkSettings*
443 gtk_settings_get_for_screen (GdkScreen *screen)
444 {
445   GtkSettings *settings;
446   
447   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
448   
449   settings = g_object_get_data (G_OBJECT (screen), "gtk-settings");
450   if (!settings)
451     {
452       settings = g_object_new (GTK_TYPE_SETTINGS, NULL);
453       settings->screen = screen;
454       g_object_set_data (G_OBJECT (screen), "gtk-settings", settings);
455
456 #ifdef GDK_WINDOWING_X11  
457       /* Set the default substitution function for the Pango fontmap.
458        */
459       pango_xft_set_default_substitute (GDK_SCREEN_XDISPLAY (screen),
460                                         GDK_SCREEN_XNUMBER (screen),
461                                         gtk_default_substitute,
462                                         settings, NULL);
463 #endif /* GDK_WINDOWING_X11 */
464       
465       gtk_rc_reparse_all_for_settings (settings, TRUE);
466       settings_update_double_click (settings);
467     }
468   
469   return settings;
470 }
471
472 /**
473  * gtk_settings_get_default:
474  * 
475  * Gets the #GtkSettings object for the default GDK screen, creating
476  * it if necessary. See gtk_settings_get_for_screen().
477  * 
478  * Return value: a #GtkSettings object. If there is no default
479  *  screen, then returns %NULL.
480  **/
481 GtkSettings*
482 gtk_settings_get_default (void)
483 {
484   GdkScreen *screen = gdk_screen_get_default ();
485
486   if (screen)
487     return gtk_settings_get_for_screen (screen);
488   else
489     return NULL;
490 }
491
492 static void
493 gtk_settings_set_property (GObject      *object,
494                            guint         property_id,
495                            const GValue *value,
496                            GParamSpec   *pspec)
497 {
498   GtkSettings *settings = GTK_SETTINGS (object);
499
500   g_value_copy (value, &settings->property_values[property_id - 1].value);
501   settings->property_values[property_id - 1].source = GTK_SETTINGS_SOURCE_APPLICATION;
502 }
503
504 static void
505 gtk_settings_get_property (GObject     *object,
506                            guint        property_id,
507                            GValue      *value,
508                            GParamSpec  *pspec)
509 {
510   GtkSettings *settings = GTK_SETTINGS (object);
511   GType value_type = G_VALUE_TYPE (value);
512   GType fundamental_type = G_TYPE_FUNDAMENTAL (value_type);
513
514   /* For enums and strings, we need to get the value as a string,
515    * not as an int, since we support using names/nicks as the setting
516    * value.
517    */
518   if ((g_value_type_transformable (G_TYPE_INT, value_type) &&
519        !(fundamental_type == G_TYPE_ENUM || fundamental_type == G_TYPE_FLAGS)) ||
520       g_value_type_transformable (G_TYPE_STRING, G_VALUE_TYPE (value)) ||
521       g_value_type_transformable (GDK_TYPE_COLOR, G_VALUE_TYPE (value)))
522     {
523       if (settings->property_values[property_id - 1].source == GTK_SETTINGS_SOURCE_APPLICATION ||
524           !gdk_screen_get_setting (settings->screen, pspec->name, value))
525         g_value_copy (&settings->property_values[property_id - 1].value, value);
526       else
527         g_param_value_validate (pspec, value);
528     }
529   else
530     {
531       GValue val = { 0, };
532
533       /* Try to get xsetting as a string and parse it. */
534       
535       g_value_init (&val, G_TYPE_STRING);
536
537       if (settings->property_values[property_id - 1].source == GTK_SETTINGS_SOURCE_APPLICATION ||
538           !gdk_screen_get_setting (settings->screen, pspec->name, &val))
539         {
540           g_value_copy (&settings->property_values[property_id - 1].value, value);
541         }
542       else
543         {
544           GValue tmp_value = { 0, };
545           GValue gstring_value = { 0, };
546           GtkRcPropertyParser parser = (GtkRcPropertyParser) g_param_spec_get_qdata (pspec, quark_property_parser);
547           
548           g_value_init (&gstring_value, G_TYPE_GSTRING);
549
550           g_value_set_boxed (&gstring_value,
551                              g_string_new (g_value_get_string (&val)));
552
553           g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
554
555           if (parser && _gtk_settings_parse_convert (parser, &gstring_value,
556                                                      pspec, &tmp_value))
557             {
558               g_value_copy (&tmp_value, value);
559               g_param_value_validate (pspec, value);
560             }
561           else
562             {
563               g_value_copy (&settings->property_values[property_id - 1].value, value);
564             }
565
566           g_value_unset (&gstring_value);
567           g_value_unset (&tmp_value);
568         }
569
570       g_value_unset (&val);
571     }
572 }
573
574 static void
575 gtk_settings_notify (GObject    *object,
576                      GParamSpec *pspec)
577 {
578   GtkSettings *settings = GTK_SETTINGS (object);
579   guint property_id = pspec->param_id;
580
581   if (settings->screen == NULL) /* initialization */
582     return;
583
584   switch (property_id)
585     {
586     case PROP_DOUBLE_CLICK_TIME:
587     case PROP_DOUBLE_CLICK_DISTANCE:
588       settings_update_double_click (settings);
589       break;
590 #ifdef GDK_WINDOWING_X11      
591     case PROP_XFT_ANTIALIAS:
592     case PROP_XFT_HINTING:
593     case PROP_XFT_HINTSTYLE:
594     case PROP_XFT_RGBA:
595     case PROP_XFT_DPI:
596       pango_xft_substitute_changed (GDK_SCREEN_XDISPLAY (settings->screen),
597                                     GDK_SCREEN_XNUMBER (settings->screen));
598       /* This is a hack because with gtk_rc_reset_styles() doesn't get
599        * widgets with gtk_widget_style_set(), and also causes more
600        * recomputation than necessary.
601        */
602       gtk_rc_reset_styles (GTK_SETTINGS (object));
603       break;
604 #endif /* GDK_WINDOWING_X11 */
605     }
606 }
607
608 gboolean
609 _gtk_settings_parse_convert (GtkRcPropertyParser parser,
610                              const GValue       *src_value,
611                              GParamSpec         *pspec,
612                              GValue             *dest_value)
613 {
614   gboolean success = FALSE;
615
616   g_return_val_if_fail (G_VALUE_HOLDS (dest_value, G_PARAM_SPEC_VALUE_TYPE (pspec)), FALSE);
617
618   if (parser)
619     {
620       GString *gstring;
621       gboolean free_gstring = TRUE;
622       
623       if (G_VALUE_HOLDS (src_value, G_TYPE_GSTRING))
624         {
625           gstring = g_value_get_boxed (src_value);
626           free_gstring = FALSE;
627         }
628       else if (G_VALUE_HOLDS_LONG (src_value))
629         {
630           gstring = g_string_new (NULL);
631           g_string_append_printf (gstring, "%ld", g_value_get_long (src_value));
632         }
633       else if (G_VALUE_HOLDS_DOUBLE (src_value))
634         {
635           gstring = g_string_new (NULL);
636           g_string_append_printf (gstring, "%f", g_value_get_double (src_value));
637         }
638       else if (G_VALUE_HOLDS_STRING (src_value))
639         {
640           gchar *tstr = g_strescape (g_value_get_string (src_value), NULL);
641           
642           gstring = g_string_new ("\"");
643           g_string_append (gstring, tstr);
644           g_string_append_c (gstring, '\"');
645           g_free (tstr);
646         }
647       else
648         {
649           g_return_val_if_fail (G_VALUE_HOLDS (src_value, G_TYPE_GSTRING), FALSE);
650           gstring = NULL; /* silence compiler */
651         }
652
653       success = (parser (pspec, gstring, dest_value) &&
654                  !g_param_value_validate (pspec, dest_value));
655
656       if (free_gstring)
657         g_string_free (gstring, TRUE);
658     }
659   else if (G_VALUE_HOLDS (src_value, G_TYPE_GSTRING))
660     {
661       if (G_VALUE_HOLDS (dest_value, G_TYPE_STRING))
662         {
663           GString *gstring = g_value_get_boxed (src_value);
664
665           g_value_set_string (dest_value, gstring ? gstring->str : NULL);
666           success = !g_param_value_validate (pspec, dest_value);
667         }
668     }
669   else if (g_value_type_transformable (G_VALUE_TYPE (src_value), G_VALUE_TYPE (dest_value)))
670     success = g_param_value_convert (pspec, src_value, dest_value, TRUE);
671
672   return success;
673 }
674
675 static void
676 apply_queued_setting (GtkSettings             *data,
677                       GParamSpec              *pspec,
678                       GtkSettingsValuePrivate *qvalue)
679 {
680   GValue tmp_value = { 0, };
681   GtkRcPropertyParser parser = (GtkRcPropertyParser) g_param_spec_get_qdata (pspec, quark_property_parser);
682
683   g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
684   if (_gtk_settings_parse_convert (parser, &qvalue->public.value,
685                                    pspec, &tmp_value))
686     {
687       g_object_set_property (G_OBJECT (data), pspec->name, &tmp_value);
688       data->property_values[pspec->param_id - 1].source = qvalue->source;
689     }
690   else
691     {
692       gchar *debug = g_strdup_value_contents (&qvalue->public.value);
693       
694       g_message ("%s: failed to retrieve property `%s' of type `%s' from rc file value \"%s\" of type `%s'",
695                  qvalue->public.origin,
696                  pspec->name,
697                  g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
698                  debug,
699                  G_VALUE_TYPE_NAME (&tmp_value));
700       g_free (debug);
701     }
702   g_value_unset (&tmp_value);
703 }
704
705 static guint
706 settings_install_property_parser (GtkSettingsClass   *class,
707                                   GParamSpec         *pspec,
708                                   GtkRcPropertyParser parser)
709 {
710   GSList *node, *next;
711
712   switch (G_TYPE_FUNDAMENTAL (G_PARAM_SPEC_VALUE_TYPE (pspec)))
713     {
714     case G_TYPE_BOOLEAN:
715     case G_TYPE_UCHAR:
716     case G_TYPE_CHAR:
717     case G_TYPE_UINT:
718     case G_TYPE_INT:
719     case G_TYPE_ULONG:
720     case G_TYPE_LONG:
721     case G_TYPE_FLOAT:
722     case G_TYPE_DOUBLE:
723     case G_TYPE_STRING:
724       break;
725     default:
726       if (!parser)
727         {
728           g_warning (G_STRLOC ": parser needs to be specified for property \"%s\" of type `%s'",
729                      pspec->name, g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
730           return 0;
731         }
732     }
733   if (g_object_class_find_property (G_OBJECT_CLASS (class), pspec->name))
734     {
735       g_warning (G_STRLOC ": an rc-data property \"%s\" already exists",
736                  pspec->name);
737       return 0;
738     }
739   
740   for (node = object_list; node; node = node->next)
741     g_object_freeze_notify (node->data);
742
743   g_object_class_install_property (G_OBJECT_CLASS (class), ++class_n_properties, pspec);
744   g_param_spec_set_qdata (pspec, quark_property_parser, (gpointer) parser);
745
746   for (node = object_list; node; node = node->next)
747     {
748       GtkSettings *settings = node->data;
749       GtkSettingsValuePrivate *qvalue;
750       
751       settings->property_values = g_renew (GtkSettingsPropertyValue, settings->property_values, class_n_properties);
752       settings->property_values[class_n_properties - 1].value.g_type = 0;
753       g_value_init (&settings->property_values[class_n_properties - 1].value, G_PARAM_SPEC_VALUE_TYPE (pspec));
754       g_param_value_set_default (pspec, &settings->property_values[class_n_properties - 1].value);
755       settings->property_values[class_n_properties - 1].source = GTK_SETTINGS_SOURCE_DEFAULT;
756       g_object_notify (G_OBJECT (settings), pspec->name);
757       
758       qvalue = g_datalist_get_data (&settings->queued_settings, pspec->name);
759       if (qvalue)
760         apply_queued_setting (settings, pspec, qvalue);
761     }
762
763   for (node = object_list; node; node = next)
764     {
765       next = node->next;
766       g_object_thaw_notify (node->data);
767     }
768
769   return class_n_properties;
770 }
771
772 GtkRcPropertyParser
773 _gtk_rc_property_parser_from_type (GType type)
774 {
775   if (type == GDK_TYPE_COLOR)
776     return gtk_rc_property_parse_color;
777   else if (type == GTK_TYPE_REQUISITION)
778     return gtk_rc_property_parse_requisition;
779   else if (type == GTK_TYPE_BORDER)
780     return gtk_rc_property_parse_border;
781   else if (G_TYPE_FUNDAMENTAL (type) == G_TYPE_ENUM && G_TYPE_IS_DERIVED (type))
782     return gtk_rc_property_parse_enum;
783   else if (G_TYPE_FUNDAMENTAL (type) == G_TYPE_FLAGS && G_TYPE_IS_DERIVED (type))
784     return gtk_rc_property_parse_flags;
785   else
786     return NULL;
787 }
788
789 void
790 gtk_settings_install_property (GParamSpec *pspec)
791 {
792   GtkRcPropertyParser parser;
793
794   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
795
796   parser = _gtk_rc_property_parser_from_type (G_PARAM_SPEC_VALUE_TYPE (pspec));
797
798   settings_install_property_parser (gtk_type_class (GTK_TYPE_SETTINGS), pspec, parser);
799 }
800
801 void
802 gtk_settings_install_property_parser (GParamSpec          *pspec,
803                                       GtkRcPropertyParser  parser)
804 {
805   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
806   g_return_if_fail (parser != NULL);
807   
808   settings_install_property_parser (gtk_type_class (GTK_TYPE_SETTINGS), pspec, parser);
809 }
810
811 static void
812 free_value (gpointer data)
813 {
814   GtkSettingsValuePrivate *qvalue = data;
815   
816   g_value_unset (&qvalue->public.value);
817   g_free (qvalue->public.origin);
818   g_free (qvalue);
819 }
820
821 static void
822 gtk_settings_set_property_value_internal (GtkSettings            *settings,
823                                           const gchar            *prop_name,
824                                           const GtkSettingsValue *new_value,
825                                           GtkSettingsSource       source)
826 {
827   GtkSettingsValuePrivate *qvalue;
828   GParamSpec *pspec;
829   gchar *name;
830   GQuark name_quark;
831
832   if (!G_VALUE_HOLDS_LONG (&new_value->value) &&
833       !G_VALUE_HOLDS_DOUBLE (&new_value->value) &&
834       !G_VALUE_HOLDS_STRING (&new_value->value) &&
835       !G_VALUE_HOLDS (&new_value->value, G_TYPE_GSTRING))
836     {
837       g_warning (G_STRLOC ": value type invalid");
838       return;
839     }
840   
841   name = g_strdup (prop_name);
842   g_strcanon (name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-');
843   name_quark = g_quark_from_string (name);
844   g_free (name);
845
846   qvalue = g_datalist_id_get_data (&settings->queued_settings, name_quark);
847   if (!qvalue)
848     {
849       qvalue = g_new0 (GtkSettingsValuePrivate, 1);
850       g_datalist_id_set_data_full (&settings->queued_settings, name_quark, qvalue, free_value);
851     }
852   else
853     {
854       g_free (qvalue->public.origin);
855       g_value_unset (&qvalue->public.value);
856     }
857   qvalue->public.origin = g_strdup (new_value->origin);
858   g_value_init (&qvalue->public.value, G_VALUE_TYPE (&new_value->value));
859   g_value_copy (&new_value->value, &qvalue->public.value);
860   qvalue->source = source;
861   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (settings), g_quark_to_string (name_quark));
862   if (pspec)
863     apply_queued_setting (settings, pspec, qvalue);
864 }
865
866 void
867 gtk_settings_set_property_value (GtkSettings            *settings,
868                                  const gchar            *prop_name,
869                                  const GtkSettingsValue *new_value)
870 {
871   g_return_if_fail (GTK_SETTINGS (settings));
872   g_return_if_fail (prop_name != NULL);
873   g_return_if_fail (new_value != NULL);
874   g_return_if_fail (new_value->origin != NULL);
875
876   gtk_settings_set_property_value_internal (settings, prop_name, new_value,
877                                             GTK_SETTINGS_SOURCE_APPLICATION);
878 }
879
880 void
881 _gtk_settings_set_property_value_from_rc (GtkSettings            *settings,
882                                           const gchar            *prop_name,
883                                           const GtkSettingsValue *new_value)
884 {
885   g_return_if_fail (GTK_SETTINGS (settings));
886   g_return_if_fail (prop_name != NULL);
887   g_return_if_fail (new_value != NULL);
888   g_return_if_fail (new_value->origin != NULL);
889
890   gtk_settings_set_property_value_internal (settings, prop_name, new_value,
891                                             GTK_SETTINGS_SOURCE_RC_FILE);
892 }
893
894 void
895 gtk_settings_set_string_property (GtkSettings *settings,
896                                   const gchar *name,
897                                   const gchar *v_string,
898                                   const gchar *origin)
899 {
900   GtkSettingsValue svalue = { NULL, { 0, }, };
901
902   g_return_if_fail (GTK_SETTINGS (settings));
903   g_return_if_fail (name != NULL);
904   g_return_if_fail (v_string != NULL);
905   g_return_if_fail (origin != NULL);
906
907   svalue.origin = (gchar*) origin;
908   g_value_init (&svalue.value, G_TYPE_STRING);
909   g_value_set_static_string (&svalue.value, v_string);
910   gtk_settings_set_property_value (settings, name, &svalue);
911   g_value_unset (&svalue.value);
912 }
913
914 void
915 gtk_settings_set_long_property (GtkSettings *settings,
916                                 const gchar *name,
917                                 glong        v_long,
918                                 const gchar *origin)
919 {
920   GtkSettingsValue svalue = { NULL, { 0, }, };
921   
922   g_return_if_fail (GTK_SETTINGS (settings));
923   g_return_if_fail (name != NULL);
924   g_return_if_fail (origin != NULL);
925
926   svalue.origin = (gchar*) origin;
927   g_value_init (&svalue.value, G_TYPE_LONG);
928   g_value_set_long (&svalue.value, v_long);
929   gtk_settings_set_property_value (settings, name, &svalue);
930   g_value_unset (&svalue.value);
931 }
932
933 void
934 gtk_settings_set_double_property (GtkSettings *settings,
935                                   const gchar *name,
936                                   gdouble      v_double,
937                                   const gchar *origin)
938 {
939   GtkSettingsValue svalue = { NULL, { 0, }, };
940
941   g_return_if_fail (GTK_SETTINGS (settings));
942   g_return_if_fail (name != NULL);
943   g_return_if_fail (origin != NULL);
944
945   svalue.origin = (gchar*) origin;
946   g_value_init (&svalue.value, G_TYPE_DOUBLE);
947   g_value_set_double (&svalue.value, v_double);
948   gtk_settings_set_property_value (settings, name, &svalue);
949   g_value_unset (&svalue.value);
950 }
951
952 /**
953  * gtk_rc_property_parse_color:
954  * @pspec: a #GParamSpec
955  * @gstring: the #GString to be parsed
956  * @property_value: a #GValue which must hold #GdkColor values.
957  * 
958  * A #GtkRcPropertyParser for use with gtk_settings_install_property_parser()
959  * or gtk_widget_class_install_style_property_parser() which parses a
960  * color given either by its name or in the form 
961  * <literal>{ red, green, blue }</literal> where %red, %green and
962  * %blue are integers between 0 and 65535 or floating-point numbers
963  * between 0 and 1.
964  * 
965  * Return value: %TRUE if @gstring could be parsed and @property_value
966  * has been set to the resulting #GdkColor.
967  **/
968 gboolean
969 gtk_rc_property_parse_color (const GParamSpec *pspec,
970                              const GString    *gstring,
971                              GValue           *property_value)
972 {
973   GdkColor color = { 0, 0, 0, 0, };
974   GScanner *scanner;
975   gboolean success;
976
977   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
978   g_return_val_if_fail (G_VALUE_HOLDS (property_value, GDK_TYPE_COLOR), FALSE);
979
980   scanner = gtk_rc_scanner_new ();
981   g_scanner_input_text (scanner, gstring->str, gstring->len);
982   if (gtk_rc_parse_color (scanner, &color) == G_TOKEN_NONE &&
983       g_scanner_get_next_token (scanner) == G_TOKEN_EOF)
984     {
985       g_value_set_boxed (property_value, &color);
986       success = TRUE;
987     }
988   else
989     success = FALSE;
990   g_scanner_destroy (scanner);
991
992   return success;
993 }
994
995 /**
996  * gtk_rc_property_parse_enum:
997  * @pspec: a #GParamSpec
998  * @gstring: the #GString to be parsed
999  * @property_value: a #GValue which must hold enum values.
1000  * 
1001  * A #GtkRcPropertyParser for use with gtk_settings_install_property_parser()
1002  * or gtk_widget_class_install_style_property_parser() which parses a single
1003  * enumeration value.
1004  *
1005  * The enumeration value can be specified by its name, its nickname or
1006  * its numeric value. For consistency with flags parsing, the value
1007  * may be surrounded by parentheses.
1008  * 
1009  * Return value: %TRUE if @gstring could be parsed and @property_value
1010  * has been set to the resulting #GEnumValue.
1011  **/
1012 gboolean
1013 gtk_rc_property_parse_enum (const GParamSpec *pspec,
1014                             const GString    *gstring,
1015                             GValue           *property_value)
1016 {
1017   gboolean need_closing_brace = FALSE, success = FALSE;
1018   GScanner *scanner;
1019   GEnumValue *enum_value = NULL;
1020
1021   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
1022   g_return_val_if_fail (G_VALUE_HOLDS_ENUM (property_value), FALSE);
1023
1024   scanner = gtk_rc_scanner_new ();
1025   g_scanner_input_text (scanner, gstring->str, gstring->len);
1026
1027   /* we just want to parse _one_ value, but for consistency with flags parsing
1028    * we support optional parenthesis
1029    */
1030   g_scanner_get_next_token (scanner);
1031   if (scanner->token == '(')
1032     {
1033       need_closing_brace = TRUE;
1034       g_scanner_get_next_token (scanner);
1035     }
1036   if (scanner->token == G_TOKEN_IDENTIFIER)
1037     {
1038       GEnumClass *class = G_PARAM_SPEC_ENUM (pspec)->enum_class;
1039       
1040       enum_value = g_enum_get_value_by_name (class, scanner->value.v_identifier);
1041       if (!enum_value)
1042         enum_value = g_enum_get_value_by_nick (class, scanner->value.v_identifier);
1043       if (enum_value)
1044         {
1045           g_value_set_enum (property_value, enum_value->value);
1046           success = TRUE;
1047         }
1048     }
1049   else if (scanner->token == G_TOKEN_INT)
1050     {
1051       g_value_set_enum (property_value, scanner->value.v_int);
1052       success = TRUE;
1053     }
1054   if (need_closing_brace && g_scanner_get_next_token (scanner) != ')')
1055     success = FALSE;
1056   if (g_scanner_get_next_token (scanner) != G_TOKEN_EOF)
1057     success = FALSE;
1058
1059   g_scanner_destroy (scanner);
1060
1061   return success;
1062 }
1063
1064 static guint
1065 parse_flags_value (GScanner    *scanner,
1066                    GFlagsClass *class,
1067                    guint       *number)
1068 {
1069   g_scanner_get_next_token (scanner);
1070   if (scanner->token == G_TOKEN_IDENTIFIER)
1071     {
1072       GFlagsValue *flags_value;
1073
1074       flags_value = g_flags_get_value_by_name (class, scanner->value.v_identifier);
1075       if (!flags_value)
1076         flags_value = g_flags_get_value_by_nick (class, scanner->value.v_identifier);
1077       if (flags_value)
1078         {
1079           *number |= flags_value->value;
1080           return G_TOKEN_NONE;
1081         }
1082     }
1083   else if (scanner->token == G_TOKEN_INT)
1084     {
1085       *number |= scanner->value.v_int;
1086       return G_TOKEN_NONE;
1087     }
1088   return G_TOKEN_IDENTIFIER;
1089 }
1090
1091 /**
1092  * gtk_rc_property_parse_flags:
1093  * @pspec: a #GParamSpec
1094  * @gstring: the #GString to be parsed
1095  * @property_value: a #GValue which must hold flags values.
1096  * 
1097  * A #GtkRcPropertyParser for use with gtk_settings_install_property_parser()
1098  * or gtk_widget_class_install_style_property_parser() which parses flags. 
1099  * 
1100  * Flags can be specified by their name, their nickname or
1101  * numerically. Multiple flags can be specified in the form 
1102  * <literal>"( flag1 | flag2 | ... )"</literal>.
1103  * 
1104  * Return value: %TRUE if @gstring could be parsed and @property_value
1105  * has been set to the resulting flags value.
1106  **/
1107 gboolean
1108 gtk_rc_property_parse_flags (const GParamSpec *pspec,
1109                              const GString    *gstring,
1110                              GValue           *property_value)
1111 {
1112   GFlagsClass *class;
1113    gboolean success = FALSE;
1114   GScanner *scanner;
1115
1116   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
1117   g_return_val_if_fail (G_VALUE_HOLDS_FLAGS (property_value), FALSE);
1118
1119   class = G_PARAM_SPEC_FLAGS (pspec)->flags_class;
1120   scanner = gtk_rc_scanner_new ();
1121   g_scanner_input_text (scanner, gstring->str, gstring->len);
1122
1123   /* parse either a single flags value or a "\( ... [ \| ... ] \)" compound */
1124   if (g_scanner_peek_next_token (scanner) == G_TOKEN_IDENTIFIER ||
1125       scanner->next_token == G_TOKEN_INT)
1126     {
1127       guint token, flags_value = 0;
1128       
1129       token = parse_flags_value (scanner, class, &flags_value);
1130
1131       if (token == G_TOKEN_NONE && g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
1132         {
1133           success = TRUE;
1134           g_value_set_flags (property_value, flags_value);
1135         }
1136       
1137     }
1138   else if (g_scanner_get_next_token (scanner) == '(')
1139     {
1140       guint token, flags_value = 0;
1141
1142       /* parse first value */
1143       token = parse_flags_value (scanner, class, &flags_value);
1144
1145       /* parse nth values, preceeded by '|' */
1146       while (token == G_TOKEN_NONE && g_scanner_get_next_token (scanner) == '|')
1147         token = parse_flags_value (scanner, class, &flags_value);
1148
1149       /* done, last token must have closed expression */
1150       if (token == G_TOKEN_NONE && scanner->token == ')' &&
1151           g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
1152         {
1153           g_value_set_flags (property_value, flags_value);
1154           success = TRUE;
1155         }
1156     }
1157   g_scanner_destroy (scanner);
1158
1159   return success;
1160 }
1161
1162 static gboolean
1163 get_braced_int (GScanner *scanner,
1164                 gboolean  first,
1165                 gboolean  last,
1166                 gint     *value)
1167 {
1168   if (first)
1169     {
1170       g_scanner_get_next_token (scanner);
1171       if (scanner->token != '{')
1172         return FALSE;
1173     }
1174
1175   g_scanner_get_next_token (scanner);
1176   if (scanner->token != G_TOKEN_INT)
1177     return FALSE;
1178
1179   *value = scanner->value.v_int;
1180
1181   if (last)
1182     {
1183       g_scanner_get_next_token (scanner);
1184       if (scanner->token != '}')
1185         return FALSE;
1186     }
1187   else
1188     {
1189       g_scanner_get_next_token (scanner);
1190       if (scanner->token != ',')
1191         return FALSE;
1192     }
1193
1194   return TRUE;
1195 }
1196
1197 /**
1198  * gtk_rc_property_parse_requisition:
1199  * @pspec: a #GParamSpec
1200  * @gstring: the #GString to be parsed
1201  * @property_value: a #GValue which must hold boxed values.
1202  * 
1203  * A #GtkRcPropertyParser for use with gtk_settings_install_property_parser()
1204  * or gtk_widget_class_install_style_property_parser() which parses a
1205  * requisition in the form 
1206  * <literal>"{ width, height }"</literal> for integers %width and %height.
1207  * 
1208  * Return value: %TRUE if @gstring could be parsed and @property_value
1209  * has been set to the resulting #GtkRequisition.
1210  **/
1211 gboolean
1212 gtk_rc_property_parse_requisition  (const GParamSpec *pspec,
1213                                     const GString    *gstring,
1214                                     GValue           *property_value)
1215 {
1216   GtkRequisition requisition;
1217   GScanner *scanner;
1218   gboolean success = FALSE;
1219
1220   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
1221   g_return_val_if_fail (G_VALUE_HOLDS_BOXED (property_value), FALSE);
1222
1223   scanner = gtk_rc_scanner_new ();
1224   g_scanner_input_text (scanner, gstring->str, gstring->len);
1225
1226   if (get_braced_int (scanner, TRUE, FALSE, &requisition.width) &&
1227       get_braced_int (scanner, FALSE, TRUE, &requisition.height))
1228     {
1229       g_value_set_boxed (property_value, &requisition);
1230       success = TRUE;
1231     }
1232
1233   g_scanner_destroy (scanner);
1234
1235   return success;
1236 }
1237
1238 /**
1239  * gtk_rc_property_parse_border:
1240  * @pspec: a #GParamSpec
1241  * @gstring: the #GString to be parsed
1242  * @property_value: a #GValue which must hold boxed values.
1243  * 
1244  * A #GtkRcPropertyParser for use with gtk_settings_install_property_parser()
1245  * or gtk_widget_class_install_style_property_parser() which parses
1246  * borders in the form 
1247  * <literal>"{ left, right, top, bottom }"</literal> for integers 
1248  * %left, %right, %top and %bottom.
1249  * 
1250  * Return value: %TRUE if @gstring could be parsed and @property_value
1251  * has been set to the resulting #GtkBorder.
1252  **/
1253 gboolean
1254 gtk_rc_property_parse_border (const GParamSpec *pspec,
1255                               const GString    *gstring,
1256                               GValue           *property_value)
1257 {
1258   GtkBorder border;
1259   GScanner *scanner;
1260   gboolean success = FALSE;
1261
1262   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
1263   g_return_val_if_fail (G_VALUE_HOLDS_BOXED (property_value), FALSE);
1264
1265   scanner = gtk_rc_scanner_new ();
1266   g_scanner_input_text (scanner, gstring->str, gstring->len);
1267
1268   if (get_braced_int (scanner, TRUE, FALSE, &border.left) &&
1269       get_braced_int (scanner, FALSE, FALSE, &border.right) &&
1270       get_braced_int (scanner, FALSE, FALSE, &border.top) &&
1271       get_braced_int (scanner, FALSE, TRUE, &border.bottom))
1272     {
1273       g_value_set_boxed (property_value, &border);
1274       success = TRUE;
1275     }
1276
1277   g_scanner_destroy (scanner);
1278
1279   return success;
1280 }
1281
1282 void
1283 _gtk_settings_handle_event (GdkEventSetting *event)
1284 {
1285   GtkSettings *settings = gtk_settings_get_for_screen (gdk_drawable_get_screen (event->window));
1286   
1287   if (g_object_class_find_property (G_OBJECT_GET_CLASS (settings), event->name))
1288     g_object_notify (G_OBJECT (settings), event->name);
1289 }
1290
1291 static void
1292 reset_rc_values_foreach (GQuark    key_id,
1293                          gpointer  data,
1294                          gpointer  user_data)
1295 {
1296   GtkSettingsValuePrivate *qvalue = data;
1297   GSList **to_reset = user_data;
1298
1299   if (qvalue->source == GTK_SETTINGS_SOURCE_RC_FILE)
1300     *to_reset = g_slist_prepend (*to_reset, GUINT_TO_POINTER (key_id));
1301 }
1302
1303 void
1304 _gtk_settings_reset_rc_values (GtkSettings *settings)
1305 {
1306   GSList *to_reset = NULL;
1307   GSList *tmp_list;
1308   GParamSpec **pspecs, **p;
1309   gint i;
1310
1311   /* Remove any queued settings
1312    */
1313   g_datalist_foreach (&settings->queued_settings,
1314                       reset_rc_values_foreach,
1315                       &to_reset);
1316
1317   for (tmp_list = to_reset; tmp_list; tmp_list = tmp_list->next)
1318     {
1319       GQuark key_id = GPOINTER_TO_UINT (tmp_list->data);
1320       g_datalist_id_remove_data (&settings->queued_settings, key_id);
1321     }
1322
1323   /* Now reset the active settings
1324    */
1325   pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (settings), NULL);
1326   i = 0;
1327
1328   g_object_freeze_notify (G_OBJECT (settings));
1329   for (p = pspecs; *p; p++)
1330     {
1331       if (settings->property_values[i].source == GTK_SETTINGS_SOURCE_RC_FILE)
1332         {
1333           GParamSpec *pspec = *p;
1334
1335           g_param_value_set_default (pspec, &settings->property_values[i].value);
1336           g_object_notify (G_OBJECT (settings), pspec->name);
1337         }
1338       i++;
1339     }
1340   g_object_thaw_notify (G_OBJECT (settings));
1341   g_free (pspecs);
1342 }
1343
1344 static void
1345 settings_update_double_click (GtkSettings *settings)
1346 {
1347   if (gdk_screen_get_number (settings->screen) == 0)
1348     {
1349       GdkDisplay *display = gdk_screen_get_display (settings->screen);
1350       gint double_click_time;
1351       gint double_click_distance;
1352   
1353       g_object_get (settings, 
1354                     "gtk-double-click-time", &double_click_time, 
1355                     "gtk-double-click-distance", &double_click_distance,
1356                     NULL);
1357       
1358       gdk_display_set_double_click_time (display, double_click_time);
1359       gdk_display_set_double_click_distance (display, double_click_distance);
1360     }
1361 }