[glibmm] Custom Interfaces: Implement derived interface properties in present.



commit ce20003fd7ed3d6dd11433388598d6c1b1f41029
Author: José Alburquerque <jaalburqu svn gnome org>
Date:   Mon Apr 22 23:50:27 2013 -0400

    Custom Interfaces: Implement derived interface properties in present.
    
        * glib/glibmm/class.cc (Class::properties_quark): Initialize this
        GQuark which is used to store/get the data used for setting and
        getting the properties of the interfaces that a custom type overrides.
        (Class::interface_finalize_function): Add this function which
        once invoked frees the property data stored as gqata in the GType and
        allocated/appended to in the Glib::Interface constructor below.
        * glib/glibmm/class.h: Declare the interface_finalize_function above.
        Also declare the quark used to store/get the property data and the
        typedef data type of the property data.
    
        * glib/glibmm/interface.cc (Interface_Class::add_interface): Specify a
        custom interface finalize function when adding the interface so that
        the resources allocated for handling the derived interface properties
        can be freed if the type is a custom interface type.
        (Interface::Interface(const Interface_Class&)): Modify the constructor
        so that when dealing with a custom interface type, it gets a list of
        the properties of the interface to be added and overrides these by
        appending approperiate GValues to the data used to handle
        getting/setting properties that is stored as qdata in the GType.  The
        constructor uses g_param_spec_overrided() to override the properties
        of the implemented interface and g_object_install_property() to
        install the properties.
    
        * glib/glibmm/property.cc (PropertyBase::install_property): Rewrite
        this method so that the acquired generated id's of custom implemented
        properties does not collide with the id's of properties of implemented
        interfaces that have been overridden in a custom type.  This is done
        by offsetting the acquired generated id (by addition) with the number
        of already existing properties (the ones that have been overridden).
        (custom_get_property_callback): Rewrite this function (which gets
        properties for custom types) so that if the property id is less than
        or equal to the number of overridden interface properties (which would
        mean that an overridden interface property should be gotten) the
        correct overridden interface property is gotten.  Otherwise, a custom
        property should be retrieved, in which case the id is offset (by
        subtraction) when the PropertyBase is retrieved from the id which
        would ensure getting the correct PropertyBase.
        (custom_set_property_callback): Rewrite this function as the above
        custom_get_property_callback was rewritten.

 glib/glibmm/class.cc     |   23 +++++++++++++-
 glib/glibmm/class.h      |   12 +++++++
 glib/glibmm/interface.cc |   40 +++++++++++++++++++++--
 glib/glibmm/property.cc  |   79 +++++++++++++++++++++++++++++++++++++---------
 4 files changed, 134 insertions(+), 20 deletions(-)
---
diff --git a/glib/glibmm/class.cc b/glib/glibmm/class.cc
index 5cb9130..c31a834 100644
--- a/glib/glibmm/class.cc
+++ b/glib/glibmm/class.cc
@@ -131,6 +131,28 @@ GType Class::clone_custom_type(const char* custom_type_name) const
   return custom_type;
 }
 
+// Initialize the static quark to store/get custom type properties.
+GQuark Class::properties_quark = g_quark_from_string("gtkmm_CustomObject_properties");
+
+// static
+void Class::interface_finalize_function(void* g_iface, void*)
+{
+  const GType gtype = G_TYPE_FROM_CLASS(g_iface);
+
+  // Free the data related to the properties for the custom type, if any.
+  properties_type* props = static_cast<properties_type*>(g_type_get_qdata(gtype, properties_quark));
+
+  if(props)
+  {
+    for(properties_type::size_type i = 0; i < props->size(); i++)
+    {
+      g_value_unset((*props)[i]);
+      g_free((*props)[i]);
+    }
+    delete props;
+  }
+}
+
 // static
 void Class::custom_class_init_function(void* g_class, void* class_data)
 {
@@ -149,4 +171,3 @@ void Class::custom_class_init_function(void* g_class, void* class_data)
 }
 
 } // namespace Glib
