diff options
Diffstat (limited to 'glib/glibmm')
-rw-r--r-- | glib/glibmm/class.cc | 31 | ||||
-rw-r--r-- | glib/glibmm/extraclassinit.h | 45 | ||||
-rw-r--r-- | glib/glibmm/main.cc | 57 | ||||
-rw-r--r-- | glib/glibmm/main.h | 13 | ||||
-rw-r--r-- | glib/glibmm/objectbase.cc | 17 | ||||
-rw-r--r-- | glib/glibmm/propertyproxy_base.cc | 22 | ||||
-rw-r--r-- | glib/glibmm/signalproxy.cc | 49 |
7 files changed, 201 insertions, 33 deletions
diff --git a/glib/glibmm/class.cc b/glib/glibmm/class.cc index 31f92c61..5344f381 100644 --- a/glib/glibmm/class.cc +++ b/glib/glibmm/class.cc @@ -21,6 +21,30 @@ #include <glibmm/interface.h> #include <glibmm/private/interface_p.h> +namespace +{ +// C++ linkage +using BaseFinalizeFuncType = void (*)(void*); +using ClassInitFuncType = void (*)(void*, void*); + +BaseFinalizeFuncType p_custom_class_base_finalize_function; +ClassInitFuncType p_custom_class_init_function; + +extern "C" +{ +// From functions with C linkage, to private static member functions with C++ linkage +static void Class_custom_class_base_finalize_function(void* g_class) +{ + p_custom_class_base_finalize_function(g_class); +} + +static void Class_custom_class_init_function(void* g_class, void* class_data) +{ + p_custom_class_init_function(g_class, class_data); +} +} // extern "C" +} // anonymous namespace + namespace Glib { @@ -128,11 +152,14 @@ Class::clone_custom_type( all_class_init_funcs->insert(all_class_init_funcs->end(), class_init_funcs->begin(), class_init_funcs->end()); + p_custom_class_base_finalize_function = &Class::custom_class_base_finalize_function; + p_custom_class_init_function = &Class::custom_class_init_function; + const GTypeInfo derived_info = { class_size, nullptr, // base_init - &Class::custom_class_base_finalize_function, // base_finalize - &Class::custom_class_init_function, + &Class_custom_class_base_finalize_function, // base_finalize + &Class_custom_class_init_function, nullptr, // class_finalize all_class_init_funcs, // class_data instance_size, diff --git a/glib/glibmm/extraclassinit.h b/glib/glibmm/extraclassinit.h index b5b9e698..03ad9c8a 100644 --- a/glib/glibmm/extraclassinit.h +++ b/glib/glibmm/extraclassinit.h @@ -29,6 +29,30 @@ namespace Glib * @code * #include <glibmm/extraclassinit.h> * + * extern "C" + * { + * // Extra class init function. + * static void my_extra_class_init_function(void* g_class, void* class_data) + * { + * g_return_if_fail(GTK_IS_WIDGET_CLASS(g_class)); + * + * const auto klass = static_cast<GtkWidgetClass*>(g_class); + * const auto css_name = static_cast<Glib::ustring*>(class_data); + * + * gtk_widget_class_set_css_name(klass, css_name->c_str()); + * } + * + * // Extra instance init function. + * static void my_instance_init_function(GTypeInstance* instance, void* g_class) + * { + * g_return_if_fail(GTK_IS_WIDGET(instance)); + * + * // Nothing to do here. + * // This extra instance init function just shows how such a function can + * // be added to a custom widget, if necessary. + * } + * } // extern "C" + * * class MyExtraInit : public Glib::ExtraClassInit * { * public: @@ -39,17 +63,6 @@ namespace Glib * { } * * private: - * static void my_extra_class_init_function(void* g_class, void* class_data) - * { - * const auto klass = static_cast<GtkWidgetClass*>(g_class); - * const auto css_name = static_cast<Glib::ustring*>(class_data); - * gtk_widget_class_set_css_name(klass, css_name->c_str()); - * } - * static void my_instance_init_function(GTypeInstance* instance, void* g_class) - * { - * gtk_widget_set_has_surface(GTK_WIDGET(instance), true); - * } - * * Glib::ustring m_css_name; * }; * @@ -69,6 +82,16 @@ namespace Glib * }; * @endcode * + * The callback functions (my_extra_class_init_function() and my_instance_init_function() + * in the example) are called from GLib (a C library). They shall have C linkage. + * (Many compilers accept callback functions with C++ linkage, but such a program + * has undefined behavior.) + * + * If you want the functions with C linkage to have internal linkage, they must + * be declared 'static', even if they are defined in an anonymous namespace. + * The compiler respects namespace declarations of functions with C linkage, + * but the linker does not. + * @note Classes derived from %ExtraClassInit (MyExtraInit in the example) * must be listed before Glib::Object or a class derived from * %Glib::Object (Gtk::Widget in the example) in the list of base classes. diff --git a/glib/glibmm/main.cc b/glib/glibmm/main.cc index b46a615c..a0577ba4 100644 --- a/glib/glibmm/main.cc +++ b/glib/glibmm/main.cc @@ -170,6 +170,37 @@ glibmm_source_get_callback_data(GSource* source) return static_cast<SourceCallbackData*>(user_data); } +// The function pointers, glibmm_source_*_vfuncptr, are set in the Source ctor +// that calls g_source_new(const_cast<GSourceFuncs*>(&vfunc_table_), sizeof(GSource)), +// making it possible to indirectly call the Source::*_vfunc() member functions +// from the glibmm_source_*_callback() functions with C linkage. +using SourcePrepareVFuncType = gboolean (*)(GSource* source, int* timeout); +using SourceCheckVFuncType = gboolean (*)(GSource* source); +using SourceDispatchVFuncType = gboolean (*)(GSource* source, GSourceFunc callback, void* user_data); +SourcePrepareVFuncType glibmm_source_prepare_vfuncptr; +SourceCheckVFuncType glibmm_source_check_vfuncptr; +SourceDispatchVFuncType glibmm_source_dispatch_vfuncptr; + +extern "C" +{ +static gboolean +glibmm_source_prepare_callback(GSource* source, int* timeout) +{ + return glibmm_source_prepare_vfuncptr(source, timeout); +} + +static gboolean +glibmm_source_check_callback(GSource* source) +{ + return glibmm_source_check_vfuncptr(source); +} + +static gboolean +glibmm_source_dispatch_callback(GSource* source, GSourceFunc callback, void* user_data) +{ + return glibmm_source_dispatch_vfuncptr(source, callback, user_data); +} + /* Glib::Source doesn't use the callback function installed with * g_source_set_callback(). Instead, it invokes the sigc++ slot * directly from dispatch_vfunc(), which is both simpler and more @@ -273,6 +304,7 @@ glibmm_child_watch_callback(GPid pid, gint child_status, void* data) } return 0; } +} // extern "C" static void glibmm_signal_connect_once( @@ -291,7 +323,9 @@ glibmm_signal_connect_once( g_source_unref(source); // GMainContext holds a reference } -gboolean +extern "C" +{ +static gboolean glibmm_main_context_invoke_callback(void* data) { sigc::slot_base* const slot = reinterpret_cast<sigc::slot_base*>(data); @@ -308,13 +342,20 @@ glibmm_main_context_invoke_callback(void* data) return 0; } -void +static void glibmm_main_context_invoke_destroy_notify_callback(void* data) { sigc::slot_base* const slot = reinterpret_cast<sigc::slot_base*>(data); delete slot; } +static void +glibmm_source_callback_data_destroy_notify_callback(void* data) +{ + SourceCallbackData::destroy_notify_callback(data); +} +} // extern "C" + } // anonymous namespace namespace Glib @@ -844,7 +885,9 @@ wrap(GMainLoop* gobject, bool take_copy) // static const GSourceFuncs Source::vfunc_table_ = { - &Source::prepare_vfunc, &Source::check_vfunc, &Source::dispatch_vfunc, + &glibmm_source_prepare_callback, + &glibmm_source_check_callback, + &glibmm_source_dispatch_callback, // We can't use finalize_vfunc because there is no way // to store a pointer to our wrapper anywhere in GSource so // that it persists until finalize_vfunc would be called from here. @@ -937,16 +980,20 @@ Source::unreference() const Source::Source() : gobject_(g_source_new(const_cast<GSourceFuncs*>(&vfunc_table_), sizeof(GSource))) { + glibmm_source_prepare_vfuncptr = &prepare_vfunc; + glibmm_source_check_vfuncptr = &check_vfunc; + glibmm_source_dispatch_vfuncptr = &dispatch_vfunc; + g_source_set_callback(gobject_, &glibmm_dummy_source_callback, new SourceCallbackData(this), // our persistent callback data object - &SourceCallbackData::destroy_notify_callback); + &glibmm_source_callback_data_destroy_notify_callback); } Source::Source(GSource* cast_item, GSourceFunc callback_func) : gobject_(cast_item) { g_source_set_callback(gobject_, callback_func, new SourceCallbackData(this), // our persistent callback data object - &SourceCallbackData::destroy_notify_callback); + &glibmm_source_callback_data_destroy_notify_callback); } Source::~Source() noexcept diff --git a/glib/glibmm/main.h b/glib/glibmm/main.h index ecdfb9a7..77c27909 100644 --- a/glib/glibmm/main.h +++ b/glib/glibmm/main.h @@ -494,6 +494,8 @@ public: * This function could possibly be used to integrate the GLib event loop with an external event * loop. * @param poll_func The function to call to poll all file descriptors. + * This function shall have C linkage. (Many compilers also accept + * a function with C++ linkage.) */ void set_poll_func(GPollFunc poll_func); @@ -800,9 +802,11 @@ protected: /** Wrap an existing GSource object and install the given callback function. * The constructed object doesn't use the virtual functions prepare(), check() and dispatch(). * This constructor is for use by derived types that need to wrap a GSource object. - * The callback function can be a static member function. But beware - - * depending on the actual implementation of the GSource's virtual functions - * the expected type of the callback function can differ from GSourceFunc. + * The callback function is called from GLib (a C library). It shall have C + * linkage. (Many compilers accept a function with C++ linkage. If you use + * only such compilers, the callback function can be a static member function.) + * But beware - depending on the actual implementation of the GSource's virtual + * functions the expected type of the callback function can differ from GSourceFunc. */ GLIBMM_API Source(GSource* cast_item, GSourceFunc callback_func); @@ -927,6 +931,9 @@ protected: /** Wrap an existing GSource object and install the given callback function. * This constructor is for use by derived types that need to wrap a GSource object. + * The callback function is called from GLib (a C library). It shall have C + * linkage. (Many compilers accept a function with C++ linkage. If you use + * only such compilers, the callback function can be a static member function.) * @see Source::Source(GSource*, GSourceFunc). * @newin{2,42} */ diff --git a/glib/glibmm/objectbase.cc b/glib/glibmm/objectbase.cc index f23c4977..84067f8c 100644 --- a/glib/glibmm/objectbase.cc +++ b/glib/glibmm/objectbase.cc @@ -32,6 +32,18 @@ namespace static const char anonymous_custom_type_name[] = "gtkmm__anonymous_custom_type"; +using ObjectBaseDestroyNotifyFuncType = void (*)(void* data); +ObjectBaseDestroyNotifyFuncType ObjectBase_destroy_notify_funcptr; + +// From function with C linkage, to protected static member function with C++ linkage +extern "C" +{ +static void ObjectBase_destroy_notify_callback(void* data) +{ + ObjectBase_destroy_notify_funcptr(data); +} +} // extern "C" + } // anonymous namespace namespace Glib @@ -219,7 +231,8 @@ ObjectBase::_set_current_wrapper(GObject* object) { if (!g_object_get_qdata(object, Glib::quark_)) { - g_object_set_qdata_full(object, Glib::quark_, this, &destroy_notify_callback_); + ObjectBase_destroy_notify_funcptr = &destroy_notify_callback_; + g_object_set_qdata_full(object, Glib::quark_, this, &ObjectBase_destroy_notify_callback); } else { @@ -247,7 +260,7 @@ ObjectBase::_move_current_wrapper(GObject* object, Glib::ObjectBase* previous_wr g_object_steal_qdata(object, Glib::quark_); // Set the new wrapper: - g_object_set_qdata_full(object, Glib::quark_, this, &destroy_notify_callback_); + g_object_set_qdata_full(object, Glib::quark_, this, &ObjectBase_destroy_notify_callback); // Clear the previous wrapper: previous_wrapper->gobject_ = nullptr; diff --git a/glib/glibmm/propertyproxy_base.cc b/glib/glibmm/propertyproxy_base.cc index bc643498..b062bb68 100644 --- a/glib/glibmm/propertyproxy_base.cc +++ b/glib/glibmm/propertyproxy_base.cc @@ -23,6 +23,24 @@ #include <glibmm/private/object_p.h> #include <utility> // For std::move() +namespace +{ +extern "C" +{ +// From functions with C linkage to public static member functions with C++ linkage +static void PropertyProxyConnectionNode_callback(GObject* object, GParamSpec* pspec, gpointer data) +{ + Glib::PropertyProxyConnectionNode::callback(object, pspec, data); +} + +static void PropertyProxyConnectionNode_destroy_notify_handler(gpointer data, GClosure* closure) +{ + // It's actually in the base class SignalProxyConnectionNode + Glib::PropertyProxyConnectionNode::destroy_notify_handler(data, closure); +} +} // extern "C" +} // anonymous namespace + namespace Glib { @@ -55,8 +73,8 @@ PropertyProxyConnectionNode::connect_changed(const Glib::ustring& property_name) // 'this' will be passed as the data argument to the callback. const Glib::ustring notify_signal_name = get_detailed_signal_name("notify", property_name); connection_id_ = g_signal_connect_data(object_, notify_signal_name.c_str(), - (GCallback)(&PropertyProxyConnectionNode::callback), this, - &PropertyProxyConnectionNode::destroy_notify_handler, G_CONNECT_AFTER); + (GCallback)(&PropertyProxyConnectionNode_callback), this, + &PropertyProxyConnectionNode_destroy_notify_handler, G_CONNECT_AFTER); return sigc::connection(slot_); } diff --git a/glib/glibmm/signalproxy.cc b/glib/glibmm/signalproxy.cc index c36d7130..1d1461f5 100644 --- a/glib/glibmm/signalproxy.cc +++ b/glib/glibmm/signalproxy.cc @@ -21,6 +21,23 @@ #include <glibmm/object.h> #include <glibmm/signalproxy.h> +namespace +{ +extern "C" +{ +// From functions with C linkage to public static member functions with C++ linkage +static void SignalProxyNormal_slot0_void_callback(GObject* self, void* data) +{ + Glib::SignalProxyNormal::slot0_void_callback(self, data); +} + +static void SignalProxyConnectionNode_destroy_notify_handler(gpointer data, GClosure* closure) +{ + Glib::SignalProxyConnectionNode::destroy_notify_handler(data, closure); +} +} // extern "C" +} // anonymous namespace + namespace Glib { @@ -44,14 +61,18 @@ SignalProxyNormal::~SignalProxyNormal() noexcept sigc::slot_base& SignalProxyNormal::connect_impl_(bool notify, const sigc::slot_base& slot, bool after) { + GCallback c_handler = notify ? info_->notify_callback : info_->callback; + if (c_handler == (GCallback)&slot0_void_callback) + // Callback via a function with C linkage. + c_handler = (GCallback)&SignalProxyNormal_slot0_void_callback; + // create a proxy to hold our connection info auto pConnectionNode = new SignalProxyConnectionNode(slot, obj_->gobj()); // connect it to glib // pConnectionNode will be passed in the data argument to the callback. pConnectionNode->connection_id_ = g_signal_connect_data(obj_->gobj(), info_->signal_name, - notify ? info_->notify_callback : info_->callback, pConnectionNode, - &SignalProxyConnectionNode::destroy_notify_handler, + c_handler, pConnectionNode, &SignalProxyConnectionNode_destroy_notify_handler, static_cast<GConnectFlags>(after ? G_CONNECT_AFTER : 0)); return pConnectionNode->slot_; @@ -60,14 +81,18 @@ SignalProxyNormal::connect_impl_(bool notify, const sigc::slot_base& slot, bool sigc::slot_base& SignalProxyNormal::connect_impl_(bool notify, sigc::slot_base&& slot, bool after) { + GCallback c_handler = notify ? info_->notify_callback : info_->callback; + if (c_handler == (GCallback)&slot0_void_callback) + // Callback via a function with C linkage. + c_handler = (GCallback)&SignalProxyNormal_slot0_void_callback; + // create a proxy to hold our connection info auto pConnectionNode = new SignalProxyConnectionNode(std::move(slot), obj_->gobj()); // connect it to glib // pConnectionNode will be passed in the data argument to the callback. pConnectionNode->connection_id_ = g_signal_connect_data(obj_->gobj(), info_->signal_name, - notify ? info_->notify_callback : info_->callback, pConnectionNode, - &SignalProxyConnectionNode::destroy_notify_handler, + c_handler, pConnectionNode, &SignalProxyConnectionNode_destroy_notify_handler, static_cast<GConnectFlags>(after ? G_CONNECT_AFTER : 0)); return pConnectionNode->slot_; @@ -116,14 +141,18 @@ SignalProxyDetailedBase::~SignalProxyDetailedBase() noexcept sigc::slot_base& SignalProxyDetailedBase::connect_impl_(bool notify, const sigc::slot_base& slot, bool after) { + GCallback c_handler = notify ? info_->notify_callback : info_->callback; + if (c_handler == (GCallback)&SignalProxyNormal::slot0_void_callback) + // Callback via a function with C linkage. + c_handler = (GCallback)&SignalProxyNormal_slot0_void_callback; + // create a proxy to hold our connection info auto pConnectionNode = new SignalProxyConnectionNode(slot, obj_->gobj()); // connect it to glib // pConnectionNode will be passed in the data argument to the callback. pConnectionNode->connection_id_ = g_signal_connect_data(obj_->gobj(), detailed_name_.c_str(), - notify ? info_->notify_callback : info_->callback, pConnectionNode, - &SignalProxyConnectionNode::destroy_notify_handler, + c_handler, pConnectionNode, &SignalProxyConnectionNode_destroy_notify_handler, static_cast<GConnectFlags>(after ? G_CONNECT_AFTER : 0)); return pConnectionNode->slot_; @@ -132,14 +161,18 @@ SignalProxyDetailedBase::connect_impl_(bool notify, const sigc::slot_base& slot, sigc::slot_base& SignalProxyDetailedBase::connect_impl_(bool notify, sigc::slot_base&& slot, bool after) { + GCallback c_handler = notify ? info_->notify_callback : info_->callback; + if (c_handler == (GCallback)&SignalProxyNormal::slot0_void_callback) + // Callback via a function with C linkage. + c_handler = (GCallback)&SignalProxyNormal_slot0_void_callback; + // create a proxy to hold our connection info auto pConnectionNode = new SignalProxyConnectionNode(std::move(slot), obj_->gobj()); // connect it to glib // pConnectionNode will be passed in the data argument to the callback. pConnectionNode->connection_id_ = g_signal_connect_data(obj_->gobj(), detailed_name_.c_str(), - notify ? info_->notify_callback : info_->callback, pConnectionNode, - &SignalProxyConnectionNode::destroy_notify_handler, + c_handler, pConnectionNode, &SignalProxyConnectionNode_destroy_notify_handler, static_cast<GConnectFlags>(after ? G_CONNECT_AFTER : 0)); return pConnectionNode->slot_; |