[glibmm] Add interfaces to custom types before class_init.



commit fc35fb6a7d16631b1d120631c4fc982f14e09a96
Author: Kjell Ahlstedt <kjell ahlstedt bredband net>
Date:   Thu Aug 1 09:33:41 2013 +0200

    Add interfaces to custom types before class_init.
    
    * glib/glibmm/class.[h|cc]: Add a clone_custom_type() overload that takes
    a vector of pointers to Interface_Class instances, so we can call their
    add_interface() functions on the GType just after registering it, but before
    instantiating the first GObject.
    custom_class_init_function(): Override properties of implemented interfaces
    that have not been overridden in a base class.
    * glib/glibmm/interface.cc:
    Interface::Interface(const Interface_Class& interface_class):
    If the GObject has not been instantiated yet, then add interface_class to
    the Class::custom_interface_classes vector.
    * glib/glibmm/objectbase.[h|cc]: Add extra_object_base_data and
    extra_object_base_data_mutex.
    * glib/glibmm/objectbase.cc: ~ObjectBase(): Erase 'this' from
    extra_object_base_data.
    * glib/glibmm/object.cc: Default constructor and
    Object::Object(const Glib::ConstructParams& construct_params): Pass the list
    of Interface_Class pointers to the new Class::clone_custom_type() method
    overload.  Bug #697229.

 glib/glibmm/class.cc      |   63 +++++++++++++++++++++++++++++++++++-
 glib/glibmm/class.h       |   28 ++++++++++++++++
 glib/glibmm/interface.cc  |   78 ++++++++++++++++++++++++---------------------
 glib/glibmm/object.cc     |   32 +++++++++++++++++--
 glib/glibmm/objectbase.cc |   16 +++++++++-
 glib/glibmm/objectbase.h  |   27 +++++++++++++++-
 6 files changed, 202 insertions(+), 42 deletions(-)
---
diff --git a/glib/glibmm/class.cc b/glib/glibmm/class.cc
index 3b6da41..f68138b 100644
--- a/glib/glibmm/class.cc
+++ b/glib/glibmm/class.cc
@@ -22,7 +22,8 @@
 #include <glibmm/property.h>
 #include <glibmm/ustring.h>
 #include <glibmm/utility.h>
-
+#include <glibmm/interface.h>
+#include <glibmm/private/interface_p.h>
 
 namespace Glib
 {
@@ -86,6 +87,12 @@ void Class::register_derived_type(GType base_type, GTypeModule* module)
 
 GType Class::clone_custom_type(const char* custom_type_name) const
 {
+  return clone_custom_type(custom_type_name, interface_class_vector_type());
+}
+
+GType Class::clone_custom_type(const char* custom_type_name,
+  const interface_class_vector_type& interface_classes) const
+{
   std::string full_name ("gtkmm__CustomObject_");
   Glib::append_canonical_typename(full_name, custom_type_name);
 
@@ -126,6 +133,17 @@ GType Class::clone_custom_type(const char* custom_type_name) const
 
     custom_type = g_type_register_static(
         base_type, full_name.c_str(), &derived_info, GTypeFlags(0));
+
+    //Add derived versions of interfaces, if the C type implements any interfaces.
+    //For instance, TreeModel_Class::add_interface().
+    for (interface_class_vector_type::size_type i = 0; i < interface_classes.size(); i++)
+    {
+      const Interface_Class* interface_class = interface_classes[i];
+      if (interface_class)
+      {
+        interface_class->add_interface(custom_type);
+      }
+    }
   }
 
   return custom_type;
@@ -168,6 +186,49 @@ void Class::custom_class_init_function(void* g_class, void* class_data)
   GObjectClass *const gobject_class = static_cast<GObjectClass*>(g_class);
   gobject_class->get_property = &Glib::custom_get_property_callback;
   gobject_class->set_property = &Glib::custom_set_property_callback;
+
+  // Override the properties of implemented interfaces, if any.
+  const GType object_type = G_TYPE_FROM_CLASS(g_class);
+
+  Class::properties_type* props = static_cast<Class::properties_type*>(
+    g_type_get_qdata(object_type, Class::properties_quark));
+  if (!props)
+  {
+    props = new Class::properties_type();
+    g_type_set_qdata(object_type, Class::properties_quark, props);
+  }
+
+  guint n_interfaces = 0;
+  GType* iface_types = g_type_interfaces(object_type, &n_interfaces);
+
+  for (guint i = 0; i < n_interfaces; ++i)
+  {
+    void* const g_iface = g_type_default_interface_ref(iface_types[i]);
+
+    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++)
+    {
+      const gchar* prop_name = g_param_spec_get_name(iface_props[p]);
+
+      // Override only properties which have not been overridden in a base class.
+      if (!g_object_class_find_property(gobject_class, prop_name))
+      {
+        GValue* g_value = g_new0(GValue, 1);
+        g_value_init(g_value, iface_props[p]->value_type);
+        props->push_back(g_value);
+
+        g_object_class_override_property(gobject_class, props->size(), prop_name);
+      }
+    } // end for p
+
+    g_type_default_interface_unref(g_iface);
+    g_free(iface_props);
+
+  } // end for i
+
+  g_free(iface_types);
 }
 
 } // namespace Glib
