diff options
author | Murray Cumming <murrayc@murrayc.com> | 2007-09-25 14:02:47 +0000 |
---|---|---|
committer | Murray Cumming <murrayc@src.gnome.org> | 2007-09-25 14:02:47 +0000 |
commit | 325bd60ad0e52842a21a3df0d11e1fceaf0bfc34 (patch) | |
tree | e355ed0e613e8581a842991a7809cac16baf6358 /glib/glibmm | |
parent | 7c3d8c926c65411b57514cfa01a27e7a45abb51b (diff) | |
download | glibmm-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.h | 9 | ||||
-rw-r--r-- | glib/glibmm/wrap.cc | 77 | ||||
-rw-r--r-- | glib/glibmm/wrap.h | 48 |
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(). |