-
diff --git a/glib/glibmm/class.h b/glib/glibmm/class.h
index 2e7345d..7092d50 100644
--- a/glib/glibmm/class.h
+++ b/glib/glibmm/class.h
@@ -25,6 +25,7 @@
 #include <glib-object.h>
 #include <glibmmconfig.h> //Include this here so that the /private/*.h classes have access to 
GLIBMM_VFUNCS_ENABLED
 
+#include <vector> //For properties that custom types might override.
 
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
 
@@ -66,8 +67,19 @@ protected:
    */
   void register_derived_type(GType base_type, GTypeModule* module);
 
+protected:
+  static void interface_finalize_function(void* g_iface, void* iface_data);
+
 private:
   static void custom_class_init_function(void* g_class, void* class_data);
+
+public:
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+  // The type that holds the values of the properties of custom types.
+  typedef std::vector<GValue*> properties_type;
+  // The quark used for storing/getting the properties of custom types.
+  static GQuark properties_quark;
+#endif
 };
 
 inline
diff --git a/glib/glibmm/interface.cc b/glib/glibmm/interface.cc
index d284b02..d378cbe 100644
--- a/glib/glibmm/interface.cc
+++ b/glib/glibmm/interface.cc
@@ -19,6 +19,7 @@
  */
 
 #include <glibmm/interface.h>
+#include <glibmm/class.h>
 #include <glibmm/private/interface_p.h>
 
 
@@ -35,7 +36,7 @@ void Interface_Class::add_interface(GType instance_type) const
     const GInterfaceInfo interface_info =
     {
       class_init_func_,
-      0, // interface_finalize
+      &Class::interface_finalize_function, // interface_finalize
       0, // interface_data
     };
 
@@ -58,11 +59,42 @@ Interface::Interface(const Interface_Class& interface_class)
 
   if(custom_type_name_ && !is_anonymous_custom_())
   {
-    void *const instance_class = G_OBJECT_GET_CLASS(gobject_);
+    GObjectClass *const instance_class = G_OBJECT_GET_CLASS(gobject_);
+    const GType iface_type = interface_class.get_type();
 
-    if(!g_type_interface_peek(instance_class, interface_class.get_type()))
+    if(!g_type_interface_peek(instance_class, iface_type))
     {
-      interface_class.add_interface(G_OBJECT_CLASS_TYPE(instance_class));
+      void* const g_iface = g_type_default_interface_ref(iface_type);
+
+      const GType custom_type = G_OBJECT_CLASS_TYPE(instance_class);
+      Class::properties_type* props = static_cast<Class::properties_type*>(g_type_get_qdata(custom_type, 
Class::properties_quark));
+
+      if(!props)
+      {
+        props = new Class::properties_type();
+        g_type_set_qdata(custom_type, Class::properties_quark, props);
+      }
+
+      const guint n_existing_props = props->size();
+
+      guint n_iface_props = 0;
+      GParamSpec** iface_props = g_object_interface_list_properties(g_iface, &n_iface_props);
+
+      for(guint p = 0; p < n_iface_props; p++)
+      {
+        GValue* g_value = g_new0(GValue, 1);
+        g_value_init(g_value, iface_props[p]->value_type);
+        props->push_back(g_value);
+
+        const gchar* prop_name = g_param_spec_get_name(iface_props[p]);
+        GParamSpec* new_spec = g_param_spec_override(prop_name, iface_props[p]);
+        g_object_class_install_property(instance_class, p + 1 + n_existing_props, new_spec);
+      }
+
+      interface_class.add_interface(custom_type);
+
+      g_type_default_interface_unref(g_iface);
+      g_free(iface_props);
     }
   }
 }
diff --git a/glib/glibmm/property.cc b/glib/glibmm/property.cc
index 3b73b6b..0ae0345 100644
--- a/glib/glibmm/property.cc
+++ b/glib/glibmm/property.cc
@@ -22,6 +22,7 @@
 
 
 #include <glibmm/object.h>
+#include <glibmm/class.h>
 #include <cstddef>
 
 // Temporary hack till GLib gets fixed.