diff --git a/glib/glibmm/class.h b/glib/glibmm/class.h
index dbd7c58..438c3ca 100644
--- a/glib/glibmm/class.h
+++ b/glib/glibmm/class.h
@@ -31,6 +31,7 @@
 
 namespace Glib
 {
+class Interface_Class;
 
 class Class
 {
@@ -52,8 +53,35 @@ public:
   //static Glib::Object* wrap_new(GObject*);
 
   inline GType get_type() const;
+
+  //TODO: Remove this method at the next ABI/API break.
+  /** Register a static custom GType, derived from the parent of this class's type.
+   * The parent type of the registered custom type is the same C class as the parent
+   * of the get_type() type. If a type with the specified name is already registered,
+   * nothing is done. register_derived_type() must have been called.
+   * @param custom_type_name The name of the registered type is
+   *        "gtkmm__CustomObject_" + canonic(custom_type_name), where canonic()
+   *        replaces special characters with '+'.
+   * @return The registered type.
+   */
   GType clone_custom_type(const char* custom_type_name) const;
 
+  /// The type that holds pointers to the interfaces of custom types.
+  typedef std::vector<const Interface_Class*> interface_class_vector_type;
+
+  /** Register a static custom GType, derived from the parent of this class's type.
+   * The parent type of the registered custom type is the same C class as the parent
+   * of the get_type() type. If a type with the specified name is already registered,
+   * nothing is done. register_derived_type() must have been called.
+   * @param custom_type_name The name of the registered type is
+   *        "gtkmm__CustomObject_" + canonic(custom_type_name), where canonic()
+   *        replaces special characters with '+'.
+   * @param interface_classes Interfaces that the custom type implements.
+   * @return The registered type.
+   */
+  GType clone_custom_type(const char* custom_type_name,
+    const interface_class_vector_type& interface_classes) const;
+
 protected:
   GType           gtype_;
   GClassInitFunc  class_init_func_;
diff --git a/glib/glibmm/interface.cc b/glib/glibmm/interface.cc
index 7183bc7..511f541 100644
--- a/glib/glibmm/interface.cc
+++ b/glib/glibmm/interface.cc
@@ -18,8 +18,8 @@
  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <glibmm/threads.h> // Needed until the next ABI break.
 #include <glibmm/interface.h>
-#include <glibmm/class.h>
 #include <glibmm/private/interface_p.h>
 
 
@@ -52,52 +52,58 @@ Interface::Interface(const Interface_Class& interface_class)
   //gobject_ will be set in the Object constructor.
   //Any instantiable class that derives from Interface should also inherit from Object.
 
-  // If I understand it correctly, gobject_ shouldn't be 0 now.  daniel.
-  // TODO: Make this a g_assert() if the assumption above is correct.
-
-  g_return_if_fail(gobject_ != 0);
-
   if(custom_type_name_ && !is_anonymous_custom_())
   {
-    GObjectClass *const instance_class = G_OBJECT_GET_CLASS(gobject_);
-    const GType iface_type = interface_class.get_type();
-
-    if(!g_type_interface_peek(instance_class, iface_type))
+    if (gobject_)
     {
-      void* const g_iface = g_type_default_interface_ref(iface_type);
+      GObjectClass *const instance_class = G_OBJECT_GET_CLASS(gobject_);
+      const GType iface_type = interface_class.get_type();
 
-      // Override the properties of the derived interface, if any.
+      if(!g_type_interface_peek(instance_class, iface_type))
+      {
+        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));
+        // Override the properties of the derived interface, if any.
 
-      if(!props)
-      {
-        props = new Class::properties_type();
-        g_type_set_qdata(custom_type, Class::properties_quark, props);
-      }
+        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));
 
-      const guint n_existing_props = props->size();
+        if(!props)
+        {
+          props = new Class::properties_type();
+          g_type_set_qdata(custom_type, Class::properties_quark, props);
+        }
 
-      guint n_iface_props = 0;
-      GParamSpec** iface_props = g_object_interface_list_properties(g_iface, &n_iface_props);
+        const guint n_existing_props = props->size();
 
-      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);
-        g_param_value_set_default(iface_props[p], g_value);
-        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);
-      }
+        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);
+          g_param_value_set_default(iface_props[p], g_value);
+          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);
+        interface_class.add_interface(custom_type);
 
