summaryrefslogtreecommitdiff
path: root/glib/glibmm
diff options
context:
space:
mode:
authorMurray Cumming <murrayc@murrayc.com>2007-09-25 14:02:47 +0000
committerMurray Cumming <murrayc@src.gnome.org>2007-09-25 14:02:47 +0000
commit325bd60ad0e52842a21a3df0d11e1fceaf0bfc34 (patch)
treee355ed0e613e8581a842991a7809cac16baf6358 /glib/glibmm
parent7c3d8c926c65411b57514cfa01a27e7a45abb51b (diff)
downloadglibmm-325bd60ad0e52842a21a3df0d11e1fceaf0bfc34.tar.gz
Added wrap_auto_interface<>(), which should be used by wrap()
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. svn path=/trunk/; revision=445
Diffstat (limited to 'glib/glibmm')
-rw-r--r--glib/glibmm/signalproxy_connectionnode.h9
-rw-r--r--glib/glibmm/wrap.cc77
-rw-r--r--glib/glibmm/wrap.h48
3 files changed, 99 insertions, 35 deletions
diff --git a/glib/glibmm/signalproxy_connectionnode.h b/glib/glibmm/signalproxy_connectionnode.h
index d3cfff81..dececda2 100644
--- a/glib/glibmm/signalproxy_connectionnode.h
+++ b/glib/glibmm/signalproxy_connectionnode.h
@@ -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 */
diff --git a/glib/glibmm/wrap.cc b/glib/glibmm/wrap.cc
index 5a7d8404..bb84b8f2 100644
--- a/glib/glibmm/wrap.cc
+++ b/glib/glibmm/wrap.cc
@@ -45,36 +45,6 @@ typedef std::vector<Glib::WrapNewFunction> WrapFuncTable;
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, WrapNewFunction func)
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, bool take_copy)
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)
{
diff --git a/glib/glibmm/wrap.h b/glib/glibmm/wrap.h
index 58288ecd..472150e7 100644
--- a/glib/glibmm/wrap.h
+++ b/glib/glibmm/wrap.h
@@ -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, WrapNewFunction func);
// 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().