Release Clutter 1.11.4 (snapshot)
[profile/ivi/clutter.git] / clutter / clutter-settings.c
1 /**
2  * SECTION:clutter-settings
3  * @Title: ClutterSettings
4  * @Short_Description: Settings configuration
5  *
6  * Clutter depends on some settings to perform operations like detecting
7  * multiple button press events, or font options to render text.
8  *
9  * Usually, Clutter will strive to use the platform's settings in order
10  * to be as much integrated as possible. It is, however, possible to
11  * change these settings on a per-application basis, by using the
12  * #ClutterSettings singleton object and setting its properties. It is
13  * also possible, for toolkit developers, to retrieve the settings from
14  * the #ClutterSettings properties when implementing new UI elements,
15  * for instance the default font name.
16  *
17  * #ClutterSettings is available since Clutter 1.4
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "clutter-settings.h"
25
26 #ifdef HAVE_PANGO_FT2
27 /* for pango_fc_font_map_cache_clear() */
28 #define PANGO_ENABLE_BACKEND
29 #include <pango/pangofc-fontmap.h>
30 #endif /* HAVE_PANGO_FT2 */
31
32 #include "clutter-debug.h"
33 #include "clutter-settings-private.h"
34 #include "clutter-private.h"
35
36 #define DEFAULT_FONT_NAME       "Sans 12"
37
38 #define CLUTTER_SETTINGS_CLASS(klass)           (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_SETTINGS, ClutterSettingsClass))
39 #define CLUTTER_IS_SETTINGS_CLASS(klass)        (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_SETTINGS))
40 #define CLUTTER_SETTINGS_GET_CLASS(obj)         (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_SETTINGS, ClutterSettingsClass))
41
42 /**
43  * ClutterSettings:
44  *
45  * <structname>ClutterSettings</structname> is an opaque structure whose
46  * members cannot be directly accessed.
47  *
48  * Since: 1.4
49  */
50 struct _ClutterSettings
51 {
52   GObject parent_instance;
53
54   ClutterBackend *backend;
55
56   gint double_click_time;
57   gint double_click_distance;
58
59   gint dnd_drag_threshold;
60
61   gdouble resolution;
62
63   gchar *font_name;
64
65   gint xft_hinting;
66   gint xft_antialias;
67   gchar *xft_hint_style;
68   gchar *xft_rgba;
69
70   gint long_press_duration;
71
72   guint last_fontconfig_timestamp;
73
74   guint password_hint_time;
75 };
76
77 struct _ClutterSettingsClass
78 {
79   GObjectClass parent_class;
80 };
81
82 enum
83 {
84   PROP_0,
85
86   PROP_BACKEND,
87
88   PROP_DOUBLE_CLICK_TIME,
89   PROP_DOUBLE_CLICK_DISTANCE,
90
91   PROP_DND_DRAG_THRESHOLD,
92
93   PROP_FONT_NAME,
94
95   PROP_FONT_ANTIALIAS,
96   PROP_FONT_DPI,
97   PROP_FONT_HINTING,
98   PROP_FONT_HINT_STYLE,
99   PROP_FONT_RGBA,
100
101   PROP_LONG_PRESS_DURATION,
102
103   PROP_FONTCONFIG_TIMESTAMP,
104
105   PROP_PASSWORD_HINT_TIME,
106
107   PROP_LAST
108 };
109
110 static GParamSpec *obj_props[PROP_LAST];
111
112 G_DEFINE_TYPE (ClutterSettings, clutter_settings, G_TYPE_OBJECT);
113
114 static inline void
115 settings_update_font_options (ClutterSettings *self)
116 {
117   cairo_hint_style_t hint_style = CAIRO_HINT_STYLE_NONE;
118   cairo_antialias_t antialias_mode = CAIRO_ANTIALIAS_GRAY;
119   cairo_subpixel_order_t subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
120   cairo_font_options_t *options;
121
122   if (self->backend == NULL)
123     return;
124
125   options = cairo_font_options_create ();
126
127   cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
128
129   if (self->xft_hinting >= 0 &&
130       self->xft_hint_style == NULL)
131     {
132       hint_style = CAIRO_HINT_STYLE_NONE;
133     }
134   else if (self->xft_hint_style != NULL)
135     {
136       if (strcmp (self->xft_hint_style, "hintnone") == 0)
137         hint_style = CAIRO_HINT_STYLE_NONE;
138       else if (strcmp (self->xft_hint_style, "hintslight") == 0)
139         hint_style = CAIRO_HINT_STYLE_SLIGHT;
140       else if (strcmp (self->xft_hint_style, "hintmedium") == 0)
141         hint_style = CAIRO_HINT_STYLE_MEDIUM;
142       else if (strcmp (self->xft_hint_style, "hintfull") == 0)
143         hint_style = CAIRO_HINT_STYLE_FULL;
144     }
145
146   cairo_font_options_set_hint_style (options, hint_style);
147
148   if (self->xft_rgba)
149     {
150       if (strcmp (self->xft_rgba, "rgb") == 0)
151         subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB;
152       else if (strcmp (self->xft_rgba, "bgr") == 0)
153         subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR;
154       else if (strcmp (self->xft_rgba, "vrgb") == 0)
155         subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB;
156       else if (strcmp (self->xft_rgba, "vbgr") == 0)
157         subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR;
158     }
159
160   cairo_font_options_set_subpixel_order (options, subpixel_order);
161
162   if (self->xft_antialias >= 0 && !self->xft_antialias)
163     antialias_mode = CAIRO_ANTIALIAS_NONE;
164   else if (subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT)
165     antialias_mode = CAIRO_ANTIALIAS_SUBPIXEL;
166   else if (self->xft_antialias >= 0)
167     antialias_mode = CAIRO_ANTIALIAS_GRAY;
168
169   cairo_font_options_set_antialias (options, antialias_mode);
170
171   CLUTTER_NOTE (BACKEND, "New font options:\n"
172                 " - font-name:  %s\n"
173                 " - antialias:  %d\n"
174                 " - hinting:    %d\n"
175                 " - hint-style: %s\n"
176                 " - rgba:       %s\n"
177                 " - dpi:        %.2f",
178                 self->font_name != NULL ? self->font_name : DEFAULT_FONT_NAME,
179                 self->xft_antialias,
180                 self->xft_hinting,
181                 self->xft_hint_style != NULL ? self->xft_hint_style : "<null>",
182                 self->xft_rgba != NULL ? self->xft_rgba : "<null>",
183                 self->resolution);
184
185   clutter_backend_set_font_options (self->backend, options);
186   cairo_font_options_destroy (options);
187 }
188
189 static void
190 settings_update_font_name (ClutterSettings *self)
191 {
192   CLUTTER_NOTE (BACKEND, "New font-name: %s", self->font_name);
193
194   if (self->backend != NULL)
195     g_signal_emit_by_name (self->backend, "font-changed");
196 }
197
198 static void
199 settings_update_resolution (ClutterSettings *self)
200 {
201   CLUTTER_NOTE (BACKEND, "New resolution: %.2f", self->resolution);
202
203   if (self->backend != NULL)
204     g_signal_emit_by_name (self->backend, "resolution-changed");
205 }
206
207 static void
208 settings_update_fontmap (ClutterSettings *self,
209                          guint            stamp)
210 {
211   if (self->backend == NULL)
212     return;
213
214 #ifdef HAVE_PANGO_FT2
215   CLUTTER_NOTE (BACKEND, "Update fontmaps (stamp: %d)", stamp);
216
217   if (self->last_fontconfig_timestamp != stamp)
218     {
219       PangoFontMap *fontmap;
220       gboolean update_needed = FALSE;
221
222       fontmap = clutter_get_font_map ();
223
224       if (PANGO_IS_FC_FONT_MAP (fontmap) &&
225           !FcConfigUptoDate (NULL))
226         {
227           pango_fc_font_map_cache_clear (PANGO_FC_FONT_MAP (fontmap));
228
229           if (FcInitReinitialize ())
230             update_needed = TRUE;
231         }
232
233       self->last_fontconfig_timestamp = stamp;
234
235       if (update_needed)
236         g_signal_emit_by_name (self->backend, "font-changed");
237     }
238 #endif /* HAVE_PANGO_FT2 */
239 }
240
241 static void
242 clutter_settings_finalize (GObject *gobject)
243 {
244   ClutterSettings *self = CLUTTER_SETTINGS (gobject);
245
246   g_free (self->font_name);
247   g_free (self->xft_hint_style);
248   g_free (self->xft_rgba);
249
250   G_OBJECT_CLASS (clutter_settings_parent_class)->finalize (gobject);
251 }
252
253 static void
254 clutter_settings_set_property (GObject      *gobject,
255                                guint         prop_id,
256                                const GValue *value,
257                                GParamSpec   *pspec)
258 {
259   ClutterSettings *self = CLUTTER_SETTINGS (gobject);
260
261   switch (prop_id)
262     {
263     case PROP_BACKEND:
264       self->backend = g_value_get_object (value);
265       break;
266
267     case PROP_DOUBLE_CLICK_TIME:
268       self->double_click_time = g_value_get_int (value);
269       break;
270
271     case PROP_DOUBLE_CLICK_DISTANCE:
272       self->double_click_distance = g_value_get_int (value);
273       break;
274
275     case PROP_DND_DRAG_THRESHOLD:
276       self->dnd_drag_threshold = g_value_get_int (value);
277       break;
278
279     case PROP_FONT_NAME:
280       g_free (self->font_name);
281       self->font_name = g_value_dup_string (value);
282       settings_update_font_name (self);
283       break;
284
285     case PROP_FONT_ANTIALIAS:
286       self->xft_antialias = g_value_get_int (value);
287       settings_update_font_options (self);
288       break;
289
290     case PROP_FONT_DPI:
291       self->resolution = (gdouble) g_value_get_int (value) / 1024.0;
292       settings_update_resolution (self);
293       break;
294
295     case PROP_FONT_HINTING:
296       self->xft_hinting = g_value_get_int (value);
297       settings_update_font_options (self);
298       break;
299
300     case PROP_FONT_HINT_STYLE:
301       g_free (self->xft_hint_style);
302       self->xft_hint_style = g_value_dup_string (value);
303       settings_update_font_options (self);
304       break;
305
306     case PROP_FONT_RGBA:
307       g_free (self->xft_rgba);
308       self->xft_rgba = g_value_dup_string (value);
309       settings_update_font_options (self);
310       break;
311
312     case PROP_LONG_PRESS_DURATION:
313       self->long_press_duration = g_value_get_int (value);
314       break;
315
316     case PROP_FONTCONFIG_TIMESTAMP:
317       settings_update_fontmap (self, g_value_get_uint (value));
318       break;
319
320     case PROP_PASSWORD_HINT_TIME:
321       self->password_hint_time = g_value_get_uint (value);
322       break;
323
324     default:
325       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
326       break;
327     }
328 }
329
330 static void
331 clutter_settings_get_property (GObject    *gobject,
332                                guint       prop_id,
333                                GValue     *value,
334                                GParamSpec *pspec)
335 {
336   ClutterSettings *self = CLUTTER_SETTINGS (gobject);
337
338   switch (prop_id)
339     {
340     case PROP_DOUBLE_CLICK_TIME:
341       g_value_set_int (value, self->double_click_time);
342       break;
343
344     case PROP_DOUBLE_CLICK_DISTANCE:
345       g_value_set_int (value, self->double_click_distance);
346       break;
347
348     case PROP_DND_DRAG_THRESHOLD:
349       g_value_set_int (value, self->dnd_drag_threshold);
350       break;
351
352     case PROP_FONT_NAME:
353       g_value_set_string (value, self->font_name);
354       break;
355
356     case PROP_FONT_ANTIALIAS:
357       g_value_set_int (value, self->xft_antialias);
358       break;
359
360     case PROP_FONT_DPI:
361       g_value_set_int (value, self->resolution * 1024);
362       break;
363
364     case PROP_FONT_HINTING:
365       g_value_set_int (value, self->xft_hinting);
366       break;
367
368     case PROP_FONT_HINT_STYLE:
369       g_value_set_string (value, self->xft_hint_style);
370       break;
371
372     case PROP_FONT_RGBA:
373       g_value_set_string (value, self->xft_rgba);
374       break;
375
376     case PROP_LONG_PRESS_DURATION:
377       g_value_set_int (value, self->long_press_duration);
378       break;
379
380     case PROP_PASSWORD_HINT_TIME:
381       g_value_set_uint (value, self->password_hint_time);
382       break;
383
384     default:
385       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
386       break;
387     }
388 }
389
390 static void
391 clutter_settings_dispatch_properties_changed (GObject     *gobject,
392                                               guint        n_pspecs,
393                                               GParamSpec **pspecs)
394 {
395   ClutterSettings *self = CLUTTER_SETTINGS (gobject);
396   GObjectClass *klass;
397
398   /* chain up to emit ::notify */
399   klass = G_OBJECT_CLASS (clutter_settings_parent_class);
400   klass->dispatch_properties_changed (gobject, n_pspecs, pspecs);
401
402   /* emit settings-changed just once for multiple properties */
403   if (self->backend != NULL)
404     g_signal_emit_by_name (self->backend, "settings-changed");
405 }
406
407 static void
408 clutter_settings_class_init (ClutterSettingsClass *klass)
409 {
410   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
411
412   /**
413    * ClutterSettings:backend:
414    *
415    * A back pointer to the #ClutterBackend
416    *
417    * Since: 1.4
418    *
419    * Deprecated: 1.10
420    */
421   obj_props[PROP_BACKEND] =
422     g_param_spec_object ("backend",
423                          "Backend",
424                          "A pointer to the backend",
425                          CLUTTER_TYPE_BACKEND,
426                          CLUTTER_PARAM_WRITABLE |
427                          G_PARAM_DEPRECATED |
428                          G_PARAM_CONSTRUCT_ONLY);
429
430   /**
431    * ClutterSettings:double-click-time:
432    *
433    * The time, in milliseconds, that should elapse between button-press
434    * events in order to increase the click count by 1.
435    *
436    * Since: 1.4
437    */
438   obj_props[PROP_DOUBLE_CLICK_TIME] =
439     g_param_spec_int ("double-click-time",
440                       P_("Double Click Time"),
441                       P_("The time between clicks necessary to detect a multiple click"),
442                       0, G_MAXINT,
443                       250,
444                       CLUTTER_PARAM_READWRITE);
445
446   /**
447    * ClutterSettings:double-click-distance:
448    *
449    * The maximum distance, in pixels, between button-press events that
450    * determines whether or not to increase the click count by 1.
451    *
452    * Since: 1.4
453    */
454   obj_props[PROP_DOUBLE_CLICK_DISTANCE] =
455     g_param_spec_int ("double-click-distance",
456                       P_("Double Click Distance"),
457                       P_("The distance between clicks necessary to detect a multiple click"),
458                       0, G_MAXINT,
459                       5,
460                       CLUTTER_PARAM_READWRITE);
461
462   /**
463    * ClutterSettings:dnd-drag-threshold:
464    *
465    * The default distance that the cursor of a pointer device
466    * should travel before a drag operation should start.
467    *
468    * Since: 1.8
469    */
470   obj_props[PROP_DND_DRAG_THRESHOLD] =
471     g_param_spec_int ("dnd-drag-threshold",
472                       P_("Drag Threshold"),
473                       P_("The distance the cursor should travel before starting to drag"),
474                       1, G_MAXINT,
475                       8,
476                       CLUTTER_PARAM_READWRITE);
477
478   /**
479    * ClutterSettings:font-name:
480    *
481    * The default font name that should be used by text actors, as
482    * a string that can be passed to pango_font_description_from_string().
483    *
484    * Since: 1.4
485    */
486   obj_props[PROP_FONT_NAME] =
487     g_param_spec_string ("font-name",
488                          P_("Font Name"),
489                          P_("The description of the default font, as one that could be parsed by Pango"),
490                          NULL,
491                          CLUTTER_PARAM_READWRITE);
492
493   /**
494    * ClutterSettings:font-antialias:
495    *
496    * Whether or not to use antialiasing when rendering text; a value
497    * of 1 enables it unconditionally; a value of 0 disables it
498    * unconditionally; and -1 will use the system's default.
499    *
500    * Since: 1.4
501    */
502   obj_props[PROP_FONT_ANTIALIAS] =
503     g_param_spec_int ("font-antialias",
504                       P_("Font Antialias"),
505                       P_("Whether to use antialiasing (1 to enable, 0 to disable, and -1 to use the default)"),
506                       -1, 1,
507                       -1,
508                       CLUTTER_PARAM_READWRITE);
509
510   /**
511    * ClutterSettings:font-dpi:
512    *
513    * The DPI used when rendering text, as a value of 1024 * dots/inch.
514    *
515    * If set to -1, the system's default will be used instead
516    *
517    * Since: 1.4
518    */
519   obj_props[PROP_FONT_DPI] =
520     g_param_spec_int ("font-dpi",
521                       P_("Font DPI"),
522                       P_("The resolution of the font, in 1024 * dots/inch, or -1 to use the default"),
523                       -1, 1024 * 1024,
524                       -1,
525                       CLUTTER_PARAM_READWRITE);
526
527   /**
528    * ClutterSettings:font-hinting:
529    *
530    * Whether or not to use hinting when rendering text; a value of 1
531    * unconditionally enables it; a value of 0 unconditionally disables
532    * it; and a value of -1 will use the system's default.
533    *
534    * Since: 1.4
535    */
536   obj_props[PROP_FONT_HINTING] =
537     g_param_spec_int ("font-hinting",
538                       P_("Font Hinting"),
539                       P_("Whether to use hinting (1 to enable, 0 to disable and -1 to use the default)"),
540                       -1, 1,
541                       -1,
542                       CLUTTER_PARAM_READWRITE);
543
544   /**
545    * ClutterSettings:font-hint-style:
546    *
547    * The style of the hinting used when rendering text. Valid values
548    * are:
549    * <itemizedlist>
550    *   <listitem><simpara>hintnone</simpara></listitem>
551    *   <listitem><simpara>hintslight</simpara></listitem>
552    *   <listitem><simpara>hintmedium</simpara></listitem>
553    *   <listitem><simpara>hintfull</simpara></listitem>
554    * </itemizedlist>
555    *
556    * Since: 1.4
557    */
558   obj_props[PROP_FONT_HINT_STYLE] =
559     g_param_spec_string ("font-hint-style",
560                          P_("Font Hint Style"),
561                          P_("The style of hinting (hintnone, hintslight, hintmedium, hintfull)"),
562                          NULL,
563                          CLUTTER_PARAM_READWRITE);
564
565   /**
566    * ClutterSettings:font-subpixel-order:
567    *
568    * The type of sub-pixel antialiasing used when rendering text. Valid
569    * values are:
570    * <itemizedlist>
571    *   <listitem><simpara>none</simpara></listitem>
572    *   <listitem><simpara>rgb</simpara></listitem>
573    *   <listitem><simpara>bgr</simpara></listitem>
574    *   <listitem><simpara>vrgb</simpara></listitem>
575    *   <listitem><simpara>vbgr</simpara></listitem>
576    * </itemizedlist>
577    *
578    * Since: 1.4
579    */
580   obj_props[PROP_FONT_RGBA] =
581     g_param_spec_string ("font-subpixel-order",
582                          P_("Font Subpixel Order"),
583                          P_("The type of subpixel antialiasing (none, rgb, bgr, vrgb, vbgr)"),
584                          NULL,
585                          CLUTTER_PARAM_READWRITE);
586
587   /**
588    * ClutterSettings:long-press-duration:
589    *
590    * Sets the minimum duration for a press to be recognized as a long press
591    * gesture. The duration is expressed in milliseconds.
592    *
593    * See also #ClutterClickAction:long-press-duration.
594    *
595    * Since: 1.8
596    */
597   obj_props[PROP_LONG_PRESS_DURATION] =
598     g_param_spec_int ("long-press-duration",
599                       P_("Long Press Duration"),
600                       P_("The minimum duration for a long press gesture to be recognized"),
601                       0, G_MAXINT,
602                       500,
603                       CLUTTER_PARAM_READWRITE);
604
605   obj_props[PROP_FONTCONFIG_TIMESTAMP] =
606     g_param_spec_uint ("fontconfig-timestamp",
607                        P_("Fontconfig configuration timestamp"),
608                        P_("Timestamp of the current fontconfig configuration"),
609                        0, G_MAXUINT,
610                        0,
611                        CLUTTER_PARAM_WRITABLE);
612
613   /**
614    * ClutterText:password-hint-time:
615    *
616    * How long should Clutter show the last input character in editable
617    * ClutterText actors. The value is in milliseconds. A value of 0
618    * disables showing the password hint. 600 is a good value for
619    * enabling the hint.
620    *
621    * Since: 1.10
622    */
623   obj_props[PROP_PASSWORD_HINT_TIME] =
624     g_param_spec_uint ("password-hint-time",
625                        P_("Password Hint Time"),
626                        P_("How long to show the last input character in hidden entries"),
627                        0, G_MAXUINT,
628                        0,
629                        CLUTTER_PARAM_READWRITE);
630
631   gobject_class->set_property = clutter_settings_set_property;
632   gobject_class->get_property = clutter_settings_get_property;
633   gobject_class->dispatch_properties_changed =
634     clutter_settings_dispatch_properties_changed;
635   gobject_class->finalize = clutter_settings_finalize;
636   g_object_class_install_properties (gobject_class, PROP_LAST, obj_props);
637 }
638
639 static void
640 clutter_settings_init (ClutterSettings *self)
641 {
642   self->resolution = -1.0;
643
644   self->double_click_time = 250;
645   self->double_click_distance = 5;
646
647   self->dnd_drag_threshold = 8;
648
649   self->font_name = g_strdup (DEFAULT_FONT_NAME);
650
651   self->xft_antialias = -1;
652   self->xft_hinting = -1;
653   self->xft_hint_style = NULL;
654   self->xft_rgba = NULL;
655
656   self->long_press_duration = 500;
657 }
658
659 /**
660  * clutter_settings_get_default:
661  *
662  * Retrieves the singleton instance of #ClutterSettings
663  *
664  * Return value: (transfer none): the instance of #ClutterSettings. The
665  *   returned object is owned by Clutter and it should not be unreferenced
666  *   directly
667  *
668  * Since: 1.4
669  */
670 ClutterSettings *
671 clutter_settings_get_default (void)
672 {
673   static ClutterSettings *settings = NULL;
674
675   if (G_UNLIKELY (settings == NULL))
676     settings = g_object_new (CLUTTER_TYPE_SETTINGS, NULL);
677
678   return settings;
679 }
680
681 void
682 _clutter_settings_set_backend (ClutterSettings *settings,
683                                ClutterBackend  *backend)
684 {
685   g_assert (CLUTTER_IS_SETTINGS (settings));
686   g_assert (CLUTTER_IS_BACKEND (backend));
687
688   settings->backend = backend;
689 }
690
691 #define SETTINGS_GROUP  "Settings"
692
693 void
694 _clutter_settings_read_from_key_file (ClutterSettings *settings,
695                                       GKeyFile        *keyfile)
696 {
697   GObjectClass *settings_class;
698   GObject *settings_obj;
699   GParamSpec **pspecs;
700   guint n_pspecs, i;
701
702   if (!g_key_file_has_group (keyfile, SETTINGS_GROUP))
703     return;
704
705   settings_obj = G_OBJECT (settings);
706   settings_class = G_OBJECT_GET_CLASS (settings);
707   pspecs = g_object_class_list_properties (settings_class, &n_pspecs);
708
709   for (i = 0; i < n_pspecs; i++)
710     {
711       GParamSpec *pspec = pspecs[i];
712       const gchar *p_name = pspec->name;
713       GType p_type = G_TYPE_FUNDAMENTAL (pspec->value_type);
714       GValue value = G_VALUE_INIT;
715       GError *key_error = NULL;
716
717       g_value_init (&value, p_type);
718
719       switch (p_type)
720         {
721         case G_TYPE_INT:
722         case G_TYPE_UINT:
723           {
724             gint val;
725
726             val = g_key_file_get_integer (keyfile,
727                                           SETTINGS_GROUP, p_name,
728                                           &key_error);
729             if (p_type == G_TYPE_INT)
730               g_value_set_int (&value, val);
731             else
732               g_value_set_uint (&value, val);
733           }
734           break;
735
736         case G_TYPE_BOOLEAN:
737           {
738             gboolean val;
739
740             val = g_key_file_get_boolean (keyfile,
741                                           SETTINGS_GROUP, p_name,
742                                           &key_error);
743             g_value_set_boolean (&value, val);
744           }
745           break;
746
747         case G_TYPE_FLOAT:
748         case G_TYPE_DOUBLE:
749           {
750             gdouble val;
751
752             val = g_key_file_get_double (keyfile,
753                                          SETTINGS_GROUP, p_name,
754                                          &key_error);
755             if (p_type == G_TYPE_FLOAT)
756               g_value_set_float (&value, val);
757             else
758               g_value_set_double (&value, val);
759           }
760           break;
761
762         case G_TYPE_STRING:
763           {
764             gchar *val;
765
766             val = g_key_file_get_string (keyfile,
767                                          SETTINGS_GROUP, p_name,
768                                          &key_error);
769             g_value_take_string (&value, val);
770           }
771           break;
772         }
773
774       if (key_error != NULL &&
775           key_error->domain != G_KEY_FILE_ERROR &&
776           key_error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND)
777         {
778           g_critical ("Unable to read the value for setting '%s': %s",
779                       p_name,
780                       key_error->message);
781         }
782
783       if (key_error == NULL)
784         g_object_set_property (settings_obj, p_name, &value);
785       else
786         g_error_free (key_error);
787
788       g_value_unset (&value);
789     }
790
791   g_free (pspecs);
792 }