-      g_type_default_interface_unref(g_iface);
-      g_free(iface_props);
+        g_type_default_interface_unref(g_iface);
+        g_free(iface_props);
+      }
+    }
+    else // gobject_ == 0
+    {
+      // The GObject is not instantiated yet. Add to the custom_interface_classes
+      // and add the interface in the Glib::Object constructor.
+      Threads::Mutex::Lock lock(*extra_object_base_data_mutex);
+      extra_object_base_data[this].custom_interface_classes.push_back(&interface_class);
     }
   }
 }
diff --git a/glib/glibmm/object.cc b/glib/glibmm/object.cc
index f9547f4..1658d81 100644
--- a/glib/glibmm/object.cc
+++ b/glib/glibmm/object.cc
@@ -18,6 +18,7 @@
  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <glibmm/threads.h> // Needed until the next ABI break.
 #include <glibmm/object.h>
 #include <glibmm/private/object_p.h>
 #include <glibmm/property.h>
@@ -200,16 +201,27 @@ Object::Object()
 
   if(custom_type_name_ && !is_anonymous_custom_())
   {
+    Class::interface_class_vector_type custom_interface_classes;
+
+    Threads::Mutex::Lock lock(*extra_object_base_data_mutex);
+    const extra_object_base_data_type::iterator iter = extra_object_base_data.find(this);
+    if (iter != extra_object_base_data.end())
+    {
+      custom_interface_classes = iter->second.custom_interface_classes;
+      extra_object_base_data.erase(iter);
+    }
+    lock.release();
+
     object_class_.init();
     // This creates a type that is derived (indirectly) from GObject.
-    object_type = object_class_.clone_custom_type(custom_type_name_);
+    object_type = object_class_.clone_custom_type(
+      custom_type_name_, custom_interface_classes);
   }
 
   void *const new_object = g_object_newv(object_type, 0, 0);
 
   // Connect the GObject and Glib::Object instances.
   ObjectBase::initialize(static_cast<GObject*>(new_object));
-
 }
 
 Object::Object(const Glib::ConstructParams& construct_params)
@@ -221,7 +233,21 @@ Object::Object(const Glib::ConstructParams& construct_params)
   // class, therefore its constructor is always executed first.
 
   if(custom_type_name_ && !is_anonymous_custom_())
-    object_type = construct_params.glibmm_class.clone_custom_type(custom_type_name_);
+  {
+    Class::interface_class_vector_type custom_interface_classes;
+
+    Threads::Mutex::Lock lock(*extra_object_base_data_mutex);
+    const extra_object_base_data_type::iterator iter = extra_object_base_data.find(this);
+    if (iter != extra_object_base_data.end())
+    {
+      custom_interface_classes = iter->second.custom_interface_classes;
+      extra_object_base_data.erase(iter);
+    }
+    lock.release();
+
+    object_type = construct_params.glibmm_class.clone_custom_type(
+      custom_type_name_, custom_interface_classes);
+  }
 
   // Create a new GObject with the specified array of construct properties.
   // This works with custom types too, since those inherit the properties of
