/* Copyright (C) 2010 Jonathon Jongsma * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ _CONFIGINCLUDE(giommconfig.h) #include #include #include _DEFS(giomm,gio) _PINCLUDE(glibmm/private/object_p.h) namespace Gio { class GIOMM_API SettingsSchema; /** A high-level API for application settings * * The Settings class provides a convenient API for storing and retrieving * application settings. * * @newin{2,28} */ class GIOMM_API Settings : public Glib::Object { _CLASS_GOBJECT(Settings, GSettings, G_SETTINGS, Glib::Object, GObject, , , GIOMM_API) public: _WRAP_ENUM(BindFlags, GSettingsBindFlags, decl_prefix GIOMM_API) protected: _WRAP_CTOR(Settings(const Glib::ustring& schema_id), g_settings_new) _WRAP_CTOR(Settings(const Glib::ustring& schema_id, const Glib::ustring& path), g_settings_new_with_path) //TODO: Requires SettingsBackend: _WRAP_CTOR(Settings(const Glib::ustring& schema_id, const Glib::RefPtr& backend), g_settings_new_with_backend) //TODO: Requires SettingsBackend: _WRAP_CTOR(Settings(const Glib::ustring& schema_id, const Glib::RefPtr& backend, const Glib::ustring& path), g_settings_new_with_backend_and_path) //TODO: Requires SettingsBackend: _WRAP_CTOR(Settings(const Glib::RefPtr& settings_schema, const Glib::RefPtr& backend, const Glib::ustring& path), g_settings_new_full) public: _WRAP_CREATE(const Glib::ustring& schema_id) _WRAP_CREATE(const Glib::ustring& schema_id, const Glib::ustring& path) //TODO: Requires SettingsBackend: _WRAP_CREATE(const Glib::ustring& schema_id, const Glib::RefPtr& backend) //TODO: Requires SettingsBackend: _WRAP_CREATE(const Glib::ustring& schema_id, const Glib::RefPtr& backend, const Glib::ustring& path) //TODO: Requires SettingsBackend: _WRAP_CREATE(const Glib::RefPtr& settings_schema, const Glib::RefPtr& backend, const Glib::ustring& path) //TODO: Rename these to get/set_*_value_variant() and add templated get/set_*_value() methods as elsewhere? _WRAP_METHOD(bool set_value(const Glib::ustring& key, const Glib::VariantBase& value), g_settings_set_value) /** Gets the value that is stored in the settings for a @a key. * * It is a programmer error to give a @a key that isn't contained in the * schema for the settings. * * @param key The key to get the value for. * @param value A Variant of the expected type. * * @newin{2,28} */ void get_value(const Glib::ustring& key, Glib::VariantBase& value) const; _IGNORE(g_settings_get_value) //TODO: We've added a bool return to handle the nullptr return value case, //but maybe other get_value() methods can return nullptrs too. /** Checks the "user value" of a @a key, if there is one. * * The user value of a key is the last value that was set by the user. * * After calling reset() this function should always return * false (assuming something is not wrong with the system * configuration). * * It is possible that get_value() will return a different * value than this method. This can happen in the case that the user * set a value for a key that was subsequently locked down by the system * administrator -- this method will return the user's old value. * * This method may be useful for adding a "reset" option to a UI or * for providing indication that a particular value has been changed. * * It is a programmer error to give a @a key that isn't contained in the * schema for the settings. * * @param key The key to get the user value for. * @param value A Variant of the expected type. * @result true if a user value was found. * * @newin{2,40} */ bool get_user_value(const Glib::ustring& key, Glib::VariantBase& value) const; _IGNORE(g_settings_get_user_value) /** Gets the "default value" of a key. * * This is the value that would be read if reset() were to be * called on the key. * * Note that this may be a different value than returned by * get_default_value() if the system administrator * has provided a default value. * * Comparing the return values of get_default_value() and * value() is not sufficient for determining if a value * has been set because the user may have explicitly set the value to * something that happens to be equal to the default. The difference * here is that if the default changes in the future, the user's key * will still be set. * * This method may be useful for adding an indication to a UI of what * the default value was before the user set it. * * It is a programmer error to give a @a key that isn't contained in the * schema for the settings. * * @param key The key to get the default value for. * @param value A Variant of the expected type. * * @newin{2,40} */ void get_default_value(const Glib::ustring& key, Glib::VariantBase& value) const; _IGNORE(g_settings_get_default_value) _WRAP_METHOD(int get_int(const Glib::ustring& key) const, g_settings_get_int) _WRAP_METHOD(bool set_int(const Glib::ustring& key, int value), g_settings_set_int) _WRAP_METHOD(gint64 get_int64(const Glib::ustring& key) const, g_settings_get_int64) _WRAP_METHOD(bool set_int64(const Glib::ustring& key, gint64 value), g_settings_set_int64) _WRAP_METHOD(guint get_uint(const Glib::ustring& key) const, g_settings_get_uint) _WRAP_METHOD(bool set_uint(const Glib::ustring& key, guint value), g_settings_set_uint) _WRAP_METHOD(guint64 get_uint64(const Glib::ustring& key) const, g_settings_get_uint64) _WRAP_METHOD(bool set_uint64(const Glib::ustring& key, guint64 value), g_settings_set_uint64) _WRAP_METHOD(bool get_boolean(const Glib::ustring& key) const, g_settings_get_boolean) _WRAP_METHOD(bool set_boolean(const Glib::ustring& key, bool value), g_settings_set_boolean) _WRAP_METHOD(Glib::ustring get_string(const Glib::ustring& key) const, g_settings_get_string) _WRAP_METHOD(bool set_string(const Glib::ustring& key, const Glib::ustring& value), g_settings_set_string) _WRAP_METHOD(double get_double(const Glib::ustring& key) const, g_settings_get_double) _WRAP_METHOD(bool set_double(const Glib::ustring& key, double value), g_settings_set_double) #m4 _CONVERSION(`gchar**',`std::vector',`Glib::ArrayHandler::array_to_vector($3, Glib::OWNERSHIP_DEEP)') _WRAP_METHOD(std::vector get_string_array(const Glib::ustring& key) const, g_settings_get_strv) _WRAP_METHOD(bool set_string_array(const Glib::ustring& key, const std::vector& value), g_settings_set_strv) _WRAP_METHOD(int get_enum(const Glib::ustring& key) const, g_settings_get_enum) _WRAP_METHOD(bool set_enum(const Glib::ustring& key, int value), g_settings_set_enum) _WRAP_METHOD(guint get_flags(const Glib::ustring& key) const, g_settings_get_flags) _WRAP_METHOD(bool set_flags(const Glib::ustring& key, guint value), g_settings_set_flags) // Ignore varargs functions. _IGNORE(g_settings_get, g_settings_set) _WRAP_METHOD(Glib::RefPtr get_child(const Glib::ustring& name), g_settings_get_child) _WRAP_METHOD(Glib::RefPtr get_child(const Glib::ustring& name) const, g_settings_get_child, constversion) _WRAP_METHOD(bool is_writable(const Glib::ustring& name) const, g_settings_is_writable) _WRAP_METHOD(void delay(), g_settings_delay) _WRAP_METHOD(void apply(), g_settings_apply) _WRAP_METHOD(void revert(), g_settings_revert) _WRAP_METHOD(bool get_has_unapplied() const, g_settings_get_has_unapplied) _WRAP_METHOD(void reset(const Glib::ustring& key), g_settings_reset) #m4 _CONVERSION(`gchar**',`std::vector',`Glib::ArrayHandler::array_to_vector($3, Glib::OWNERSHIP_DEEP)') _WRAP_METHOD(std::vector list_children() const, g_settings_list_children) _IGNORE(g_settings_list_keys) _IGNORE(g_settings_get_range, g_settings_list_relocatable_schemas) dnl// deprecated _IGNORE(g_settings_range_check) #m4 _CONVERSION(`Glib::ObjectBase*',`gpointer',(gpointer)$3->gobj()) _WRAP_METHOD(void bind(const Glib::ustring& key, Glib::ObjectBase* object, const Glib::ustring& property, BindFlags flags = BindFlags::DEFAULT), g_settings_bind) /** Create a binding between the @a key in the @a settings object * and the @a property_proxy. * * The binding uses the default GIO mapping functions to map * between the settings and property values. These functions * handle booleans, numeric types and string types in a * straightforward way. Use g_settings_bind_with_mapping() if * you need a custom mapping, or map between types that are not * supported by the default mapping functions. * * Unless the @a flags include Gio::Settings::BindFlags::NO_SENSITIVITY, this * function also establishes a binding between the writability of * @a key and the "sensitive" property of @a object (if @a object has * a boolean property by that name). See bind_writable() * for more details about writable bindings. * * Note that the lifecycle of the binding is tied to @a object, * and that you can have only one binding per object property. * If you bind the same property twice on the same object, the second * binding overrides the first one. * * @param key The key to bind. * @param property_proxy The property to bind. * @param flags Flags for the binding. */ void bind(const Glib::ustring& key, const Glib::PropertyProxy_Base& property_proxy, BindFlags flags = BindFlags::DEFAULT); /** A slot to be called to map values in a binding. * * For instance: * @code * std::optional map_ustring_to_int(const Glib::ustring& from_string); * @endcode * * @return A value of type T_to if the mapping was successful, * and an empty optional with no value (i.e. std::nullopt) otherwise. */ template using SlotTypedMapping = sigc::slot(const T_from&)>; // Gio::Settings::bind() is similar to Glib::Binding::bind_property(). /** Create a binding between the @a key in the @a settings object * and the property @a property of @a object. * * The binding uses the provided mapping functions to map between * settings and property values. * * Note that the lifecycle of the binding is tied to @a object, * and that you can have only one binding per object property. * If you bind the same property twice on the same object, the second * binding overrides the first one. * * The template parameters T_setting and T_property must be * explicitly specified in each call. The compiler can't deduce them. * For instance: * @code * m_settings->bind("transition", * m_transition, "selected", Gio::Settings::BindFlags::DEFAULT, * sigc::mem_fun(*this, &ExampleAppPrefs::map_from_ustring_to_int), * sigc::mem_fun(*this, &ExampleAppPrefs::map_from_int_to_ustring)); * @endcode * * @newin{2,76} * * @param key The key to bind. * @param object A Glib::ObjectBase. * @param property The name of the property to bind. * @param flags Flags for the binding. * @param slot_get_mapping A function that gets called to convert values from * setting to parameter, or an empty slot to use the default GIO mapping. * @param slot_set_mapping A function that gets called to convert values from * parameter to setting, or an empty slot to use the default GIO mapping. * * @tparam T_setting Type of the setting. Must be a type that can be * stored in a Glib::Variant object. * @tparam T_property Type of the property. Must be a type that can be * stored in a Glib::Value object. */ template void bind(const Glib::ustring& key, Glib::ObjectBase* object, const Glib::ustring& property, BindFlags flags, const SlotTypedMapping& slot_get_mapping, const SlotTypedMapping& slot_set_mapping) { return bind_value(key, object, property, flags, slot_get_mapping.empty() ? SlotGetMapping() : GetMappingProp(slot_get_mapping), slot_set_mapping.empty() ? SlotSetMapping() : SetMappingProp(slot_set_mapping)); } /** Create a binding between the @a key in the @a settings object * and the @a property_proxy. * * The binding uses the provided mapping functions to map between * settings and property values. * * Note that the lifecycle of the binding is tied to @a property_proxy's * object, and that you can have only one binding per object property. * If you bind the same property twice on the same object, the second * binding overrides the first one. * * The template parameters T_setting and T_property must be * explicitly specified in each call. The compiler can't deduce them. * For instance: * @code * m_settings->bind("transition", * m_transition->property_selected(), Gio::Settings::BindFlags::DEFAULT, * sigc::mem_fun(*this, &ExampleAppPrefs::map_from_ustring_to_int), * sigc::mem_fun(*this, &ExampleAppPrefs::map_from_int_to_ustring)); * @endcode * * @newin{2,76} * * @param key The key to bind. * @param property_proxy The property to bind. * @param flags Flags for the binding. * @param slot_get_mapping A function that gets called to convert values from * setting to parameter, or an empty slot to use the default GIO mapping. * @param slot_set_mapping A function that gets called to convert values from * parameter to setting, or an empty slot to use the default GIO mapping. * * @tparam T_setting Type of the setting. Must be a type that can be * stored in a Glib::Variant object. * @tparam T_property Type of the property. Must be a type that can be * stored in a Glib::Value object. */ template void bind(const Glib::ustring& key, const Glib::PropertyProxy_Base& property_proxy, BindFlags flags, const SlotTypedMapping& slot_get_mapping, const SlotTypedMapping& slot_set_mapping) { bind(key, property_proxy.get_object(), property_proxy.get_name(), flags, slot_get_mapping, slot_set_mapping); } _IGNORE(g_settings_bind_with_mapping) _WRAP_METHOD(void bind_writable(const Glib::ustring& key, Glib::ObjectBase* object, const Glib::ustring& property, bool inverted=false), g_settings_bind_writable) /** Create a binding between the writability of @a key in the * @a settings object and the @a property_proxy. * * The property must be boolean; "sensitive" or "visible" * properties of widgets are the most likely candidates. * * Writable bindings are always uni-directional; changes of the * writability of the setting will be propagated to the object * property, not the other way. * * When the @a inverted argument is true, the binding inverts the * value as it passes from the setting to the object, i.e. the property * will be set to true if the key is not writable. * * Note that the lifecycle of the binding is tied to @a object, * and that you can have only one binding per object property. * If you bind the same property twice on the same object, the second * binding overrides the first one. * * @param key The key to bind. * @param property_proxy The boolean property to bind. * @param inverted Whether to 'invert' the value. */ void bind_writable(const Glib::ustring& key, const Glib::PropertyProxy_Base& property_proxy, bool inverted=false); _WRAP_METHOD(static void unbind(Glib::ObjectBase* object, const Glib::ustring& property), g_settings_unbind, newin "2,76") /** Removes an existing binding for @a property_proxy. * * Note that bindings are automatically removed when the * object is finalized, so it is rarely necessary to call this * function. * * @newin{2,76} * * @param property_proxy The property whose binding is removed. */ static void unbind(const Glib::PropertyProxy_Base& property_proxy); _WRAP_METHOD(Glib::RefPtr create_action(const Glib::ustring& key), g_settings_create_action) //TODO?: _WRAP_PROPERTY("backend", Glib::RefPtr) _WRAP_PROPERTY("delay-apply", bool) _WRAP_PROPERTY("has-unapplied", bool) _WRAP_PROPERTY("path", std::string) _IGNORE_PROPERTY("schema") _WRAP_PROPERTY("schema-id", Glib::ustring) _WRAP_PROPERTY("settings-schema", Glib::RefPtr, newin "2,58") //TODO?: _WRAP_SIGNAL(bool change_event(const std::vector& keys, int n_keys), "change-event") #m4 _CONVERSION(`const char*',`const Glib::ustring&',__GCHARP_TO_USTRING) _WRAP_SIGNAL(void changed(const Glib::ustring& key), "changed", detail_name key) _WRAP_SIGNAL(bool writable_change_event(GQuark key), "writable-change-event") _WRAP_SIGNAL(void writable_changed(const Glib::ustring& key), writable_changed, detail_name key) #ifndef DOXYGEN_SHOULD_SKIP_THIS // SlotGetMapping and SlotSetMapping must be public. They are used in // the anonymous namespace in settings.ccg. /* A slot to be called to map values in a binding created by bind_value(). * * For instance: * @code * bool map_from_setting_to_property(GValue* to_value, GVariant* from_variant); * @endcode * * @return true if the mapping was successful, and false otherwise. */ using SlotGetMapping = sigc::slot; /* A slot to be called to map values in a binding created by bind_value(). * * For instance: * @code * GVariant* map_from_property_to_setting( * const GValue* from_value, const GVariantType* expected_type); * @endcode * * @return A new GVariant if the mapping was successful, * and nullptr otherwise. */ using SlotSetMapping = sigc::slot; #endif // DOXYGEN_SHOULD_SKIP_THIS private: void bind_value(const Glib::ustring& key, Glib::ObjectBase* object, const Glib::ustring& property, BindFlags flags, const SlotGetMapping& get_mapping, const SlotSetMapping& set_mapping); // The functor GetMappingProp can be implicitly converted to a SlotGetMapping // and used in a call to bind_value(). template class GetMappingProp { public: explicit GetMappingProp(const SlotTypedMapping& slot) : typed_mapping(slot) {} bool operator()(GValue* to_value, GVariant* from_variant) { Glib::Variant from_glib_variant(from_variant, true); const auto to = typed_mapping(from_glib_variant.get()); if (!to.has_value()) return false; Glib::Value to_glib_value; to_glib_value.init(to_value); to_glib_value.set(*to); g_value_copy(to_glib_value.gobj(), to_value); return true; } private: SlotTypedMapping typed_mapping; }; // Settings::GetMappingProp // The functor SetMappingProp can be implicitly converted to a SlotGetMapping // and used in a call to bind_value(). template class SetMappingProp { public: explicit SetMappingProp(const SlotTypedMapping& slot) : typed_mapping(slot) {} GVariant* operator()(const GValue* from_value, const GVariantType* /* expected_type */) { Glib::Value from_glib_value; from_glib_value.init(from_value); const auto to = typed_mapping(from_glib_value.get()); if (!to.has_value()) return nullptr; auto to_glib_variant = Glib::Variant::create(*to); return to_glib_variant.gobj_copy(); } private: SlotTypedMapping typed_mapping; }; // Settings::SetMappingProp }; // Settings } // namespace Gio