diff options
author | Kjell Ahlstedt <kjellahlstedt@gmail.com> | 2019-06-27 18:25:37 +0200 |
---|---|---|
committer | Kjell Ahlstedt <kjellahlstedt@gmail.com> | 2019-06-27 18:25:37 +0200 |
commit | 29dda74e8fddec63d5d12a16976d82bed5f51105 (patch) | |
tree | e027136f7fb9144f43054a221c0863afb1d5c53f /glib | |
parent | 03b97def4ff512d379db7999828d100016a21529 (diff) | |
download | glibmm-29dda74e8fddec63d5d12a16976d82bed5f51105.tar.gz |
Glib::Property: Update for compatibility with Gtk::Builder
When an object is created by GtkBuilder, the GObject-derived C object is
created and its properties set before there is a C++ wrapper to store
the property values in. Glib::custom_set_property_callback() stores
property values in a data structure reached via a GQuark in the object.
PropertyBase::lookup_property() copies those property values to the
PropertyBase objects when the C++ wrapper is created.
Diffstat (limited to 'glib')
-rw-r--r-- | glib/glibmm/property.cc | 116 | ||||
-rw-r--r-- | glib/glibmm/property.h | 12 |
2 files changed, 96 insertions, 32 deletions
diff --git a/glib/glibmm/property.cc b/glib/glibmm/property.cc index 30de7485..56dad849 100644 --- a/glib/glibmm/property.cc +++ b/glib/glibmm/property.cc @@ -19,6 +19,7 @@ #include <glibmm/object.h> #include <glibmm/class.h> #include <cstddef> +#include <map> // Temporary hack till GLib gets fixed. #undef G_STRLOC @@ -76,19 +77,34 @@ destroy_notify_obj_iface_props(void* data) } } -// The type that holds pointers to the custom properties of custom types. -using custom_properties_type = std::vector<Glib::PropertyBase*>; +struct custom_properties_type +{ + // Pointers to the custom properties of custom types. + std::vector<Glib::PropertyBase*> prop_base_vector; + + // Property values, set by custom_set_property_callback() before a + // Glib::PropertyBase wrapper has been created. E.g. if the containing + // custom GObject has been created by GtkBuilder. + std::map<unsigned int, GValue*> prop_value_map; +}; + // The quark used for storing/getting the custom properties of custom types. static const GQuark custom_properties_quark = g_quark_from_string("gtkmm_CustomObject_custom_properties"); -// Delete the vector of pointers to custom properties when an object of -// a custom type is finalized. -void -destroy_notify_obj_custom_props(void* data) +// Delete the custom properties data when an object of a custom type is finalized. +void destroy_notify_obj_custom_props(void* data) { - // Shallow deletion. The vector does not own the objects pointed to. - delete static_cast<custom_properties_type*>(data); + auto obj_custom_props = static_cast<custom_properties_type*>(data); + // prop_base_vector does not own the objects pointed to. + // prop_value_map owns the objects pointed to. + auto map_end = obj_custom_props->prop_value_map.end(); + for (auto it = obj_custom_props->prop_value_map.begin(); it != map_end; ++it) + { + g_value_unset(it->second); + g_free(it->second); + } + delete obj_custom_props; } custom_properties_type* @@ -139,19 +155,32 @@ custom_get_property_callback( } else { + auto obj_custom_props = get_obj_custom_props(object); + const unsigned index = property_id - iface_props_size - 1; + if (Glib::ObjectBase* const wrapper = Glib::ObjectBase::_get_current_wrapper(object)) { - auto obj_custom_props = - static_cast<custom_properties_type*>(g_object_get_qdata(object, custom_properties_quark)); - const unsigned index = property_id - iface_props_size - 1; - - if (obj_custom_props && index < obj_custom_props->size() && - (*obj_custom_props)[index]->object_ == wrapper && - (*obj_custom_props)[index]->param_spec_ == param_spec) - g_value_copy((*obj_custom_props)[index]->value_.gobj(), value); + if (obj_custom_props && index < obj_custom_props->prop_base_vector.size()) + { + const Glib::PropertyBase* prop_base = (obj_custom_props->prop_base_vector)[index]; + if (prop_base->object_ == wrapper && prop_base->param_spec_ == param_spec) + g_value_copy(prop_base->value_.gobj(), value); + else + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, param_spec); + } else G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, param_spec); } + else + { + // No C++ wrapper exists. Check if there is a value in obj_custom_props->prop_value_map. + auto it = obj_custom_props->prop_value_map.find(index); + if (it != obj_custom_props->prop_value_map.end()) + g_value_copy(it->second, value); + else + // else return the property's default value. + g_value_copy(g_param_spec_get_default_value(param_spec), value); + } } } @@ -164,7 +193,7 @@ custom_set_property_callback( GType custom_type = G_OBJECT_TYPE(object); - Class::iface_properties_type* iface_props = static_cast<Class::iface_properties_type*>( + auto iface_props = static_cast<Class::iface_properties_type*>( g_type_get_qdata(custom_type, Class::iface_properties_quark)); Class::iface_properties_type::size_type iface_props_size = 0; @@ -176,7 +205,7 @@ custom_set_property_callback( { // If the object does not have interface property values, // copy the class's default values to the object. - Class::iface_properties_type* obj_iface_props = static_cast<Class::iface_properties_type*>( + auto obj_iface_props = static_cast<Class::iface_properties_type*>( g_object_get_qdata(object, Class::iface_properties_quark)); if (!obj_iface_props) { @@ -197,22 +226,40 @@ custom_set_property_callback( } else { + auto obj_custom_props = get_obj_custom_props(object); + const unsigned index = property_id - iface_props_size - 1; + if (Glib::ObjectBase* const wrapper = Glib::ObjectBase::_get_current_wrapper(object)) { - auto obj_custom_props = - static_cast<custom_properties_type*>(g_object_get_qdata(object, custom_properties_quark)); - const unsigned index = property_id - iface_props_size - 1; - - if (obj_custom_props && index < obj_custom_props->size() && - (*obj_custom_props)[index]->object_ == wrapper && - (*obj_custom_props)[index]->param_spec_ == param_spec) + if (obj_custom_props && index < obj_custom_props->prop_base_vector.size()) { - g_value_copy(value, (*obj_custom_props)[index]->value_.gobj()); - g_object_notify_by_pspec(object, param_spec); + Glib::PropertyBase* prop_base = (obj_custom_props->prop_base_vector)[index]; + if (prop_base->object_ == wrapper && prop_base->param_spec_ == param_spec) + { + g_value_copy(value, prop_base->value_.gobj()); + g_object_notify_by_pspec(object, param_spec); + } + else + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, param_spec); } else G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, param_spec); } + else + { + // No C++ wrapper exists. Store the value in obj_custom_props->prop_value_map. + auto it = obj_custom_props->prop_value_map.find(index); + if (it != obj_custom_props->prop_value_map.end()) + g_value_copy(value, it->second); + else + { + GValue* g_value = g_new0(GValue, 1); + g_value_init(g_value, G_VALUE_TYPE(value)); + g_value_copy(value, g_value); + obj_custom_props->prop_value_map[index] = g_value; + } + g_object_notify_by_pspec(object, param_spec); + } } } @@ -244,7 +291,16 @@ PropertyBase::lookup_property(const Glib::ustring& name) g_assert(G_PARAM_SPEC_VALUE_TYPE(param_spec_) == G_VALUE_TYPE(value_.gobj())); g_param_spec_ref(param_spec_); - get_obj_custom_props(object_->gobj())->emplace_back(this); + auto obj_custom_props = get_obj_custom_props(object_->gobj()); + const unsigned int pos_in_obj_custom_props = obj_custom_props->prop_base_vector.size(); + obj_custom_props->prop_base_vector.emplace_back(this); + + // If a value has been set by a call to custom_set_property_callback() + // before this Glib::PropertyBase wrapper was creared, copy that value + // to value_. + auto it = obj_custom_props->prop_value_map.find(pos_in_obj_custom_props); + if (it != obj_custom_props->prop_value_map.end()) + g_value_copy(it->second, value_.gobj()); } return (param_spec_ != nullptr); @@ -270,8 +326,8 @@ PropertyBase::install_property(GParamSpec* param_spec) auto obj_custom_props = get_obj_custom_props(object_->gobj()); - const unsigned int pos_in_obj_custom_props = obj_custom_props->size(); - obj_custom_props->emplace_back(this); + const unsigned int pos_in_obj_custom_props = obj_custom_props->prop_base_vector.size(); + obj_custom_props->prop_base_vector.emplace_back(this); // We need to offset by 1 as zero is an invalid property id. const unsigned int property_id = pos_in_obj_custom_props + iface_props_size + 1; diff --git a/glib/glibmm/property.h b/glib/glibmm/property.h index fbd485f7..35e074c8 100644 --- a/glib/glibmm/property.h +++ b/glib/glibmm/property.h @@ -129,7 +129,7 @@ private: * * The default value and the minimum and maximum bounds (depending on the type of the property). * * Flags, defining, among other things, whether the property can be read or written. * - * This Property class currently supports the name, nick name, description default value and flags. + * This %Property class currently supports the name, nick name, description, default value and flags. * The minimum and maximum bounds are set to the full range of the value. * Because of internal implementation, flags shouldn't be set to values: Glib::ParamFlags::STATIC_NAME, * Glib::ParamFlags::STATIC_NICK, Glib::ParamFlags::STATIC_BLURB, Glib::ParamFlags::CONSTRUCT and @@ -146,7 +146,7 @@ private: * declare all properties as direct data members of the type. * * You may register new properties for your class (actually for the underlying GType) - * simply by adding a Property instance as a class member. + * simply by adding a %Property instance as a class member. * However, your constructor must call the Glib::ObjectBase constructor with a new GType name, * in order to register a new GType. * @@ -175,6 +175,14 @@ private: * Glib::Property<int> property_myint_; * }; * @endcode + * + * @par %Glib::Property and Gtk::Builder + * The new GType is registered, and the properties installed in the GType, when + * the first instance of the class is created. When the underlying GObject-derived + * instance is created before the wrapping Glib::Object-derived instance, you may + * have to first create a dummy instance just to register the GType. + * See the description of Gtk::Builder for instructions how to combine %Property + * with Gtk::Builder. */ template <class T> class Property : public PropertyBase |