summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjell Ahlstedt <kjellahlstedt@gmail.com>2023-03-31 15:24:13 +0200
committerKjell Ahlstedt <kjellahlstedt@gmail.com>2023-03-31 15:24:13 +0200
commit98f3b67b5c1bd71d0e7b41193fb4683fc957e321 (patch)
tree1fa8a4cf1bf9a93a79bfe08be83426bb15da01e9
parentb7ad9b86d70003c065606c563578cc66dcd2ce0a (diff)
downloadglibmm-98f3b67b5c1bd71d0e7b41193fb4683fc957e321.tar.gz
Glib: Use callback functions with C linkageglibmm-2-76
* 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
-rw-r--r--gio/src/cancellable.ccg8
-rw-r--r--glib/glibmm/class.cc31
-rw-r--r--glib/glibmm/extraclassinit.h45
-rw-r--r--glib/glibmm/main.cc57
-rw-r--r--glib/glibmm/main.h13
-rw-r--r--glib/glibmm/objectbase.cc17
-rw-r--r--glib/glibmm/propertyproxy_base.cc22
-rw-r--r--glib/glibmm/signalproxy.cc49
-rw-r--r--glib/src/binding.ccg10
-rw-r--r--glib/src/bytearray.ccg12
-rw-r--r--glib/src/markup.ccg72
-rw-r--r--glib/src/optioncontext.ccg4
-rw-r--r--glib/src/optiongroup.ccg37
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 <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_;
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<BindingTransformSlots*>(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<const guint8*>(a), static_cast<const guint8*>(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<Glib::OptionContext::SlotTranslate*>(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<void*>(&OptionGroup::option_arg_callback);
+ // carg_ = reinterpret_cast<void*>(&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<void*>(&OptionGroup::option_arg_callback);
+ carg_ = reinterpret_cast<void*>(&OptionGroup_option_arg_callback);
+ OptionGroup_option_arg_callback_funcptr = &OptionGroup::option_arg_callback;
break;
}