]> Pileus Git - ~andy/gtk/blob - gtk/gtksettings.c
Document 2.2 API additions.
[~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 enum {
46   PROP_0,
47   PROP_DOUBLE_CLICK_TIME,
48   PROP_CURSOR_BLINK,
49   PROP_CURSOR_BLINK_TIME,
50   PROP_SPLIT_CURSOR,
51   PROP_THEME_NAME,
52   PROP_KEY_THEME_NAME,
53   PROP_MENU_BAR_ACCEL,
54   PROP_DND_DRAG_THRESHOLD,
55   PROP_FONT_NAME,
56   PROP_ICON_SIZES
57 };
58
59
60 /* --- prototypes --- */
61 static void     gtk_settings_init                (GtkSettings           *settings);
62 static void     gtk_settings_class_init          (GtkSettingsClass      *class);
63 static void     gtk_settings_finalize            (GObject               *object);
64 static void     gtk_settings_get_property        (GObject               *object,
65                                                   guint                  property_id,
66                                                   GValue                *value,
67                                                   GParamSpec            *pspec);
68 static void     gtk_settings_set_property        (GObject               *object,
69                                                   guint                  property_id,
70                                                   const GValue          *value,
71                                                   GParamSpec            *pspec);
72 static void     gtk_settings_notify              (GObject               *object,
73                                                   GParamSpec            *pspec);
74 static guint    settings_install_property_parser (GtkSettingsClass      *class,
75                                                   GParamSpec            *pspec,
76                                                   GtkRcPropertyParser    parser);
77
78
79 /* --- variables --- */
80 static gpointer          parent_class = NULL;
81 static GQuark            quark_property_parser = 0;
82 static GSList           *object_list = NULL;
83 static guint             class_n_properties = 0;
84
85
86 /* --- functions --- */
87 GType
88 gtk_settings_get_type (void)
89 {
90   static GType settings_type = 0;
91   
92   if (!settings_type)
93     {
94       static const GTypeInfo settings_info =
95       {
96         sizeof (GtkSettingsClass),
97         NULL,           /* base_init */
98         NULL,           /* base_finalize */
99         (GClassInitFunc) gtk_settings_class_init,
100         NULL,           /* class_finalize */
101         NULL,           /* class_data */
102         sizeof (GtkSettings),
103         0,              /* n_preallocs */
104         (GInstanceInitFunc) gtk_settings_init,
105       };
106       
107       settings_type = g_type_register_static (G_TYPE_OBJECT, "GtkSettings",
108                                               &settings_info, 0);
109     }
110   
111   return settings_type;
112 }
113
114 static void
115 gtk_settings_init (GtkSettings *settings)
116 {
117   GParamSpec **pspecs, **p;
118   guint i = 0;
119   
120   g_datalist_init (&settings->queued_settings);
121   object_list = g_slist_prepend (object_list, settings);
122
123   /* build up property array for all yet existing properties and queue
124    * notification for them (at least notification for internal properties
125    * will instantly be caught)
126    */
127   pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (settings), NULL);
128   for (p = pspecs; *p; p++)
129     if ((*p)->owner_type == G_OBJECT_TYPE (settings))
130       i++;
131   settings->property_values = g_new0 (GtkSettingsPropertyValue, i);
132   i = 0;
133   g_object_freeze_notify (G_OBJECT (settings));
134   for (p = pspecs; *p; p++)
135     {
136       GParamSpec *pspec = *p;
137
138       if (pspec->owner_type != G_OBJECT_TYPE (settings))
139         continue;
140       g_value_init (&settings->property_values[i].value, G_PARAM_SPEC_VALUE_TYPE (pspec));
141       g_param_value_set_default (pspec, &settings->property_values[i].value);
142       g_object_notify (G_OBJECT (settings), pspec->name);
143       settings->property_values[i].source = GTK_SETTINGS_SOURCE_DEFAULT;
144       i++;
145     }
146   g_object_thaw_notify (G_OBJECT (settings));
147   g_free (pspecs);
148 }
149
150 static void
151 gtk_settings_class_init (GtkSettingsClass *class)
152 {
153   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
154   guint result;
155   
156   parent_class = g_type_class_peek_parent (class);
157
158   gobject_class->finalize = gtk_settings_finalize;
159   gobject_class->get_property = gtk_settings_get_property;
160   gobject_class->set_property = gtk_settings_set_property;
161   gobject_class->notify = gtk_settings_notify;
162
163   quark_property_parser = g_quark_from_static_string ("gtk-rc-property-parser");
164
165   result = settings_install_property_parser (class,
166                                              g_param_spec_int ("gtk-double-click-time",
167                                                                _("Double Click Time"),
168                                                                _("Maximum time allowed between two clicks for them to be considered a double click (in milliseconds)"),
169                                                                0, G_MAXINT, 250,
170                                                                G_PARAM_READWRITE),
171                                              NULL);
172   g_assert (result == PROP_DOUBLE_CLICK_TIME);
173   result = settings_install_property_parser (class,
174                                              g_param_spec_boolean ("gtk-cursor-blink",
175                                                                    _("Cursor Blink"),
176                                                                    _("Whether the cursor should blink"),
177                                                                    TRUE,
178                                                                    G_PARAM_READWRITE),
179                                              NULL);
180   g_assert (result == PROP_CURSOR_BLINK);
181   result = settings_install_property_parser (class,
182                                              g_param_spec_int ("gtk-cursor-blink-time",
183                                                                _("Cursor Blink Time"),
184                                                                _("Length of the cursor blink cycle, in milleseconds"),
185                                                                100, G_MAXINT, 1200,
186                                                                G_PARAM_READWRITE),
187                                              NULL);
188   g_assert (result == PROP_CURSOR_BLINK_TIME);
189   result = settings_install_property_parser (class,
190                                              g_param_spec_boolean ("gtk-split-cursor",
191                                                                    _("Split Cursor"),
192                                                                    _("Whether two cursors should be displayed for mixed left-to-right and right-to-left text"),
193                                                                    TRUE,
194                                                                    G_PARAM_READWRITE),
195                                              NULL);
196   g_assert (result == PROP_SPLIT_CURSOR);
197   result = settings_install_property_parser (class,
198                                              g_param_spec_string ("gtk-theme-name",
199                                                                    _("Theme Name"),
200                                                                    _("Name of theme RC file to load"),
201                                                                   "Default",
202                                                                   G_PARAM_READWRITE),
203                                              NULL);
204   g_assert (result == PROP_THEME_NAME);
205   result = settings_install_property_parser (class,
206                                              g_param_spec_string ("gtk-key-theme-name",
207                                                                   _("Key Theme Name"),
208                                                                   _("Name of key theme RC file to load"),
209                                                                   NULL,
210                                                                   G_PARAM_READWRITE),
211                                              NULL);
212   g_assert (result == PROP_KEY_THEME_NAME);    
213
214   result = settings_install_property_parser (class,
215                                              g_param_spec_string ("gtk-menu-bar-accel",
216                                                                   _("Menu bar accelerator"),
217                                                                   _("Keybinding to activate the menu bar"),
218                                                                   "F10",
219                                                                   G_PARAM_READWRITE),
220                                              NULL);
221   g_assert (result == PROP_MENU_BAR_ACCEL);
222
223   result = settings_install_property_parser (class,
224                                              g_param_spec_int ("gtk-dnd-drag-threshold",
225                                                                _("Drag threshold"),
226                                                                _("Number of pixels the cursor can move before dragging"),
227                                                                1, G_MAXINT, 8,
228                                                                G_PARAM_READWRITE),
229                                              NULL);
230   g_assert (result == PROP_DND_DRAG_THRESHOLD);
231
232   result = settings_install_property_parser (class,
233                                              g_param_spec_string ("gtk-font-name",
234                                                                    _("Font Name"),
235                                                                    _("Name of default font to use"),
236                                                                   "Sans 10",
237                                                                   G_PARAM_READWRITE),
238                                              NULL);
239   g_assert (result == PROP_FONT_NAME);
240
241   result = settings_install_property_parser (class,
242                                              g_param_spec_string ("gtk-icon-sizes",
243                                                                    _("Icon Sizes"),
244                                                                    _("List of icon sizes (gtk-menu=16,16;gtk-button=20,20..."),
245                                                                   NULL,
246                                                                   G_PARAM_READWRITE),
247                                              NULL);
248   g_assert (result == PROP_ICON_SIZES);
249 }
250
251 static void
252 gtk_settings_finalize (GObject *object)
253 {
254   GtkSettings *settings = GTK_SETTINGS (object);
255   guint i;
256
257   object_list = g_slist_remove (object_list, settings);
258
259   for (i = 0; i < class_n_properties; i++)
260     g_value_unset (&settings->property_values[i].value);
261   g_free (settings->property_values);
262
263   g_datalist_clear (&settings->queued_settings);
264
265   G_OBJECT_CLASS (parent_class)->finalize (object);
266 }
267
268 /**
269  * gtk_settings_get_for_screen:
270  * @screen : a #GdkScreen.
271  * 
272  * Gets the #GtkSettings object for @screen, creating it if necessary.
273  *
274  * Return value: a #GtkSettings object.
275  *
276  * Since: 2.2
277  */
278 GtkSettings*
279 gtk_settings_get_for_screen (GdkScreen *screen)
280 {
281   GtkSettings *settings;
282   
283   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
284   
285   settings = g_object_get_data (G_OBJECT (screen), "gtk-settings");
286   if (!settings)
287     {
288       settings = g_object_new (GTK_TYPE_SETTINGS, NULL);
289       settings->screen = screen;
290       g_object_set_data (G_OBJECT (screen), "gtk-settings", settings); 
291       gtk_rc_reparse_all_for_settings (settings, TRUE);
292     }
293   
294   return settings;
295 }
296
297 /**
298  * gtk_settings_get_default:
299  * 
300  * Gets the #GtkSettings object for the default GDK screen, creating
301  * it if necessary. See gtk_settings_get_for_screen().
302  * 
303  * Return value: a #GtkSettings object. If there is no default
304  *  screen, then returns %NULL.
305  **/
306 GtkSettings*
307 gtk_settings_get_default (void)
308 {
309   GdkScreen *screen = gdk_screen_get_default ();
310
311   if (screen)
312     return gtk_settings_get_for_screen (screen);
313   else
314     return NULL;
315 }
316
317 static void
318 gtk_settings_set_property (GObject      *object,
319                            guint         property_id,
320                            const GValue *value,
321                            GParamSpec   *pspec)
322 {
323   GtkSettings *settings = GTK_SETTINGS (object);
324
325   g_value_copy (value, &settings->property_values[property_id - 1].value);
326   settings->property_values[property_id - 1].source = GTK_SETTINGS_SOURCE_APPLICATION;
327 }
328
329 static void
330 gtk_settings_get_property (GObject     *object,
331                            guint        property_id,
332                            GValue      *value,
333                            GParamSpec  *pspec)
334 {
335   GtkSettings *settings = GTK_SETTINGS (object);
336   GType value_type = G_VALUE_TYPE (value);
337   GType fundamental_type = G_TYPE_FUNDAMENTAL (value_type);
338
339   /* For enums and strings, we need to get the value as a string,
340    * not as an int, since we support using names/nicks as the setting
341    * value.
342    */
343   if ((g_value_type_transformable (G_TYPE_INT, value_type) &&
344        !(fundamental_type == G_TYPE_ENUM || fundamental_type == G_TYPE_FLAGS)) ||
345       g_value_type_transformable (G_TYPE_STRING, G_VALUE_TYPE (value)) ||
346       g_value_type_transformable (GDK_TYPE_COLOR, G_VALUE_TYPE (value)))
347     {
348       if (settings->property_values[property_id - 1].source == GTK_SETTINGS_SOURCE_APPLICATION ||
349           !gdk_screen_get_setting (settings->screen, pspec->name, value))
350         g_value_copy (&settings->property_values[property_id - 1].value, value);
351       else
352         g_param_value_validate (pspec, value);
353     }
354   else
355     {
356       GValue val = { 0, };
357
358       /* Try to get xsetting as a string and parse it. */
359       
360       g_value_init (&val, G_TYPE_STRING);
361
362       if (settings->property_values[property_id - 1].source == GTK_SETTINGS_SOURCE_APPLICATION ||
363           !gdk_screen_get_setting (settings->screen, pspec->name, &val))
364         {
365           g_value_copy (&settings->property_values[property_id - 1].value, value);
366         }
367       else
368         {
369           GValue tmp_value = { 0, };
370           GValue gstring_value = { 0, };
371           GtkRcPropertyParser parser = (GtkRcPropertyParser) g_param_spec_get_qdata (pspec, quark_property_parser);
372           
373           g_value_init (&gstring_value, G_TYPE_GSTRING);
374
375           g_value_set_boxed (&gstring_value,
376                              g_string_new (g_value_get_string (&val)));
377
378           g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
379
380           if (parser && _gtk_settings_parse_convert (parser, &gstring_value,
381                                                      pspec, &tmp_value))
382             {
383               g_value_copy (&tmp_value, value);
384               g_param_value_validate (pspec, value);
385             }
386           else
387             {
388               g_value_copy (&settings->property_values[property_id - 1].value, value);
389             }
390
391           g_value_unset (&gstring_value);
392           g_value_unset (&tmp_value);
393         }
394
395       g_value_unset (&val);
396     }
397 }
398
399 static void
400 gtk_settings_notify (GObject    *object,
401                      GParamSpec *pspec)
402 {
403   GtkSettings *settings = GTK_SETTINGS (object);
404   guint property_id = pspec->param_id;
405   gint double_click_time;
406
407   if (settings->screen == NULL) /* initialization */
408     return;
409
410   switch (property_id)
411     {
412     case PROP_DOUBLE_CLICK_TIME:
413       {
414         GdkDisplay *display;
415         
416         g_object_get (object, pspec->name, &double_click_time, NULL);
417         display = gdk_screen_get_display (settings->screen);
418         if (settings->screen == gdk_display_get_screen (display, 0))
419           gdk_display_set_double_click_time (display, double_click_time);
420         break;
421       }
422     }
423 }
424
425 gboolean
426 _gtk_settings_parse_convert (GtkRcPropertyParser parser,
427                              const GValue       *src_value,
428                              GParamSpec         *pspec,
429                              GValue             *dest_value)
430 {
431   gboolean success = FALSE;
432
433   g_return_val_if_fail (G_VALUE_HOLDS (dest_value, G_PARAM_SPEC_VALUE_TYPE (pspec)), FALSE);
434
435   if (parser)
436     {
437       GString *gstring;
438       gboolean free_gstring = TRUE;
439       
440       if (G_VALUE_HOLDS (src_value, G_TYPE_GSTRING))
441         {
442           gstring = g_value_get_boxed (src_value);
443           free_gstring = FALSE;
444         }
445       else if (G_VALUE_HOLDS_LONG (src_value))
446         {
447           gstring = g_string_new ("");
448           g_string_append_printf (gstring, "%ld", g_value_get_long (src_value));
449         }
450       else if (G_VALUE_HOLDS_DOUBLE (src_value))
451         {
452           gstring = g_string_new ("");
453           g_string_append_printf (gstring, "%f", g_value_get_double (src_value));
454         }
455       else if (G_VALUE_HOLDS_STRING (src_value))
456         {
457           gchar *tstr = g_strescape (g_value_get_string (src_value), NULL);
458           
459           gstring = g_string_new ("\"");
460           g_string_append (gstring, tstr);
461           g_string_append_c (gstring, '\"');
462           g_free (tstr);
463         }
464       else
465         {
466           g_return_val_if_fail (G_VALUE_HOLDS (src_value, G_TYPE_GSTRING), FALSE);
467           gstring = NULL; /* silence compiler */
468         }
469
470       success = (parser (pspec, gstring, dest_value) &&
471                  !g_param_value_validate (pspec, dest_value));
472
473       if (free_gstring)
474         g_string_free (gstring, TRUE);
475     }
476   else if (G_VALUE_HOLDS (src_value, G_TYPE_GSTRING))
477     {
478       if (G_VALUE_HOLDS (dest_value, G_TYPE_STRING))
479         {
480           GString *gstring = g_value_get_boxed (src_value);
481
482           g_value_set_string (dest_value, gstring ? gstring->str : NULL);
483           success = !g_param_value_validate (pspec, dest_value);
484         }
485     }
486   else if (g_value_type_transformable (G_VALUE_TYPE (src_value), G_VALUE_TYPE (dest_value)))
487     success = g_param_value_convert (pspec, src_value, dest_value, TRUE);
488
489   return success;
490 }
491
492 static void
493 apply_queued_setting (GtkSettings             *data,
494                       GParamSpec              *pspec,
495                       GtkSettingsValuePrivate *qvalue)
496 {
497   GValue tmp_value = { 0, };
498   GtkRcPropertyParser parser = (GtkRcPropertyParser) g_param_spec_get_qdata (pspec, quark_property_parser);
499
500   g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
501   if (_gtk_settings_parse_convert (parser, &qvalue->public.value,
502                                    pspec, &tmp_value))
503     {
504       g_object_set_property (G_OBJECT (data), pspec->name, &tmp_value);
505       data->property_values[pspec->param_id - 1].source = qvalue->source;
506     }
507   else
508     {
509       gchar *debug = g_strdup_value_contents (&qvalue->public.value);
510       
511       g_message ("%s: failed to retrieve property `%s' of type `%s' from rc file value \"%s\" of type `%s'",
512                  qvalue->public.origin,
513                  pspec->name,
514                  g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
515                  debug,
516                  G_VALUE_TYPE_NAME (&tmp_value));
517       g_free (debug);
518     }
519   g_value_unset (&tmp_value);
520 }
521
522 static guint
523 settings_install_property_parser (GtkSettingsClass   *class,
524                                   GParamSpec         *pspec,
525                                   GtkRcPropertyParser parser)
526 {
527   GSList *node, *next;
528
529   switch (G_TYPE_FUNDAMENTAL (G_PARAM_SPEC_VALUE_TYPE (pspec)))
530     {
531     case G_TYPE_BOOLEAN:
532     case G_TYPE_UCHAR:
533     case G_TYPE_CHAR:
534     case G_TYPE_UINT:
535     case G_TYPE_INT:
536     case G_TYPE_ULONG:
537     case G_TYPE_LONG:
538     case G_TYPE_FLOAT:
539     case G_TYPE_DOUBLE:
540     case G_TYPE_STRING:
541       break;
542     default:
543       if (!parser)
544         {
545           g_warning (G_STRLOC ": parser needs to be specified for property \"%s\" of type `%s'",
546                      pspec->name, g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
547           return 0;
548         }
549     }
550   if (g_object_class_find_property (G_OBJECT_CLASS (class), pspec->name))
551     {
552       g_warning (G_STRLOC ": an rc-data property \"%s\" already exists",
553                  pspec->name);
554       return 0;
555     }
556   
557   for (node = object_list; node; node = node->next)
558     g_object_freeze_notify (node->data);
559
560   g_object_class_install_property (G_OBJECT_CLASS (class), ++class_n_properties, pspec);
561   g_param_spec_set_qdata (pspec, quark_property_parser, (gpointer) parser);
562
563   for (node = object_list; node; node = node->next)
564     {
565       GtkSettings *settings = node->data;
566       GtkSettingsValuePrivate *qvalue;
567       
568       settings->property_values = g_renew (GtkSettingsPropertyValue, settings->property_values, class_n_properties);
569       settings->property_values[class_n_properties - 1].value.g_type = 0;
570       g_value_init (&settings->property_values[class_n_properties - 1].value, G_PARAM_SPEC_VALUE_TYPE (pspec));
571       g_param_value_set_default (pspec, &settings->property_values[class_n_properties - 1].value);
572       settings->property_values[class_n_properties - 1].source = GTK_SETTINGS_SOURCE_DEFAULT;
573       g_object_notify (G_OBJECT (settings), pspec->name);
574       
575       qvalue = g_datalist_get_data (&settings->queued_settings, pspec->name);
576       if (qvalue)
577         apply_queued_setting (settings, pspec, qvalue);
578     }
579
580   for (node = object_list; node; node = next)
581     {
582       next = node->next;
583       g_object_thaw_notify (node->data);
584     }
585
586   return class_n_properties;
587 }
588
589 GtkRcPropertyParser
590 _gtk_rc_property_parser_from_type (GType type)
591 {
592   if (type == GDK_TYPE_COLOR)
593     return gtk_rc_property_parse_color;
594   else if (type == GTK_TYPE_REQUISITION)
595     return gtk_rc_property_parse_requisition;
596   else if (type == GTK_TYPE_BORDER)
597     return gtk_rc_property_parse_border;
598   else if (G_TYPE_FUNDAMENTAL (type) == G_TYPE_ENUM && G_TYPE_IS_DERIVED (type))
599     return gtk_rc_property_parse_enum;
600   else if (G_TYPE_FUNDAMENTAL (type) == G_TYPE_FLAGS && G_TYPE_IS_DERIVED (type))
601     return gtk_rc_property_parse_flags;
602   else
603     return NULL;
604 }
605
606 void
607 gtk_settings_install_property (GParamSpec *pspec)
608 {
609   GtkRcPropertyParser parser;
610
611   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
612
613   parser = _gtk_rc_property_parser_from_type (G_PARAM_SPEC_VALUE_TYPE (pspec));
614
615   settings_install_property_parser (gtk_type_class (GTK_TYPE_SETTINGS), pspec, parser);
616 }
617
618 void
619 gtk_settings_install_property_parser (GParamSpec          *pspec,
620                                       GtkRcPropertyParser  parser)
621 {
622   g_return_if_fail (G_IS_PARAM_SPEC (pspec));
623   g_return_if_fail (parser != NULL);
624   
625   settings_install_property_parser (gtk_type_class (GTK_TYPE_SETTINGS), pspec, parser);
626 }
627
628 static void
629 free_value (gpointer data)
630 {
631   GtkSettingsValuePrivate *qvalue = data;
632   
633   g_value_unset (&qvalue->public.value);
634   g_free (qvalue->public.origin);
635   g_free (qvalue);
636 }
637
638 static void
639 gtk_settings_set_property_value_internal (GtkSettings            *settings,
640                                           const gchar            *prop_name,
641                                           const GtkSettingsValue *new_value,
642                                           GtkSettingsSource       source)
643 {
644   GtkSettingsValuePrivate *qvalue;
645   GParamSpec *pspec;
646   gchar *name;
647   GQuark name_quark;
648
649   if (!G_VALUE_HOLDS_LONG (&new_value->value) &&
650       !G_VALUE_HOLDS_DOUBLE (&new_value->value) &&
651       !G_VALUE_HOLDS_STRING (&new_value->value) &&
652       !G_VALUE_HOLDS (&new_value->value, G_TYPE_GSTRING))
653     {
654       g_warning (G_STRLOC ": value type invalid");
655       return;
656     }
657   
658   name = g_strdup (prop_name);
659   g_strcanon (name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-');
660   name_quark = g_quark_from_string (name);
661   g_free (name);
662
663   qvalue = g_datalist_id_get_data (&settings->queued_settings, name_quark);
664   if (!qvalue)
665     {
666       qvalue = g_new0 (GtkSettingsValuePrivate, 1);
667       g_datalist_id_set_data_full (&settings->queued_settings, name_quark, qvalue, free_value);
668     }
669   else
670     {
671       g_free (qvalue->public.origin);
672       g_value_unset (&qvalue->public.value);
673     }
674   qvalue->public.origin = g_strdup (new_value->origin);
675   g_value_init (&qvalue->public.value, G_VALUE_TYPE (&new_value->value));
676   g_value_copy (&new_value->value, &qvalue->public.value);
677   qvalue->source = source;
678   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (settings), g_quark_to_string (name_quark));
679   if (pspec)
680     apply_queued_setting (settings, pspec, qvalue);
681 }
682
683 void
684 gtk_settings_set_property_value (GtkSettings            *settings,
685                                  const gchar            *prop_name,
686                                  const GtkSettingsValue *new_value)
687 {
688   g_return_if_fail (GTK_SETTINGS (settings));
689   g_return_if_fail (prop_name != NULL);
690   g_return_if_fail (new_value != NULL);
691   g_return_if_fail (new_value->origin != NULL);
692
693   gtk_settings_set_property_value_internal (settings, prop_name, new_value,
694                                             GTK_SETTINGS_SOURCE_APPLICATION);
695 }
696
697 void
698 _gtk_settings_set_property_value_from_rc (GtkSettings            *settings,
699                                           const gchar            *prop_name,
700                                           const GtkSettingsValue *new_value)
701 {
702   g_return_if_fail (GTK_SETTINGS (settings));
703   g_return_if_fail (prop_name != NULL);
704   g_return_if_fail (new_value != NULL);
705   g_return_if_fail (new_value->origin != NULL);
706
707   gtk_settings_set_property_value_internal (settings, prop_name, new_value,
708                                             GTK_SETTINGS_SOURCE_RC_FILE);
709 }
710
711 void
712 gtk_settings_set_string_property (GtkSettings *settings,
713                                   const gchar *name,
714                                   const gchar *v_string,
715                                   const gchar *origin)
716 {
717   GtkSettingsValue svalue = { NULL, { 0, }, };
718
719   g_return_if_fail (GTK_SETTINGS (settings));
720   g_return_if_fail (name != NULL);
721   g_return_if_fail (v_string != NULL);
722   g_return_if_fail (origin != NULL);
723
724   svalue.origin = (gchar*) origin;
725   g_value_init (&svalue.value, G_TYPE_STRING);
726   g_value_set_static_string (&svalue.value, v_string);
727   gtk_settings_set_property_value (settings, name, &svalue);
728   g_value_unset (&svalue.value);
729 }
730
731 void
732 gtk_settings_set_long_property (GtkSettings *settings,
733                                 const gchar *name,
734                                 glong        v_long,
735                                 const gchar *origin)
736 {
737   GtkSettingsValue svalue = { NULL, { 0, }, };
738   
739   g_return_if_fail (GTK_SETTINGS (settings));
740   g_return_if_fail (name != NULL);
741   g_return_if_fail (origin != NULL);
742
743   svalue.origin = (gchar*) origin;
744   g_value_init (&svalue.value, G_TYPE_LONG);
745   g_value_set_long (&svalue.value, v_long);
746   gtk_settings_set_property_value (settings, name, &svalue);
747   g_value_unset (&svalue.value);
748 }
749
750 void
751 gtk_settings_set_double_property (GtkSettings *settings,
752                                   const gchar *name,
753                                   gdouble      v_double,
754                                   const gchar *origin)
755 {
756   GtkSettingsValue svalue = { NULL, { 0, }, };
757
758   g_return_if_fail (GTK_SETTINGS (settings));
759   g_return_if_fail (name != NULL);
760   g_return_if_fail (origin != NULL);
761
762   svalue.origin = (gchar*) origin;
763   g_value_init (&svalue.value, G_TYPE_DOUBLE);
764   g_value_set_double (&svalue.value, v_double);
765   gtk_settings_set_property_value (settings, name, &svalue);
766   g_value_unset (&svalue.value);
767 }
768
769 gboolean
770 gtk_rc_property_parse_color (const GParamSpec *pspec,
771                              const GString    *gstring,
772                              GValue           *property_value)
773 {
774   GdkColor color = { 0, 0, 0, 0, };
775   GScanner *scanner;
776   gboolean success;
777
778   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
779   g_return_val_if_fail (G_VALUE_HOLDS (property_value, GDK_TYPE_COLOR), FALSE);
780
781   scanner = gtk_rc_scanner_new ();
782   g_scanner_input_text (scanner, gstring->str, gstring->len);
783   if (gtk_rc_parse_color (scanner, &color) == G_TOKEN_NONE &&
784       g_scanner_get_next_token (scanner) == G_TOKEN_EOF)
785     {
786       g_value_set_boxed (property_value, &color);
787       success = TRUE;
788     }
789   else
790     success = FALSE;
791   g_scanner_destroy (scanner);
792
793   return success;
794 }
795
796 gboolean
797 gtk_rc_property_parse_enum (const GParamSpec *pspec,
798                             const GString    *gstring,
799                             GValue           *property_value)
800 {
801   gboolean need_closing_brace = FALSE, success = FALSE;
802   GScanner *scanner;
803   GEnumValue *enum_value = NULL;
804
805   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
806   g_return_val_if_fail (G_VALUE_HOLDS_ENUM (property_value), FALSE);
807
808   scanner = gtk_rc_scanner_new ();
809   g_scanner_input_text (scanner, gstring->str, gstring->len);
810
811   /* we just want to parse _one_ value, but for consistency with flags parsing
812    * we support optional paranthesis
813    */
814   g_scanner_get_next_token (scanner);
815   if (scanner->token == '(')
816     {
817       need_closing_brace = TRUE;
818       g_scanner_get_next_token (scanner);
819     }
820   if (scanner->token == G_TOKEN_IDENTIFIER)
821     {
822       GEnumClass *class = G_PARAM_SPEC_ENUM (pspec)->enum_class;
823       
824       enum_value = g_enum_get_value_by_name (class, scanner->value.v_identifier);
825       if (!enum_value)
826         enum_value = g_enum_get_value_by_nick (class, scanner->value.v_identifier);
827       if (enum_value)
828         {
829           g_value_set_enum (property_value, enum_value->value);
830           success = TRUE;
831         }
832     }
833   else if (scanner->token == G_TOKEN_INT)
834     {
835       g_value_set_enum (property_value, scanner->value.v_int);
836       success = TRUE;
837     }
838   if (need_closing_brace && g_scanner_get_next_token (scanner) != ')')
839     success = FALSE;
840   if (g_scanner_get_next_token (scanner) != G_TOKEN_EOF)
841     success = FALSE;
842
843   g_scanner_destroy (scanner);
844
845   return success;
846 }
847
848 static guint
849 parse_flags_value (GScanner    *scanner,
850                    GFlagsClass *class,
851                    guint       *number)
852 {
853   g_scanner_get_next_token (scanner);
854   if (scanner->token == G_TOKEN_IDENTIFIER)
855     {
856       GFlagsValue *flags_value;
857
858       flags_value = g_flags_get_value_by_name (class, scanner->value.v_identifier);
859       if (!flags_value)
860         flags_value = g_flags_get_value_by_nick (class, scanner->value.v_identifier);
861       if (flags_value)
862         {
863           *number |= flags_value->value;
864           return G_TOKEN_NONE;
865         }
866     }
867   else if (scanner->token == G_TOKEN_INT)
868     {
869       *number |= scanner->value.v_int;
870       return G_TOKEN_NONE;
871     }
872   return G_TOKEN_IDENTIFIER;
873 }
874
875 gboolean
876 gtk_rc_property_parse_flags (const GParamSpec *pspec,
877                              const GString    *gstring,
878                              GValue           *property_value)
879 {
880   GFlagsClass *class;
881   gboolean success = FALSE;
882   GScanner *scanner;
883
884   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
885   g_return_val_if_fail (G_VALUE_HOLDS_FLAGS (property_value), FALSE);
886
887   class = G_PARAM_SPEC_FLAGS (pspec)->flags_class;
888   scanner = gtk_rc_scanner_new ();
889   g_scanner_input_text (scanner, gstring->str, gstring->len);
890
891   /* parse either a single flags value or a "\( ... [ \| ... ] \)" compound */
892   if (g_scanner_peek_next_token (scanner) == G_TOKEN_IDENTIFIER ||
893       scanner->next_token == G_TOKEN_INT)
894     {
895       guint token, flags_value = 0;
896       
897       token = parse_flags_value (scanner, class, &flags_value);
898
899       if (token == G_TOKEN_NONE && g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
900         {
901           success = TRUE;
902           g_value_set_flags (property_value, flags_value);
903         }
904       
905     }
906   else if (g_scanner_get_next_token (scanner) == '(')
907     {
908       guint token, flags_value = 0;
909
910       /* parse first value */
911       token = parse_flags_value (scanner, class, &flags_value);
912
913       /* parse nth values, preceeded by '|' */
914       while (token == G_TOKEN_NONE && g_scanner_get_next_token (scanner) == '|')
915         token = parse_flags_value (scanner, class, &flags_value);
916
917       /* done, last token must have closed expression */
918       if (token == G_TOKEN_NONE && scanner->token == ')' &&
919           g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
920         {
921           g_value_set_flags (property_value, flags_value);
922           success = TRUE;
923         }
924     }
925   g_scanner_destroy (scanner);
926
927   return success;
928 }
929
930 static gboolean
931 get_braced_int (GScanner *scanner,
932                 gboolean  first,
933                 gboolean  last,
934                 gint     *value)
935 {
936   if (first)
937     {
938       g_scanner_get_next_token (scanner);
939       if (scanner->token != '{')
940         return FALSE;
941     }
942
943   g_scanner_get_next_token (scanner);
944   if (scanner->token != G_TOKEN_INT)
945     return FALSE;
946
947   *value = scanner->value.v_int;
948
949   if (last)
950     {
951       g_scanner_get_next_token (scanner);
952       if (scanner->token != '}')
953         return FALSE;
954     }
955   else
956     {
957       g_scanner_get_next_token (scanner);
958       if (scanner->token != ',')
959         return FALSE;
960     }
961
962   return TRUE;
963 }
964
965 gboolean
966 gtk_rc_property_parse_requisition  (const GParamSpec *pspec,
967                                     const GString    *gstring,
968                                     GValue           *property_value)
969 {
970   GtkRequisition requisition;
971   GScanner *scanner;
972   gboolean success = FALSE;
973
974   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
975   g_return_val_if_fail (G_VALUE_HOLDS_BOXED (property_value), FALSE);
976
977   scanner = gtk_rc_scanner_new ();
978   g_scanner_input_text (scanner, gstring->str, gstring->len);
979
980   if (get_braced_int (scanner, TRUE, FALSE, &requisition.width) &&
981       get_braced_int (scanner, FALSE, TRUE, &requisition.height))
982     {
983       g_value_set_boxed (property_value, &requisition);
984       success = TRUE;
985     }
986
987   g_scanner_destroy (scanner);
988
989   return success;
990 }
991
992 gboolean
993 gtk_rc_property_parse_border (const GParamSpec *pspec,
994                               const GString    *gstring,
995                               GValue           *property_value)
996 {
997   GtkBorder border;
998   GScanner *scanner;
999   gboolean success = FALSE;
1000
1001   g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE);
1002   g_return_val_if_fail (G_VALUE_HOLDS_BOXED (property_value), FALSE);
1003
1004   scanner = gtk_rc_scanner_new ();
1005   g_scanner_input_text (scanner, gstring->str, gstring->len);
1006
1007   if (get_braced_int (scanner, TRUE, FALSE, &border.left) &&
1008       get_braced_int (scanner, FALSE, FALSE, &border.right) &&
1009       get_braced_int (scanner, FALSE, FALSE, &border.top) &&
1010       get_braced_int (scanner, FALSE, TRUE, &border.bottom))
1011     {
1012       g_value_set_boxed (property_value, &border);
1013       success = TRUE;
1014     }
1015
1016   g_scanner_destroy (scanner);
1017
1018   return success;
1019 }
1020
1021 void
1022 _gtk_settings_handle_event (GdkEventSetting *event)
1023 {
1024   GtkSettings *settings = gtk_settings_get_for_screen (gdk_drawable_get_screen (event->window));
1025   
1026   if (g_object_class_find_property (G_OBJECT_GET_CLASS (settings), event->name))
1027     g_object_notify (G_OBJECT (settings), event->name);
1028 }
1029
1030 static void
1031 reset_rc_values_foreach (GQuark    key_id,
1032                          gpointer  data,
1033                          gpointer  user_data)
1034 {
1035   GtkSettingsValuePrivate *qvalue = data;
1036   GSList **to_reset = user_data;
1037
1038   if (qvalue->source == GTK_SETTINGS_SOURCE_RC_FILE)
1039     *to_reset = g_slist_prepend (*to_reset, GUINT_TO_POINTER (key_id));
1040 }
1041
1042 void
1043 _gtk_settings_reset_rc_values (GtkSettings *settings)
1044 {
1045   GSList *to_reset = NULL;
1046   GSList *tmp_list;
1047   GParamSpec **pspecs, **p;
1048   gint i;
1049
1050   /* Remove any queued settings
1051    */
1052   g_datalist_foreach (&settings->queued_settings,
1053                       reset_rc_values_foreach,
1054                       &to_reset);
1055
1056   for (tmp_list = to_reset; tmp_list; tmp_list = tmp_list->next)
1057     {
1058       GQuark key_id = GPOINTER_TO_UINT (tmp_list->data);
1059       g_datalist_id_remove_data (&settings->queued_settings, key_id);
1060     }
1061
1062   /* Now reset the active settings
1063    */
1064   pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (settings), NULL);
1065   i = 0;
1066
1067   g_object_freeze_notify (G_OBJECT (settings));
1068   for (p = pspecs; *p; p++)
1069     {
1070       if (settings->property_values[i].source == GTK_SETTINGS_SOURCE_RC_FILE)
1071         {
1072           GParamSpec *pspec = *p;
1073
1074           g_param_value_set_default (pspec, &settings->property_values[i].value);
1075           g_object_notify (G_OBJECT (settings), pspec->name);
1076         }
1077       i++;
1078     }
1079   g_object_thaw_notify (G_OBJECT (settings));
1080   g_free (pspecs);
1081 }
1082