@@ -106,31 +107,68 @@ namespace Glib
 void custom_get_property_callback(GObject* object, unsigned int property_id,
                                   GValue* value, GParamSpec* param_spec)
 {
-  if(Glib::ObjectBase *const wrapper = Glib::ObjectBase::_get_current_wrapper(object))
+  // If the id is zero there is no property to get.
+  g_return_if_fail(property_id != 0);
+
+  GType custom_type = G_OBJECT_TYPE(object);
+
+  Class::properties_type* props = static_cast<Class::properties_type*>(g_type_get_qdata(custom_type, 
Class::properties_quark));
+  Class::properties_type::size_type props_size = 0;
+
+  if(props) props_size = props->size();
+
+  if(property_id <= props_size)
   {
-    PropertyBase& property = property_from_id(*wrapper, property_id);
+    g_value_copy((*props)[property_id - 1], value);
+  }
+  else
+  {
+    if(Glib::ObjectBase *const wrapper = Glib::ObjectBase::_get_current_wrapper(object))
+    {
+      PropertyBase& property =
+        property_from_id(*wrapper, property_id - props_size);
 
-    if((property.object_ == wrapper) && (property.param_spec_ == param_spec))
-      g_value_copy(property.value_.gobj(), value);
-    else
-      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, param_spec);
+      if((property.object_ == wrapper) && (property.param_spec_ == param_spec))
+        g_value_copy(property.value_.gobj(), value);
+      else
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, param_spec);
+    }
   }
 }
 
 void custom_set_property_callback(GObject* object, unsigned int property_id,
                                   const GValue* value, GParamSpec* param_spec)
 {
-  if(Glib::ObjectBase *const wrapper = Glib::ObjectBase::_get_current_wrapper(object))
-  {
-    PropertyBase& property = property_from_id(*wrapper, property_id);
+  // If the id is zero there is no property to get.
+  g_return_if_fail(property_id != 0);
 
-    if((property.object_ == wrapper) && (property.param_spec_ == param_spec))
+  GType custom_type = G_OBJECT_TYPE(object);
+
+  Class::properties_type* props = static_cast<Class::properties_type*>(g_type_get_qdata(custom_type, 
Class::properties_quark));
+  Class::properties_type::size_type props_size = 0;
+
+  if(props) props_size = props->size();
+
+  if(property_id <= props_size)
+  {
+    g_value_copy(value, (*props)[property_id - 1]);
+    g_object_notify(object, g_param_spec_get_name(param_spec));
+  }
+  else
+  {
+    if(Glib::ObjectBase *const wrapper = Glib::ObjectBase::_get_current_wrapper(object))
     {
-      g_value_copy(value, property.value_.gobj());
-      g_object_notify(object, g_param_spec_get_name(param_spec));
+      PropertyBase& property =
+        property_from_id(*wrapper, property_id - props_size);
+
+      if((property.object_ == wrapper) && (property.param_spec_ == param_spec))
+      {
+        g_value_copy(value, property.value_.gobj());
+        g_object_notify(object, g_param_spec_get_name(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);
   }
 }
 
@@ -171,7 +209,18 @@ void PropertyBase::install_property(GParamSpec* param_spec)
 {
   g_return_if_fail(param_spec != 0);
 
-  const unsigned int property_id = property_to_id(*object_, *this);
+  // Ensure that there would not be id clashes with possible existing
+  // properties overridden from implemented interfaces if dealing with a custom
+  // type by offsetting the generated id with the number of already existing
+  // properties.
+
+  GType gtype = G_OBJECT_TYPE(object_->gobj());
+  Class::properties_type* props = static_cast<Class::properties_type*>(g_type_get_qdata(gtype, 
Class::properties_quark));
+
+  Class::properties_type::size_type props_size = 0;
+  if(props) props_size = props->size();
+
+  const unsigned int property_id = property_to_id(*object_, *this) + props_size;
 
   g_object_class_install_property(G_OBJECT_GET_CLASS(object_->gobj()), property_id, param_spec);
 


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