From 1d98d18f64edddddea314630e9830a56082c2639 Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Thu, 19 Jan 2012 09:40:24 -0500 Subject: [PATCH] add a way to create a GAction from GSettings g_settings_create_action() will create a GAction for the named key, allowing it to be added to the action group of the application (so that the setting can be directly manipulated from menus, for example). https://bugzilla.gnome.org/show_bug.cgi?id=668279 --- docs/reference/gio/gio-sections.txt | 3 + gio/gio.symbols | 1 + gio/gsettings.c | 262 ++++++++++++++++++++++++++++++++++++ gio/gsettings.h | 3 + 4 files changed, 269 insertions(+) diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt index 09b5404..9d135e6 100644 --- a/docs/reference/gio/gio-sections.txt +++ b/docs/reference/gio/gio-sections.txt @@ -2354,6 +2354,9 @@ g_settings_unbind GSettingsBindSetMapping GSettingsBindGetMapping + +g_settings_create_action + GSettingsClass G_IS_SETTINGS diff --git a/gio/gio.symbols b/gio/gio.symbols index 34b6436..2b51d69 100644 --- a/gio/gio.symbols +++ b/gio/gio.symbols @@ -1140,6 +1140,7 @@ g_settings_apply g_settings_bind g_settings_bind_writable g_settings_bind_with_mapping +g_settings_create_action g_settings_delay g_settings_get g_settings_get_child diff --git a/gio/gsettings.c b/gio/gsettings.c index 5898fdd..95f0489 100644 --- a/gio/gsettings.c +++ b/gio/gsettings.c @@ -31,6 +31,7 @@ #include "gsettingsbackendinternal.h" #include "gsettings-mapping.h" #include "gsettingsschema-internal.h" +#include "gaction.h" #include "strinfo.c" @@ -2841,6 +2842,267 @@ g_settings_unbind (gpointer object, g_object_set_qdata (object, binding_quark, NULL); } +/* GAction {{{1 */ + +typedef struct +{ + GObject parent_instance; + + GSettingsSchemaKey key; + GSettings *settings; +} GSettingsAction; + +typedef GObjectClass GSettingsActionClass; + +static GType g_settings_action_get_type (void); +static void g_settings_action_iface_init (GActionInterface *iface); +G_DEFINE_TYPE_WITH_CODE (GSettingsAction, g_settings_action, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_ACTION, g_settings_action_iface_init)) + +enum +{ + ACTION_PROP_0, + ACTION_PROP_NAME, + ACTION_PROP_PARAMETER_TYPE, + ACTION_PROP_ENABLED, + ACTION_PROP_STATE_TYPE, + ACTION_PROP_STATE +}; + +static const gchar * +g_settings_action_get_name (GAction *action) +{ + GSettingsAction *gsa = (GSettingsAction *) action; + + return gsa->key.name; +} + +static const GVariantType * +g_settings_action_get_parameter_type (GAction *action) +{ + GSettingsAction *gsa = (GSettingsAction *) action; + const GVariantType *type; + + type = g_variant_get_type (gsa->key.default_value); + if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN)) + type = NULL; + + return type; +} + +static gboolean +g_settings_action_get_enabled (GAction *action) +{ + GSettingsAction *gsa = (GSettingsAction *) action; + + return g_settings_is_writable (gsa->settings, gsa->key.name); +} + +static const GVariantType * +g_settings_action_get_state_type (GAction *action) +{ + GSettingsAction *gsa = (GSettingsAction *) action; + + return g_variant_get_type (gsa->key.default_value); +} + +static GVariant * +g_settings_action_get_state (GAction *action) +{ + GSettingsAction *gsa = (GSettingsAction *) action; + GVariant *value; + + value = g_settings_read_from_backend (gsa->settings, &gsa->key); + + if (value == NULL) + value = g_settings_schema_key_get_translated_default (&gsa->key); + + if (value == NULL) + value = g_variant_ref (gsa->key.default_value); + + return value; +} + +static GVariant * +g_settings_action_get_state_hint (GAction *action) +{ + GSettingsAction *gsa = (GSettingsAction *) action; + + /* no point in reimplementing this... */ + return g_settings_get_range (gsa->settings, gsa->key.name); +} + +static void +g_settings_action_change_state (GAction *action, + GVariant *value) +{ + GSettingsAction *gsa = (GSettingsAction *) action; + + if (g_settings_schema_key_type_check (&gsa->key, value) && g_settings_schema_key_range_check (&gsa->key, value)) + g_settings_write_to_backend (gsa->settings, &gsa->key, value); +} + +static void +g_settings_action_activate (GAction *action, + GVariant *parameter) +{ + GSettingsAction *gsa = (GSettingsAction *) action; + + if (g_variant_is_of_type (gsa->key.default_value, G_VARIANT_TYPE_BOOLEAN)) + { + GVariant *old; + + if (parameter != NULL) + return; + + old = g_settings_action_get_state (action); + parameter = g_variant_new_boolean (!g_variant_get_boolean (old)); + g_variant_unref (old); + } + + g_action_change_state (action, parameter); +} + +static void +g_settings_action_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + GAction *action = G_ACTION (object); + + switch (prop_id) + { + case ACTION_PROP_NAME: + g_value_set_string (value, g_settings_action_get_name (action)); + break; + + case ACTION_PROP_PARAMETER_TYPE: + g_value_set_boxed (value, g_settings_action_get_parameter_type (action)); + break; + + case ACTION_PROP_ENABLED: + g_value_set_boolean (value, g_settings_action_get_enabled (action)); + break; + + case ACTION_PROP_STATE_TYPE: + g_value_set_boxed (value, g_settings_action_get_state_type (action)); + break; + + case ACTION_PROP_STATE: + g_value_set_variant (value, g_settings_action_get_state (action)); + break; + + default: + g_assert_not_reached (); + } +} + +static void +g_settings_action_finalize (GObject *object) +{ + GSettingsAction *gsa = (GSettingsAction *) object; + + g_signal_handlers_disconnect_by_data (gsa->settings, gsa); + g_object_unref (gsa->settings); + + G_OBJECT_CLASS (g_settings_action_parent_class) + ->finalize (object); +} + +static void +g_settings_action_init (GSettingsAction *gsa) +{ +} + +static void +g_settings_action_iface_init (GActionInterface *iface) +{ + iface->get_name = g_settings_action_get_name; + iface->get_parameter_type = g_settings_action_get_parameter_type; + iface->get_enabled = g_settings_action_get_enabled; + iface->get_state_type = g_settings_action_get_state_type; + iface->get_state = g_settings_action_get_state; + iface->get_state_hint = g_settings_action_get_state_hint; + iface->change_state = g_settings_action_change_state; + iface->activate = g_settings_action_activate; +} + +static void +g_settings_action_class_init (GSettingsActionClass *class) +{ + class->get_property = g_settings_action_get_property; + class->finalize = g_settings_action_finalize; + + g_object_class_override_property (class, ACTION_PROP_NAME, "name"); + g_object_class_override_property (class, ACTION_PROP_PARAMETER_TYPE, "parameter-type"); + g_object_class_override_property (class, ACTION_PROP_ENABLED, "enabled"); + g_object_class_override_property (class, ACTION_PROP_STATE_TYPE, "state-type"); + g_object_class_override_property (class, ACTION_PROP_STATE, "state"); +} + +static void +g_settings_action_changed (GSettings *settings, + const gchar *key, + gpointer user_data) +{ + g_object_notify (user_data, "state"); +} + +static void +g_settings_action_enabled_changed (GSettings *settings, + const gchar *key, + gpointer user_data) +{ + g_object_notify (user_data, "enabled"); +} + +/** + * g_settings_create_action: + * @settings: a #GSettings + * @key: the name of a key in @settings + * + * Creates a #GAction corresponding to a given #GSettings key. + * + * The action has the same name as the key. + * + * The value of the key becomes the state of the action and the action + * is enabled when the key is writable. Changing the state of the + * action results in the key being written to. Changes to the value or + * writability of the key cause appropriate change notifications to be + * emitted for the action. + * + * For boolean-valued keys, action activations take no parameter and + * result in the toggling of the value. For all other types, + * activations take the new value for the key (which must have the + * correct type). + * + * Returns: (transfer full): a new #GAction + * + * Since: 2.32 + **/ +GAction * +g_settings_create_action (GSettings *settings, + const gchar *key) +{ + GSettingsAction *gsa; + gchar *detailed_signal; + + g_return_val_if_fail (G_IS_SETTINGS (settings), NULL); + g_return_val_if_fail (key != NULL, NULL); + + gsa = g_object_new (g_settings_action_get_type (), NULL); + gsa->settings = g_object_ref (settings); + g_settings_schema_key_init (&gsa->key, settings->priv->schema, key); + + detailed_signal = g_strdup_printf ("changed::%s", key); + g_signal_connect (settings, detailed_signal, G_CALLBACK (g_settings_action_changed), gsa); + g_free (detailed_signal); + detailed_signal = g_strdup_printf ("writable-changed::%s", key); + g_signal_connect (settings, detailed_signal, G_CALLBACK (g_settings_action_enabled_changed), gsa); + g_free (detailed_signal); + + return G_ACTION (gsa); +} + /* Epilogue {{{1 */ /* vim:set foldmethod=marker: */ diff --git a/gio/gsettings.h b/gio/gsettings.h index 80b9990..5c18842 100644 --- a/gio/gsettings.h +++ b/gio/gsettings.h @@ -267,6 +267,9 @@ void g_settings_bind_writable (GSettin void g_settings_unbind (gpointer object, const gchar *property); +GAction * g_settings_create_action (GSettings *settings, + const gchar *key); + gpointer g_settings_get_mapped (GSettings *settings, const gchar *key, GSettingsGetMapping mapping, -- 2.7.4