summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKjell Ahlstedt <kjellahlstedt@gmail.com>2023-04-02 15:05:14 +0200
committerKjell Ahlstedt <kjellahlstedt@gmail.com>2023-04-02 15:05:14 +0200
commitf357827e113ca2d3c3f9758ec572bd8325cc5847 (patch)
treeb2cff8a551149e65664c3af349acde44da1e2b50
parent07fbd1f0e0a68fb3b130fe9d0b0f5f338346746a (diff)
downloadglibmm-f357827e113ca2d3c3f9758ec572bd8325cc5847.tar.gz
Glib: NodeTree etc.: Use callback functions with C linkage
* glib/glibmm/class.cc: Use glibmm_custom_[get|set]_property_callback(). * glib/glibmm/object.[cc|h]: Add set_data_with_c_callback(). Don't call g_object_set_qdata_full() with a function with C++ linkage, if GLIBMM_CAN_ASSIGN_NON_EXTERN_C_FUNCTIONS_TO_EXTERN_C_CALLBACKS is defined. * glib/glibmm/property.[cc|h]: Declare some local functions extern "C". Add glibmm_custom_[get|set]_property_callback(). * glib/src/nodetree.[ccg|hg]: Add glibmm_NodeTree_c_callback_[traverse|foreach]() and struct NodeTreeCallback[Traverse|Foreach]Data. Part of issue #1
-rw-r--r--glib/glibmm/class.cc7
-rw-r--r--glib/glibmm/object.cc16
-rw-r--r--glib/glibmm/object.h10
-rw-r--r--glib/glibmm/property.cc34
-rw-r--r--glib/glibmm/property.h17
-rw-r--r--glib/src/nodetree.ccg38
-rw-r--r--glib/src/nodetree.hg39
7 files changed, 144 insertions, 17 deletions
diff --git a/glib/glibmm/class.cc b/glib/glibmm/class.cc
index 5344f381..1080f1ce 100644
--- a/glib/glibmm/class.cc
+++ b/glib/glibmm/class.cc
@@ -233,8 +233,8 @@ Class::custom_class_init_function(void* g_class, void* class_data)
(*init_func)(g_class, nullptr);
GObjectClass* const gobject_class = static_cast<GObjectClass*>(g_class);
- gobject_class->get_property = &Glib::custom_get_property_callback;
- gobject_class->set_property = &Glib::custom_set_property_callback;
+ gobject_class->get_property = &Glib::glibmm_custom_get_property_callback;
+ gobject_class->set_property = &Glib::glibmm_custom_set_property_callback;
// Call extra class init functions, if any.
for (std::size_t i = 1; i < class_init_funcs.size(); ++i)
@@ -277,7 +277,8 @@ Class::custom_class_init_function(void* g_class, void* class_data)
// Override only properties which have not been overridden in a base class.
// Store the default values belonging to the class.
- // They are copied to an object in custom_set_property_callback() in property.cc.
+ // They are copied to an object in glibmm_custom_set_property_callback()
+ // in property.cc.
if (!g_object_class_find_property(gobject_class, prop_name))
{
GValue* g_value = g_new0(GValue, 1);
diff --git a/glib/glibmm/object.cc b/glib/glibmm/object.cc
index 4dc73b31..30703d7d 100644
--- a/glib/glibmm/object.cc
+++ b/glib/glibmm/object.cc
@@ -283,10 +283,26 @@ Object::set_data(const Quark& id, void* data)
}
void
+Object::set_data_with_c_callback(const Quark& id, void* data, GDestroyNotify destroy)
+{
+ g_object_set_qdata_full(gobj(), id, data, destroy);
+}
+
+#ifdef GLIBMM_CAN_ASSIGN_NON_EXTERN_C_FUNCTIONS_TO_EXTERN_C_CALLBACKS
+void
Object::set_data(const Quark& id, void* data, DestroyNotify destroy)
{
g_object_set_qdata_full(gobj(), id, data, destroy);
}
+#else
+void
+Object::set_data(const Quark& id, void* data, DestroyNotify)
+{
+ g_object_set_qdata(gobj(), id, data);
+ g_critical("Can't assign a callback with C++ linkage to g_object_set_qdata_full().\n"
+ "Use Glib::Object::set_data_with_c_callback().\n");
+}
+#endif
void
Object::remove_data(const QueryQuark& id)
diff --git a/glib/glibmm/object.h b/glib/glibmm/object.h
index 6db4b5cb..4cb6ad91 100644
--- a/glib/glibmm/object.h
+++ b/glib/glibmm/object.h
@@ -33,7 +33,7 @@
#include <glibmm/utility.h> /* Could be private, but that would be tedious. */
#include <glibmm/containerhandle_shared.h> /* Because its specializations may be here. */
#include <glibmm/value.h>
-#include <glib.h> /* for G_GNUC_NULL_TERMINATED */
+#include <glib.h> // for G_GNUC_NULL_TERMINATED and GDestroyNotify
#ifndef DOXYGEN_SHOULD_SKIP_THIS
extern "C" {
@@ -118,12 +118,14 @@ public:
// GObject* gobj_copy(); //Give a ref-ed copy to someone. Use for direct struct access.
- // Glib::Objects contain a list<Quark, pair<void*, DestroyNotify> >
- // to store run time data added to the object at run time.
- // TODO: Use slots instead:
+ // TODO: When we can break ABI and API, remove DestroyNotify and the
+ // set_data() that uses it. Rename set_data_with_c_callback() to set_data().
void* get_data(const QueryQuark& key);
void set_data(const Quark& key, void* data);
using DestroyNotify = void (*)(gpointer data);
+ /** @newin{2,78} */
+ void set_data_with_c_callback(const Quark& key, void* data, GDestroyNotify notify);
+ /** Prefer set_data_with_c_callback() with a callback with C linkage. */
void set_data(const Quark& key, void* data, DestroyNotify notify);
void remove_data(const QueryQuark& quark);
// same as remove without notifying
diff --git a/glib/glibmm/property.cc b/glib/glibmm/property.cc
index 56dad849..6cb5f317 100644
--- a/glib/glibmm/property.cc
+++ b/glib/glibmm/property.cc
@@ -61,8 +61,10 @@ namespace
// a) Almost all conceivable use-cases are supported by this approach.
// b) It's comparatively efficient, and does not need a hash-table lookup.
+extern "C"
+{
// Delete the interface property values when an object of a custom type is finalized.
-void
+static void
destroy_notify_obj_iface_props(void* data)
{
auto obj_iface_props = static_cast<Glib::Class::iface_properties_type*>(data);
@@ -76,6 +78,7 @@ destroy_notify_obj_iface_props(void* data)
delete obj_iface_props;
}
}
+} // extern "C"
struct custom_properties_type
{
@@ -92,8 +95,10 @@ struct custom_properties_type
static const GQuark custom_properties_quark =
g_quark_from_string("gtkmm_CustomObject_custom_properties");
+extern "C"
+{
// Delete the custom properties data when an object of a custom type is finalized.
-void destroy_notify_obj_custom_props(void* data)
+static void destroy_notify_obj_custom_props(void* data)
{
auto obj_custom_props = static_cast<custom_properties_type*>(data);
// prop_base_vector does not own the objects pointed to.
@@ -106,6 +111,7 @@ void destroy_notify_obj_custom_props(void* data)
}
delete obj_custom_props;
}
+} // extern "C"
custom_properties_type*
get_obj_custom_props(GObject* obj)
@@ -125,11 +131,30 @@ get_obj_custom_props(GObject* obj)
namespace Glib
{
-
void
custom_get_property_callback(
GObject* object, unsigned int property_id, GValue* value, GParamSpec* param_spec)
{
+ glibmm_custom_get_property_callback(object, property_id, value, param_spec);
+}
+
+void
+custom_set_property_callback(
+ GObject* object, unsigned int property_id, const GValue* value, GParamSpec* param_spec)
+{
+ glibmm_custom_set_property_callback(object, property_id, value, param_spec);
+}
+
+extern "C"
+{
+// A function with external linkage and C linkage does not get a mangled name.
+// Even though glibmm_custom_get_property_callback() and glibmm_custom_set_property_callback()
+// are declared in a named namespace, the linker does not see the namespace name.
+// Therefore the function names shall have a prefix, hopefully unique.
+void
+glibmm_custom_get_property_callback(
+ GObject* object, unsigned int property_id, GValue* value, GParamSpec* param_spec)
+{
// If the id is zero there is no property to get.
g_return_if_fail(property_id != 0);
@@ -185,7 +210,7 @@ custom_get_property_callback(
}
void
-custom_set_property_callback(
+glibmm_custom_set_property_callback(
GObject* object, unsigned int property_id, const GValue* value, GParamSpec* param_spec)
{
// If the id is zero there is no property to set.
@@ -262,6 +287,7 @@ custom_set_property_callback(
}
}
}
+} // extern "C"
/**** Glib::PropertyBase ***************************************************/
diff --git a/glib/glibmm/property.h b/glib/glibmm/property.h
index daf92eca..5f553ccf 100644
--- a/glib/glibmm/property.h
+++ b/glib/glibmm/property.h
@@ -26,6 +26,7 @@ namespace Glib
#ifndef DOXYGEN_SHOULD_SKIP_THIS
+// TODO: When we can break ABI, remove custom_[get|set]_property_callback().
#ifdef GLIBMM_CXX_CAN_USE_NAMESPACES_INSIDE_EXTERNC
// For the AIX xlC compiler, I can not find a way to do this without putting the functions in the
// global namespace. murrayc
@@ -44,6 +45,18 @@ void custom_set_property_callback(
} // extern "C"
#endif // GLIBMM_CXX_CAN_USE_NAMESPACES_INSIDE_EXTERNC
+extern "C"
+{
+GLIBMM_API
+void glibmm_custom_get_property_callback(
+ GObject* object, unsigned int property_id, GValue* value, GParamSpec* param_spec);
+
+GLIBMM_API
+void glibmm_custom_set_property_callback(
+ GObject* object, unsigned int property_id, const GValue* value, GParamSpec* param_spec);
+
+} // extern "C"
+
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
/** This is the base class for Glib::Object properties.
@@ -109,10 +122,10 @@ protected:
private:
#ifndef DOXYGEN_SHOULD_SKIP_THIS
- friend void Glib::custom_get_property_callback(
+ friend void Glib::glibmm_custom_get_property_callback(
GObject* object, unsigned int property_id, GValue* value, GParamSpec* param_spec);
- friend void Glib::custom_set_property_callback(
+ friend void Glib::glibmm_custom_set_property_callback(
GObject* object, unsigned int property_id, const GValue* value, GParamSpec* param_spec);
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
diff --git a/glib/src/nodetree.ccg b/glib/src/nodetree.ccg
index 6ee2218c..dbfc52e5 100644
--- a/glib/src/nodetree.ccg
+++ b/glib/src/nodetree.ccg
@@ -1 +1,39 @@
+/* Copyright (C) 2007 glibmm development team
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
#include <glibmm/nodetree.h>
+
+namespace Glib
+{
+extern "C"
+{
+// A function with external linkage and C linkage does not get a mangled name.
+// Even though glibmm_NodeTree_c_callback_traverse() and glibmm_NodeTree_c_callback_foreach()
+// are declared in a named namespace, the linker does not see the namespace name.
+// Therefore the function names shall have a prefix, hopefully unique.
+gboolean glibmm_NodeTree_c_callback_traverse(GNode* node, gpointer data)
+{
+ auto traverse_data = reinterpret_cast<NodeTreeCallbackTraverseData*>(data);
+ return (*traverse_data->func)(node, traverse_data->data);
+}
+
+void glibmm_NodeTree_c_callback_foreach(GNode* node, gpointer data)
+{
+ auto foreach_data = reinterpret_cast<NodeTreeCallbackForeachData*>(data);
+ (*foreach_data->func)(node, foreach_data->data);
+}
+} // extern "C"
+} // namespace Glib
diff --git a/glib/src/nodetree.hg b/glib/src/nodetree.hg
index 300b7f31..62353574 100644
--- a/glib/src/nodetree.hg
+++ b/glib/src/nodetree.hg
@@ -29,6 +29,33 @@ _DEFS(glibmm,glib)
namespace Glib
{
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+extern "C"
+{
+/// Wrapper for invoking a TraverseFunc.
+gboolean glibmm_NodeTree_c_callback_traverse(GNode* node, gpointer data);
+
+/// Wrapper for invoking a ForeachFunc.
+void glibmm_NodeTree_c_callback_foreach(GNode* node, gpointer data);
+
+} // extern "C"
+
+// Like GNodeTraverseFunc and GNodeForeachFunc, but with C++ linkage.
+using NodeTreeCallbackTraverseFuncType = gboolean (*)(GNode *node, gpointer user_data);
+using NodeTreeCallbackForeachFuncType = void (*)(GNode *node, gpointer user_data);
+
+struct NodeTreeCallbackTraverseData
+{
+ NodeTreeCallbackTraverseFuncType func;
+ gpointer data;
+};
+
+struct NodeTreeCallbackForeachData
+{
+ NodeTreeCallbackForeachFuncType func;
+ gpointer data;
+};
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
/** N-ary Trees - trees of data with any number of branches
* The NodeTree class and its associated functions provide an N-ary tree data structure, in which nodes in the tree can contain arbitrary data.
@@ -300,7 +327,8 @@ public:
void traverse(const TraverseFunc& func, TraverseType order = TraverseType::IN_ORDER, TraverseFlags flags = TraverseFlags::ALL, int max_depth = -1)
{
TraverseFunc func_copy = func;
- g_node_traverse(gobj(), (GTraverseType)order, (GTraverseFlags)flags, max_depth, c_callback_traverse, reinterpret_cast<gpointer>(&func_copy));
+ NodeTreeCallbackTraverseData traverse_data = { &c_callback_traverse, &func_copy };
+ g_node_traverse(gobj(), (GTraverseType)order, (GTraverseFlags)flags, max_depth, glibmm_NodeTree_c_callback_traverse, &traverse_data);
}
_IGNORE(g_node_traverse);
@@ -313,7 +341,8 @@ public:
void foreach(const ForeachFunc& func, TraverseFlags flags = TraverseFlags::ALL)
{
ForeachFunc func_copy = func;
- g_node_children_foreach(gobj(), (GTraverseFlags)flags, c_callback_foreach, reinterpret_cast<gpointer>(&func_copy));
+ NodeTreeCallbackForeachData foreach_data = { &c_callback_foreach, &func_copy };
+ g_node_children_foreach(gobj(), (GTraverseFlags)flags, glibmm_NodeTree_c_callback_foreach, &foreach_data);
}
_IGNORE(g_node_children_foreach)
@@ -331,7 +360,8 @@ public:
using type_foreach_gnode_slot = sigc::slot<void(GNode*)>;
type_foreach_gnode_slot bound_slot = sigc::bind(real_slot, the_data, &child);
- g_node_children_foreach(gobj(), (GTraverseFlags)flags, c_callback_foreach_compare_child, reinterpret_cast<gpointer>(&bound_slot));
+ NodeTreeCallbackForeachData foreach_data = { &c_callback_foreach_compare_child, &bound_slot };
+ g_node_children_foreach(gobj(), (GTraverseFlags)flags, glibmm_NodeTree_c_callback_foreach, &foreach_data);
return wrap(child);
}
@@ -365,7 +395,8 @@ public:
using type_traverse_gnode_slot = sigc::slot<gboolean(GNode*)>;
type_traverse_gnode_slot bound_slot = sigc::bind(real_slot, the_data, &child);
- g_node_traverse(const_cast<GNode*>(gobj()), (GTraverseType)order, (GTraverseFlags)flags, -1, c_callback_traverse_compare_node, reinterpret_cast<gpointer>(&bound_slot));
+ NodeTreeCallbackTraverseData traverse_data = { &c_callback_traverse_compare_node, &bound_slot };
+ g_node_traverse(const_cast<GNode*>(gobj()), (GTraverseType)order, (GTraverseFlags)flags, -1, glibmm_NodeTree_c_callback_traverse, &traverse_data);
return wrap(child);
}