diff --git a/glib/glibmm/objectbase.cc b/glib/glibmm/objectbase.cc
index 7a2c377..140816a 100644
--- a/glib/glibmm/objectbase.cc
+++ b/glib/glibmm/objectbase.cc
@@ -18,12 +18,14 @@
  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <glibmm/threads.h> // Needed until the next ABI break.
 #include <glib-object.h>
 
 #include <glibmm/quark.h>
 #include <glibmm/objectbase.h>
 #include <glibmm/propertyproxy_base.h> //For PropertyProxyConnectionNode
-
+#include <glibmm/interface.h>
+#include <glibmm/private/interface_p.h>
 
 namespace
 {
@@ -42,6 +44,10 @@ namespace Glib
 
 /**** Glib::ObjectBase *****************************************************/
 
+// static data members
+ObjectBase::extra_object_base_data_type ObjectBase::extra_object_base_data;
+std::auto_ptr<Threads::Mutex> ObjectBase::extra_object_base_data_mutex(new Threads::Mutex());
+
 ObjectBase::ObjectBase()
 :
   gobject_                      (0),
@@ -102,6 +108,14 @@ ObjectBase::~ObjectBase()
   // happens if a derived class's ctor throws an exception.  In that case
   // we have to call g_object_unref() on our own.
   //
+
+  // Just a precaution. Unless a derived class's ctor has thrown an exception,
+  // 'this' should have been erased from extra_object_base_data by
+  // Glib::Object's constructor.
+  Threads::Mutex::Lock lock(*extra_object_base_data_mutex);
+  extra_object_base_data.erase(this);
+  lock.release();
+
   if(GObject *const gobject = gobject_)
   {
 #ifdef GLIBMM_DEBUG_REFCOUNTING
diff --git a/glib/glibmm/objectbase.h b/glib/glibmm/objectbase.h
index 97f78f3..9c4c4e8 100644
--- a/glib/glibmm/objectbase.h
+++ b/glib/glibmm/objectbase.h
@@ -20,15 +20,17 @@
  */
 
 #include <glibmmconfig.h>
+#include <glibmm/class.h>
 #include <glibmm/signalproxy.h>
 #include <glibmm/propertyproxy.h>
 #include <glibmm/ustring.h>
 #include <glibmm/value.h>
 #include <glibmm/quark.h>
-#include <glibmmconfig.h>
 #include <glibmm/debug.h>
 #include <sigc++/trackable.h>
 #include <typeinfo>
+#include <map> // Needed until the next ABI break.
+#include <memory> // auto_ptr, needed until the next ABI break.
 
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
 extern "C" { typedef struct _GObject GObject; }
@@ -39,6 +41,11 @@ namespace Glib
 
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
 class GSigConnectionNode;
+class Interface_Class;
+namespace Threads
+{
+class Mutex;
+}
 #endif
 
 //This inherits virtually from sigc::trackable so that people can multiply inherit glibmm classes from other 
sigc::trackable-derived classes.
@@ -188,6 +195,24 @@ protected:
 
   bool is_anonymous_custom_() const;
 
+//TODO: At the next ABI break, replace extra_object_base_data by a non-static
+// data member.
+// This is a new data member that can't be added as instance data to
+// ObjectBase now, because it would break ABI.
+struct ExtraObjectBaseData
+{
+  Class::interface_class_vector_type custom_interface_classes;
+};
+
+typedef std::map<const ObjectBase*, ExtraObjectBaseData> extra_object_base_data_type;
+static extra_object_base_data_type extra_object_base_data;
+// ObjectBase instances may be used in different threads.
+// Accesses to extra_object_base_data must be thread-safe.
+// auto_ptr, because we don't want to include glibmm/threads.h in objectbase.h.
+// threads.h must be the first included file that includes glib.h. That could cause
+// problems in files that directly or indirectly include objectbase.h.
+static std::auto_ptr<Threads::Mutex> extra_object_base_data_mutex;
+
 public: //  is_derived_() must be public, so that overridden vfuncs and signal handlers can call it via 
ObjectBase.
 
   /// This is for use by gtkmm wrappers only, and not by applications.


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