[glibmm] Add interfaces to custom types before class_init.
- From: Kjell Ahlstedt <kjellahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glibmm] Add interfaces to custom types before class_init.
- Date: Thu, 1 Aug 2013 07:36:55 +0000 (UTC)
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]