Wrapping interfaces that are implemented by unknown types.
- From: Murray Cumming <murrayc murrayc com>
- To: gtkmm-list <gtkmm-list gnome org>
- Subject: Wrapping interfaces that are implemented by unknown types.
- Date: Wed, 26 Sep 2007 10:20:16 +0200
I have already applied this patch to glibmm svn trunk, and I will soon
apply it to the 2.14 branch too. I thought I should post it here for
review.
It makes this code work, for instance:
GtkTreeModel* cmodel = libsomethingspecial_tree_model_new()
Glib::RefPtr<Gtk::TreeModel> model = Glib::wrap(cmodel);
This is helpful in libgdamm, which instantiates some objects for which
it does not even install headers.
--
murrayc murrayc com
www.murrayc.com
www.openismus.com
Index: ChangeLog
===================================================================
--- ChangeLog (revision 445)
+++ ChangeLog (working copy)
@@ -1,3 +1,16 @@
+2007-09-25 Murray Cumming <murrayc murrayc com>
+
+ * glib/glibmm/wrap.cc:
+ * glib/glibmm/wrap.h: Added wrap_auto_interface<>(), which should
+ be used by wrap() specializations for interfaces, so we create
+ instances of the interface even if the derived C type is unknown to
+ us.
+ * glib/glibmm/signalproxy_connectionnode.h: Do not wrap.h from here
+ unnecessarily, to allow us to include objectbase.h in wrap.h,
+ needed by the new templated method.
+ * tools/m4/class_interface.m4: Use wrap_auto_interface<>()
+ instead of wrap_auto() for interfaces.
+
2.14.0:
2007-09-06 Daniel Elstner <danielk openismus com>
Index: tools/m4/class_interface.m4
===================================================================
--- tools/m4/class_interface.m4 (revision 445)
+++ tools/m4/class_interface.m4 (working copy)
@@ -162,7 +162,7 @@ namespace Glib
Glib::RefPtr<__NAMESPACE__::__CPPNAME__> wrap(__CNAME__`'* object, bool take_copy)
{
- return Glib::RefPtr<__NAMESPACE__::__CPPNAME__>( dynamic_cast<__NAMESPACE__::__CPPNAME__*> (Glib::wrap_auto ((GObject*)(object), take_copy)) );
+ return Glib::RefPtr<__NAMESPACE__::__CPPNAME__>( dynamic_cast<__NAMESPACE__::__CPPNAME__*> (Glib::wrap_auto_interface<__NAMESPACE__::__CPPNAME__> ((GObject*)(object), take_copy)) );
//We use dynamic_cast<> in case of multiple inheritance.
}
@@ -237,8 +237,14 @@ private:
protected:
__CPPNAME__`'(); // you must derive from this class
+
+public:
+ // This is public so that C++ wrapper instances can be
+ // created for C instances of unwrapped types.
+ // For instance, if an unexpected C type implements the C interface.
explicit __CPPNAME__`'(__CNAME__* castitem);
+protected:
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
public:
Index: glib/glibmm/signalproxy_connectionnode.h
===================================================================
--- glib/glibmm/signalproxy_connectionnode.h (revision 445)
+++ glib/glibmm/signalproxy_connectionnode.h (working copy)
@@ -24,13 +24,18 @@
*/
#include <sigc++/sigc++.h>
-#include <glibmm/wrap.h>
+#include <glib/gtypes.h>
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
typedef struct _GObject GObject;
+typedef struct _GClosure GClosure;
+#endif //DOXYGEN_SHOULD_SKIP_THIS
namespace Glib
{
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
/** SignalProxyConnectionNode is a connection node for use with SignalProxy.
* It lives between the layer of Gtk+ and libsigc++.
* It is very much an internal class.
@@ -63,6 +68,8 @@ protected:
GObject* object_;
};
+#endif //DOXYGEN_SHOULD_SKIP_THIS
+
} /* namespace Glib */
Index: glib/glibmm/wrap.cc
===================================================================
--- glib/glibmm/wrap.cc (revision 445)
+++ glib/glibmm/wrap.cc (working copy)
@@ -45,36 +45,6 @@ typedef std::vector<Glib::WrapNewFunctio
static WrapFuncTable* wrap_func_table = 0;
-
-static Glib::ObjectBase* create_new_wrapper(GObject* object)
-{
- g_return_val_if_fail(wrap_func_table != 0, 0);
-
- bool gtkmm_wrapper_already_deleted = (bool)g_object_get_qdata((GObject*)object, Glib::quark_cpp_wrapper_deleted_);
- if(gtkmm_wrapper_already_deleted)
- {
- g_warning("Glib::create_new_wrapper: Attempted to create a 2nd C++ wrapper for a C instance whose C++ wrapper has been deleted.");
- return 0;
- }
-
- // Traverse upwards through the inheritance hierarchy
- // to find the most-specialized wrap_new() for this GType.
- //
- for(GType type = G_OBJECT_TYPE(object); type != 0; type = g_type_parent(type))
- {
- // Look up the wrap table index stored in the type's static data.
- // If a wrap_new() has been registered for the type then call it.
- //
- if(const gpointer idx = g_type_get_qdata(type, Glib::quark_))
- {
- const Glib::WrapNewFunction func = (*wrap_func_table)[GPOINTER_TO_UINT(idx)];
- return (*func)(object);
- }
- }
-
- return 0;
-}
-
} // anonymous namespace
@@ -120,6 +90,48 @@ void wrap_register(GType type, WrapNewFu
g_type_set_qdata(type, Glib::quark_, GUINT_TO_POINTER(idx));
}
+
+Glib::ObjectBase* wrap_create_new_wrapper(GObject* object, bool exact_type_only)
+{
+ g_return_val_if_fail(wrap_func_table != 0, 0);
+
+ const bool gtkmm_wrapper_already_deleted = (bool)g_object_get_qdata((GObject*)object, Glib::quark_cpp_wrapper_deleted_);
+ if(gtkmm_wrapper_already_deleted)
+ {
+ g_warning("Glib::wrap_create_new_wrapper: Attempted to create a 2nd C++ wrapper for a C instance whose C++ wrapper has been deleted.");
+ return 0;
+ }
+
+ if(exact_type_only)
+ {
+ GType type = G_OBJECT_TYPE(object);
+ if(const gpointer idx = g_type_get_qdata(type, Glib::quark_))
+ {
+ const Glib::WrapNewFunction func = (*wrap_func_table)[GPOINTER_TO_UINT(idx)];
+ return (*func)(object);
+ }
+ }
+ else
+ {
+ // Traverse upwards through the inheritance hierarchy
+ // to find the most-specialized wrap_new() for this GType.
+ //
+ for(GType type = G_OBJECT_TYPE(object); type != 0; type = g_type_parent(type))
+ {
+ // Look up the wrap table index stored in the type's static data.
+ // If a wrap_new() has been registered for the type then call it.
+ //
+ if(const gpointer idx = g_type_get_qdata(type, Glib::quark_))
+ {
+ const Glib::WrapNewFunction func = (*wrap_func_table)[GPOINTER_TO_UINT(idx)];
+ return (*func)(object);
+ }
+ }
+ }
+
+ return 0;
+}
+
// This is a factory function that converts any type to
// its C++ wrapper instance by looking up a wrap_new() function in a map.
//
@@ -129,13 +141,12 @@ ObjectBase* wrap_auto(GObject* object, b
return 0;
// Look up current C++ wrapper instance:
- ObjectBase* pCppObject =
- static_cast<ObjectBase*>(g_object_get_qdata(object, Glib::quark_));
+ ObjectBase* pCppObject = ObjectBase::_get_current_wrapper(object);
if(!pCppObject)
{
// There's not already a wrapper: generate a new C++ instance.
- pCppObject = create_new_wrapper(object);
+ pCppObject = wrap_create_new_wrapper(object);
if(!pCppObject)
{
Index: glib/glibmm/wrap.h
===================================================================
--- glib/glibmm/wrap.h (revision 445)
+++ glib/glibmm/wrap.h (working copy)
@@ -23,11 +23,13 @@
#include <glib-object.h>
#include <glibmm/refptr.h>
-
+#include <glibmm/objectbase.h>
namespace Glib
{
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
class ObjectBase;
class Object;
@@ -46,6 +48,50 @@ void wrap_register(GType type, WrapNewFu
// or automatically generate a new wrapper if there's none.
Glib::ObjectBase* wrap_auto(GObject* object, bool take_copy = false);
+/** Create a C++ instance of a known C++ type that is mostly closely associated with the GType of the C object.
+ * @param object The C object which should be placed in a new C++ instance.
+ * @param exact_type_only If this is true then only create a C++ object if we know of a C++ type that exactly matches the C object's GType.
+ */
+Glib::ObjectBase* wrap_create_new_wrapper(GObject* object, bool exact_type_only = false);
+
+// Return the current C++ wrapper instance of the GObject,
+// or automatically generate a new wrapper if there's none.
+template<class TInterface>
+TInterface* wrap_auto_interface(GObject* object, bool take_copy = false)
+{
+ if(!object)
+ return 0;
+
+ // Look up current C++ wrapper instance:
+ ObjectBase* pCppObject = ObjectBase::_get_current_wrapper(object);
+
+ if(!pCppObject)
+ {
+ // There's not already a wrapper: generate a new C++ instance.
+ // We use exact_type_only=true avoid creating Glib::Object for interfaces of unknown implementation,
+ // because we do not want a C++ object that does not dynamic_cast to the expected interface type.
+ pCppObject = wrap_create_new_wrapper(object, true /* exact_type_only */);
+ }
+
+ //If no exact wrapper was created,
+ //create an instance of the interface,
+ //so we at least get the expected type:
+ TInterface* result = 0;
+ if(pCppObject)
+ result = dynamic_cast<TInterface*>(pCppObject);
+ else
+ result = new TInterface((typename TInterface::BaseObjectType*)object);
+
+ // take_copy=true is used where the GTK+ function doesn't do
+ // an extra ref for us, and always for plain struct members.
+ if(take_copy && result)
+ result->reference();
+
+ return result;
+}
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
+
// Get a C++ instance that wraps the C instance.
// This always returns the same C++ instance for the same C instance.
// Each wrapper has it's own override of Glib::wrap().
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]