[clutter] Add a configuration file for ClutterSettings



commit f5eee5aec7a87a3c8a1f2e658231eca4b04561dd
Author: Emmanuele Bassi <ebassi linux intel com>
Date:   Tue Oct 11 14:42:31 2011 +0100

    Add a configuration file for ClutterSettings
    
    ClutterSettings should be able to load its initial state by using
    configuration files in SYSCONFDIR and XDG_CONFIG_HOME. This allows
    Clutter to have a system (and user) configuration on platforms that
    do not have XSETTINGS bridges.

 clutter/Makefile.am                |    2 +
 clutter/clutter-main.c             |   42 +++++++++
 clutter/clutter-settings-private.h |   16 ++++
 clutter/clutter-settings.c         |  164 +++++++++++++++++++++++++++++++++---
 4 files changed, 213 insertions(+), 11 deletions(-)
---
diff --git a/clutter/Makefile.am b/clutter/Makefile.am
index d9b81a8..688617d 100644
--- a/clutter/Makefile.am
+++ b/clutter/Makefile.am
@@ -27,6 +27,7 @@ AM_CPPFLAGS = \
 	-DCLUTTER_LIBDIR=\""$(libdir)"\"	\
 	-DCLUTTER_DATADIR=\""$(datadir)"\"	\
 	-DCLUTTER_LOCALEDIR=\""$(localedir)"\"	\
+	-DCLUTTER_SYSCONFDIR=\""$(sysconfdir)"\" \
 	-DCLUTTER_COMPILATION=1			\
 	-DCOGL_ENABLE_EXPERIMENTAL_API		\
 	-DG_LOG_DOMAIN=\"Clutter\" 		\
@@ -240,6 +241,7 @@ source_h_priv = \
 	$(srcdir)/clutter-private.h 			\
 	$(srcdir)/clutter-profile.h			\
 	$(srcdir)/clutter-script-private.h		\
+	$(srcdir)/clutter-settings-private.h		\
 	$(srcdir)/clutter-stage-manager-private.h	\
 	$(srcdir)/clutter-stage-private.h		\
 	$(srcdir)/clutter-timeout-interval.h    	\
diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c
index 4f0a6c8..8992909 100644
--- a/clutter/clutter-main.c
+++ b/clutter/clutter-main.c
@@ -99,6 +99,7 @@
 #include "clutter-master-clock.h"
 #include "clutter-private.h"
 #include "clutter-profile.h"
+#include "clutter-settings-private.h"
 #include "clutter-stage-manager.h"
 #include "clutter-stage-private.h"
 #include "clutter-version.h" 	/* For flavour define */
@@ -215,6 +216,35 @@ clutter_threads_init_default (void)
     clutter_threads_unlock = clutter_threads_impl_unlock;
 }
 
+#define N_CONF_DIRS     2
+
+static void
+clutter_config_read (void)
+{
+  ClutterSettings *settings;
+  gchar *config_path;
+
+  settings = clutter_settings_get_default ();
+
+  config_path = g_build_filename (CLUTTER_SYSCONFDIR,
+                                  "clutter-1.0",
+                                  "settings.ini",
+                                  NULL);
+  if (g_file_test (config_path, G_FILE_TEST_EXISTS))
+    _clutter_settings_read_from_file (settings, config_path);
+
+  g_free (config_path);
+
+  config_path = g_build_filename (g_get_user_config_dir (),
+                                  "clutter-1.0",
+                                  "settings.ini",
+                                  NULL);
+  if (g_file_test (config_path, G_FILE_TEST_EXISTS))
+    _clutter_settings_read_from_file (settings, config_path);
+
+  g_free (config_path);
+}
+
 /**
  * clutter_get_show_fps:
  *
@@ -1105,6 +1135,12 @@ clutter_context_get_default_unlocked (void)
       ctx->is_initialized = FALSE;
       ctx->motion_events_per_actor = TRUE;
 
+      /* create the default settings object, and store a back pointer to
+       * the backend singleton
+       */
+      ctx->settings = clutter_settings_get_default ();
+      _clutter_settings_set_backend (ctx->settings, ctx->backend);
+
 #ifdef CLUTTER_ENABLE_DEBUG
       ctx->timer = g_timer_new ();
       g_timer_start (ctx->timer);
