From 98f3b67b5c1bd71d0e7b41193fb4683fc957e321 Mon Sep 17 00:00:00 2001 From: Kjell Ahlstedt Date: Fri, 31 Mar 2023 15:24:13 +0200 Subject: Glib: Use callback functions with C linkage * gio/src/cancellable.ccg: Add TODO comment. * glib/glibmm/class.cc: Call custom_class_base_finalize_function() and custom_class_init_function() via local functions with C linkage. * glib/glibmm/extraclassinit.h: Point out in the class documentation that the class init and instance init functions shall have C linkage. * glib/glibmm/main.[cc|h]: Call prepare_vfunc(), check_vfunc() and dispatch_vfunc() via local functions with C linkage. * glib/glibmm/objectbase.cc: Call destroy_notify_callback() via a local function with C linkage. * glib/glibmm/propertyproxy_base.cc: Call PropertyProxyConnectionNode:: callback() and destroy_notify_handler() via local functions with C linkage. * glib/glibmm/signalproxy.cc: Call SignalProxyNormal::slot0_void_callback() and SignalProxyConnectionNode::destroy_notify_handler() via local functions with C linkage. * glib/src/binding.ccg: Add extern "C". * glib/src/bytearray.ccg: Add a TODO comment. * glib/src/markup.ccg: Call functions in the vfunc table via local functions with C linkage. * glib/src/optioncontext.ccg: Add extern "C". * glib/src/optiongroup.ccg: Call post_parse_callback() and option_arg_callback() via local functions with C linkage. Part of issue #1 --- gio/src/cancellable.ccg | 8 +++-- glib/glibmm/class.cc | 31 +++++++++++++++-- glib/glibmm/extraclassinit.h | 45 ++++++++++++++++++------ glib/glibmm/main.cc | 57 ++++++++++++++++++++++++++++--- glib/glibmm/main.h | 13 +++++-- glib/glibmm/objectbase.cc | 17 +++++++-- glib/glibmm/propertyproxy_base.cc | 22 ++++++++++-- glib/glibmm/signalproxy.cc | 49 +++++++++++++++++++++----- glib/src/binding.ccg | 10 +++--- glib/src/bytearray.ccg | 12 ++++--- glib/src/markup.ccg | 72 +++++++++++++++++++++++++++++++++++++-- glib/src/optioncontext.ccg | 4 ++- glib/src/optiongroup.ccg | 37 +++++++++++++++++--- 13 files changed, 325 insertions(+), 52 deletions(-) diff --git a/gio/src/cancellable.ccg b/gio/src/cancellable.ccg index 87d8f660..25826298 100644 --- a/gio/src/cancellable.ccg +++ b/gio/src/cancellable.ccg @@ -20,8 +20,11 @@ namespace Gio { -extern "C" { - +extern "C" +{ +// Non-static functions with C linkage get external linkage, even if they are +// defined in an anonymous namespace. +//TODO: Declare 'static' when we can break ABI. void delete_slot(gpointer data) { @@ -30,6 +33,7 @@ delete_slot(gpointer data) delete callback; } +//TODO: Declare 'static' when we can break ABI. void slot_cancelled_proxy(GCancellable* /*cancellable*/, gpointer data) { 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 #include +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 * + * 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(g_class); + * const auto css_name = static_cast(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(g_class); - * const auto css_name = static_cast(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(user_data); } +// The function pointers, glibmm_source_*_vfuncptr, are set in the Source ctor +// that calls g_source_new(const_cast(&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(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(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(&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 #include // 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 #include +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(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(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(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(after ? G_CONNECT_AFTER : 0)); return pConnectionNode->slot_; diff --git a/glib/src/binding.ccg b/glib/src/binding.ccg index ff753380..f759ab3c 100644 --- a/glib/src/binding.ccg +++ b/glib/src/binding.ccg @@ -49,7 +49,9 @@ Binding_transform_callback_common( return result; } -gboolean +extern "C" +{ +static gboolean Binding_transform_to_callback( GBinding*, const GValue* from_value, GValue* to_value, gpointer user_data) { @@ -59,7 +61,7 @@ Binding_transform_to_callback( return Binding_transform_callback_common(from_value, to_value, the_slot); } -gboolean +static gboolean Binding_transform_from_callback( GBinding*, const GValue* from_value, GValue* to_value, gpointer user_data) { @@ -69,12 +71,12 @@ Binding_transform_from_callback( return Binding_transform_callback_common(from_value, to_value, the_slot); } -void +static void Binding_transform_callback_destroy(gpointer user_data) { delete static_cast(user_data); } - +} // extern "C" } // anonymous namespace namespace Glib diff --git a/glib/src/bytearray.ccg b/glib/src/bytearray.ccg index c04fa004..393dad13 100644 --- a/glib/src/bytearray.ccg +++ b/glib/src/bytearray.ccg @@ -16,9 +16,11 @@ namespace { - -extern "C" { - +extern "C" +{ +// Non-static functions with C linkage get external linkage, even if they are +// defined in an anonymous namespace. +//TODO: Declare 'static' when we can break ABI. int ByteArray_Compare_Data_Func(gconstpointer a, gconstpointer b, gpointer user_data) { @@ -26,8 +28,8 @@ ByteArray_Compare_Data_Func(gconstpointer a, gconstpointer b, gpointer user_data return (*slot)(static_cast(a), static_cast(b)); } -} -} +} // extern "C" +} // anonymous namespace namespace Glib { diff --git a/glib/src/markup.ccg b/glib/src/markup.ccg index 408b1688..b41ba2e9 100644 --- a/glib/src/markup.ccg +++ b/glib/src/markup.ccg @@ -45,6 +45,7 @@ AttributeKeyLess::operator()(const Glib::ustring& lhs, const Glib::ustring& rhs) class ParserCallbacks { public: + //TODO: When we can break ABI, remove vfunc_table. static const GMarkupParser vfunc_table; static void start_element(GMarkupParseContext* context, const char* element_name, @@ -183,6 +184,72 @@ ParserCallbacks::error(GMarkupParseContext* context, GError* error, void* user_d } } +} // namespace Markup +} // namespace Glib + +/**** anonymous namespace *************************************************/ + +namespace +{ +using ParseContext_destroy_notify_callback_functype = void (*) (void* data); +ParseContext_destroy_notify_callback_functype ParseContext_destroy_notify_callback_funcptr; + +extern "C" +{ +static void ParseContext_destroy_notify_c_callback(void* data) +{ + ParseContext_destroy_notify_callback_funcptr(data); +} + +static void ParserCallbacks_start_element(GMarkupParseContext* context, + const char* element_name, const char** attribute_names, + const char** attribute_values, void* user_data, GError** error) +{ + Glib::Markup::ParserCallbacks::start_element(context, element_name, + attribute_names, attribute_values, user_data, error); +} + +static void ParserCallbacks_end_element(GMarkupParseContext* context, + const char* element_name, void* user_data, GError** error) +{ + Glib::Markup::ParserCallbacks::end_element(context, element_name, user_data, error); +} + +static void ParserCallbacks_text(GMarkupParseContext* context, const char* text, + gsize text_len, void* user_data, GError** error) +{ + Glib::Markup::ParserCallbacks::text(context, text, text_len, user_data, error); +} + +static void ParserCallbacks_passthrough(GMarkupParseContext* context, + const char* passthrough_text, gsize text_len, void* user_data, GError** error) +{ + Glib::Markup::ParserCallbacks::passthrough(context, passthrough_text, + text_len, user_data, error); +} + +static void ParserCallbacks_error(GMarkupParseContext* context, GError* error, + void* user_data) +{ + Glib::Markup::ParserCallbacks::error(context, error, user_data); +} + +static const GMarkupParser ParserCallbacks_vfunc_table = { + &ParserCallbacks_start_element, + &ParserCallbacks_end_element, + &ParserCallbacks_text, + &ParserCallbacks_passthrough, + &ParserCallbacks_error +}; + +} // extern "C" +} // anonymous namespace + +namespace Glib +{ +namespace Markup +{ + /**** Glib::Markup::Parser *************************************************/ Parser::Parser() @@ -233,9 +300,10 @@ Parser::on_error(ParseContext&, const MarkupError&) ParseContext::ParseContext(Parser& parser, ParseFlags flags) : parser_(&parser), - gobject_(g_markup_parse_context_new(&ParserCallbacks::vfunc_table, (GMarkupParseFlags)flags, this, - &ParseContext::destroy_notify_callback)) + gobject_(g_markup_parse_context_new(&ParserCallbacks_vfunc_table, (GMarkupParseFlags)flags, this, + &ParseContext_destroy_notify_c_callback)) { + ParseContext_destroy_notify_callback_funcptr = &destroy_notify_callback; } ParseContext::ParseContext(ParseContext&& other) noexcept : sigc::trackable(std::move(other)), diff --git a/glib/src/optioncontext.ccg b/glib/src/optioncontext.ccg index b63434e8..ad86903e 100644 --- a/glib/src/optioncontext.ccg +++ b/glib/src/optioncontext.ccg @@ -23,6 +23,8 @@ namespace Glib namespace OptionContextPrivate { +extern "C" +{ static const gchar* SignalProxy_translate_gtk_callback(const gchar* str, gpointer data) { @@ -46,7 +48,7 @@ SignalProxy_translate_gtk_callback_destroy(gpointer data) { delete static_cast(data); } - +} // extern "C" } // namespace OptionContextPrivate OptionContext::OptionContext(const Glib::ustring& parameter_string) diff --git a/glib/src/optiongroup.ccg b/glib/src/optiongroup.ccg index ee9b7bfe..543a5ab0 100644 --- a/glib/src/optiongroup.ccg +++ b/glib/src/optiongroup.ccg @@ -64,7 +64,29 @@ private: OptionArgCallback& operator=(const OptionArgCallback&); }; -extern "C" { +using OptionGroupPostParseFuncType = gboolean (*)(GOptionContext* context, + GOptionGroup* group, gpointer data, GError** error); +using OptionGroupOptionArgFuncType = gboolean (*)(const gchar* option_name, + const gchar* value, gpointer data, GError** error); +OptionGroupPostParseFuncType OptionGroup_post_parse_callback_funcptr; +OptionGroupOptionArgFuncType OptionGroup_option_arg_callback_funcptr; + +extern "C" +{ +// From functions with C linkage, to protected static member functions with C++ linkage +static gboolean +OptionGroup_post_parse_callback(GOptionContext* context, GOptionGroup* group, + gpointer data, GError** error) +{ + return OptionGroup_post_parse_callback_funcptr(context, group, data, error); +} + +static gboolean +OptionGroup_option_arg_callback(const gchar* option_name, const gchar* value, + gpointer data, GError** error) +{ + return OptionGroup_option_arg_callback_funcptr(option_name, value, data, error); +} static gboolean g_callback_pre_parse( @@ -119,6 +141,9 @@ g_callback_error( } } +// Non-static functions with C linkage get external linkage, even if they are +// defined in an anonymous namespace. +//TODO: Declare 'static' when we can break ABI. const gchar* OptionGroup_Translate_glibmm_callback(const gchar* string, gpointer data) { @@ -284,7 +309,8 @@ OptionGroup::OptionGroup(const Glib::ustring& name, const Glib::ustring& descrip // original OptionGroup instance. // Connect callbacks, so that derived classes can override the virtual methods: - g_option_group_set_parse_hooks(gobj(), &g_callback_pre_parse, &post_parse_callback); + OptionGroup_post_parse_callback_funcptr = &post_parse_callback; + g_option_group_set_parse_hooks(gobj(), &g_callback_pre_parse, &OptionGroup_post_parse_callback); g_option_group_set_error_hook(gobj(), &g_callback_error); } @@ -553,19 +579,20 @@ OptionGroup::CppOptionEntry::allocate_c_arg() { // The C arg pointer is a function pointer, cast to void*. // - // carg_ = reinterpret_cast(&OptionGroup::option_arg_callback); + // carg_ = reinterpret_cast(&OptionGroup_option_arg_callback); // or // union { // void* dp; // GOptionArgFunc fp; // } u; - // u.fp = &OptionGroup::option_arg_callback; + // u.fp = &OptionGroup_option_arg_callback; // carg_ = u.dp; // ? See // https://bugzilla.gnome.org/show_bug.cgi?id=589197 // https://github.com/libsigcplusplus/libsigcplusplus/issues/1 // https://github.com/libsigcplusplus/libsigcplusplus/issues/8 - carg_ = reinterpret_cast(&OptionGroup::option_arg_callback); + carg_ = reinterpret_cast(&OptionGroup_option_arg_callback); + OptionGroup_option_arg_callback_funcptr = &OptionGroup::option_arg_callback; break; } -- cgit v1.2.1