summaryrefslogtreecommitdiff
path: root/glib/glibmm
diff options
context:
space:
mode:
Diffstat (limited to 'glib/glibmm')
-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
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_;