@@ -1370,6 +1406,12 @@ pre_parse_hook (GOptionContext  *context,
     g_warning ("Locale not supported by C library.\n"
                "Using the fallback 'C' locale.");
 
+  /* read the configuration file, if it exists; the configuration file
+   * determines the initial state of the settings, so that command line
+   * arguments can override them.
+   */
+  clutter_config_read ();
+
   clutter_context = _clutter_context_get_default ();
 
   clutter_context->id_pool = _clutter_id_pool_new (256);
diff --git a/clutter/clutter-settings-private.h b/clutter/clutter-settings-private.h
new file mode 100644
index 0000000..112f542
--- /dev/null
+++ b/clutter/clutter-settings-private.h
@@ -0,0 +1,16 @@
+#ifndef __CLUTTER_SETTINGS_PRIVATE_H__
+#define __CLUTTER_SETTINGS_PRIVATE_H__
+
+#include <clutter/clutter-backend-private.h>
+#include <clutter/clutter-settings.h>
+
+G_BEGIN_DECLS
+
+void    _clutter_settings_set_backend           (ClutterSettings *settings,
+                                                 ClutterBackend  *backend);
+void    _clutter_settings_read_from_file        (ClutterSettings *settings,
+                                                 const gchar     *file);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_SETTINGS_PRIVATE_H__ */
diff --git a/clutter/clutter-settings.c b/clutter/clutter-settings.c
index 0bc43d9..ffbc605 100644
--- a/clutter/clutter-settings.c
+++ b/clutter/clutter-settings.c
@@ -118,6 +118,9 @@ settings_update_font_options (ClutterSettings *self)
   cairo_subpixel_order_t subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT;
   cairo_font_options_t *options;
 
+  if (self->backend == NULL)
+    return;
+
   options = cairo_font_options_create ();
 
   cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON);
@@ -187,7 +190,8 @@ settings_update_font_name (ClutterSettings *self)
 {
   CLUTTER_NOTE (BACKEND, "New font-name: %s", self->font_name);
 
-  g_signal_emit_by_name (self->backend, "font-changed");
+  if (self->backend != NULL)
+    g_signal_emit_by_name (self->backend, "font-changed");
 }
 
 static void
