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.
This commit is contained in:
Emmanuele Bassi 2011-10-11 14:42:31 +01:00
parent 01080dc5f3
commit f5eee5aec7
4 changed files with 214 additions and 12 deletions

View File

@ -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 \

View File

@ -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);

View File

@ -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__ */

View File

@ -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_LIKELY (context->settings != NULL))
return context->settings;
if (G_UNLIKELY (settings == NULL))
settings = g_object_new (CLUTTER_TYPE_SETTINGS, NULL);
context->settings = g_object_new (CLUTTER_TYPE_SETTINGS,
"backend", context->backend,
NULL);
return context->settings;
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_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);
}
g_free (pspecs);
out:
g_key_file_free (keyfile);
}