@@ -195,13 +199,17 @@ settings_update_resolution (ClutterSettings *self)
 {
   CLUTTER_NOTE (BACKEND, "New resolution: %.2f", self->resolution);
 
-  g_signal_emit_by_name (self->backend, "resolution-changed");
+  if (self->backend != NULL)
+    g_signal_emit_by_name (self->backend, "resolution-changed");
 }
 
 static void
 settings_update_fontmap (ClutterSettings *self,
                          guint            stamp)
 {
+  if (self->backend == NULL)
+    return;
+
 #ifdef HAVE_PANGO_FT2
   CLUTTER_NOTE (BACKEND, "Update fontmaps (stamp: %d)", stamp);
 
@@ -391,7 +399,8 @@ clutter_settings_dispatch_properties_changed (GObject     *gobject,
   klass->dispatch_properties_changed (gobject, n_pspecs, pspecs);
 
   /* emit settings-changed just once for multiple properties */
-  g_signal_emit_by_name (self->backend, "settings-changed");
+  if (self->backend != NULL)
+    g_signal_emit_by_name (self->backend, "settings-changed");
 }
 
 static void
@@ -405,13 +414,17 @@ clutter_settings_class_init (ClutterSettingsClass *klass)
    * A back pointer to the #ClutterBackend
    *
    * Since: 1.4
+   *
+   * Deprecated: 1.10
    */
   obj_props[PROP_BACKEND] =
     g_param_spec_object ("backend",
                          "Backend",
                          "A pointer to the backend",
                          CLUTTER_TYPE_BACKEND,
-                         CLUTTER_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
+                         CLUTTER_PARAM_WRITABLE |
+                         G_PARAM_DEPRECATED |
+                         G_PARAM_CONSTRUCT_ONLY);
 
   /**
    * ClutterSettings:double-click-time:
@@ -656,14 +669,143 @@ clutter_settings_init (ClutterSettings *self)
 ClutterSettings *
 clutter_settings_get_default (void)
 {
-  ClutterMainContext *context = _clutter_context_get_default ();
+  static ClutterSettings *settings = NULL;
+
+  if (G_UNLIKELY (settings == NULL))
+    settings = g_object_new (CLUTTER_TYPE_SETTINGS, NULL);
+
+  return settings;
+}
+
+void
+_clutter_settings_set_backend (ClutterSettings *settings,
+                               ClutterBackend  *backend)
+{
+  g_assert (CLUTTER_IS_SETTINGS (settings));
+  g_assert (CLUTTER_IS_BACKEND (backend));
+
+  settings->backend = backend;
+}
+
+#define SETTINGS_GROUP  "Settings"
+
+void
+_clutter_settings_read_from_file (ClutterSettings *settings,
+                                  const gchar     *file)
+{
+  GObjectClass *settings_class;
+  GObject *settings_obj;
+  GParamSpec **pspecs;
+  GKeyFile *keyfile;
+  GError *error;
+  guint n_pspecs, i;
+
+  error = NULL;
+  keyfile = g_key_file_new ();
+  g_key_file_load_from_file (keyfile, file, G_KEY_FILE_NONE, &error);
+  if (error != NULL)
+    {
+      g_critical ("Unable to read configuration from '%s': %s",
+                  file,
+                  error->message);
+      g_error_free (error);
+      goto out;
+    }
 
-  if (G_LIKELY (context->settings != NULL))
-    return context->settings;
+  if (!g_key_file_has_group (keyfile, SETTINGS_GROUP))
+    goto out;
+
+  settings_obj = G_OBJECT (settings);
+  settings_class = G_OBJECT_GET_CLASS (settings);
+  pspecs = g_object_class_list_properties (settings_class, &n_pspecs);
+
+  CLUTTER_NOTE (BACKEND, "Reading settings from '%s'", file);
+
+  for (i = 0; i < n_pspecs; i++)
+    {
+      GParamSpec *pspec = pspecs[i];
+      const gchar *p_name = pspec->name;
+      GType p_type = G_TYPE_FUNDAMENTAL (pspec->value_type);
+      GValue value = G_VALUE_INIT;
+      GError *key_error = NULL;
+
+      g_value_init (&value, p_type);
+
+      switch (p_type)
+        {
+        case G_TYPE_INT:
+        case G_TYPE_UINT:
+          {
+            gint val;
+
+            val = g_key_file_get_integer (keyfile,
+                                          SETTINGS_GROUP, p_name,
+                                          &key_error);
+            if (p_type == G_TYPE_INT)
+              g_value_set_int (&value, val);
+            else
+              g_value_set_uint (&value, val);
+          }
+          break;
+
+        case G_TYPE_BOOLEAN:
+          {
+            gboolean val;
+
+            val = g_key_file_get_boolean (keyfile,
+                                          SETTINGS_GROUP, p_name,
+                                          &key_error);
+            g_value_set_boolean (&value, val);
+          }
+          break;
+
+        case G_TYPE_FLOAT:
+        case G_TYPE_DOUBLE:
+          {
+            gdouble val;
+
+            val = g_key_file_get_double (keyfile,
+                                         SETTINGS_GROUP, p_name,
+                                         &key_error);
+            if (p_type == G_TYPE_FLOAT)
+              g_value_set_float (&value, val);
+            else
+              g_value_set_double (&value, val);
+          }
+          break;
+
+        case G_TYPE_STRING:
+          {
+            const gchar *val;
+
+            val = g_key_file_get_string (keyfile,
+                                         SETTINGS_GROUP, p_name,
+                                         &key_error);
+            g_value_set_string (&value, val);
+          }
+          break;
+        }
+
+      if (key_error != NULL &&
+          key_error->domain != G_KEY_FILE_ERROR &&
+          key_error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND)
+        {
+          g_critical ("Unable to read the value for setting '%s' in '%s': %s",
+                      p_name,
+                      file,
+                      key_error->message);
+        }
+
+      if (key_error == NULL)
+        g_object_set_property (settings_obj, p_name, &value);
+      else
+        g_error_free (key_error);
+
+      g_value_unset (&value);
+    }
 
-  context->settings = g_object_new (CLUTTER_TYPE_SETTINGS,
-                                    "backend", context->backend,
-                                    NULL);
+  g_free (pspecs);
 
-  return context->settings;
+out:
+  g_key_file_free (keyfile);
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]