[glibmm] gmmproc: Improved handling of final types



commit a41d6e28461bad90fdb78756344daa7c7d9db1dd
Author: Kjell Ahlstedt <kjellahlstedt gmail com>
Date:   Wed Jun 8 18:33:59 2022 +0200

    gmmproc: Improved handling of final types
    
    Some GObject-derived classes shall not be derived from.
    
    * glib/glibmm/class.cc:
    * glib/glibmm/interface.cc: Don't derive or add interfaces to a class
    if G_TYPE_IS_FINAL(gtype) is true.
    * tools/m4/class_shared.m4: Fix gtype_ when _DO_NOT_DERIVE_GTYPE is used.
    Add _ABI_AS_WITH_DERIVED_GTYPE, making it possible to
    add _DO_NOT_DERIVE_GTYPE without breaking ABI.

 glib/glibmm/class.cc     |  9 ++++++++
 glib/glibmm/interface.cc |  7 ++++++
 tools/m4/class_shared.m4 | 57 +++++++++++++++++++++++++++++++++++++++++-------
 3 files changed, 65 insertions(+), 8 deletions(-)
---
diff --git a/glib/glibmm/class.cc b/glib/glibmm/class.cc
index 36c3c4be..31f92c61 100644
--- a/glib/glibmm/class.cc
+++ b/glib/glibmm/class.cc
@@ -42,6 +42,15 @@ Class::register_derived_type(GType base_type, GTypeModule* module)
   if (base_type == 0)
     return; // already initialized
 
+#if GLIB_CHECK_VERSION(2,70,0)
+  // Don't derive a type if the base type is a final type.
+  if (G_TYPE_IS_FINAL(base_type))
+  {
+    gtype_ = base_type;
+    return;
+  }
+#endif
+
   GTypeQuery base_query = {
     0, nullptr, 0, 0,
   };
diff --git a/glib/glibmm/interface.cc b/glib/glibmm/interface.cc
index f01f13dc..eec50e3a 100644
--- a/glib/glibmm/interface.cc
+++ b/glib/glibmm/interface.cc
@@ -25,6 +25,13 @@ namespace Glib
 void
 Interface_Class::add_interface(GType instance_type) const
 {
+#if GLIB_CHECK_VERSION(2,70,0)
+  // If instance_type is a final type, it has not been registered by
+  // Glib::Class::register_derived_type(). Don't add an interface.
+  if (G_TYPE_IS_FINAL(instance_type))
+    return;
+#endif
+
   // This check is disabled, because it checks whether any of the types's bases implement the
   // interface, not just the specific type.
   // if( !g_type_is_a(instance_type, gtype_) ) //For convenience, don't complain about calling this
diff --git a/tools/m4/class_shared.m4 b/tools/m4/class_shared.m4
index 587a1f2f..1dab09d0 100644
--- a/tools/m4/class_shared.m4
+++ b/tools/m4/class_shared.m4
@@ -1,5 +1,5 @@
-dnl $Id$
-
+dnl If you change this file, check if there is a copy of it
+dnl at gtkmm/tools/m4/ that you shall also change.
 
 dnl This is just a hint to generate_wrap_init.pl.
 dnl It does not generate any code in the actual .h and .cc file.
@@ -57,7 +57,7 @@ ifelse(`$2',,,`
 _POP()
 ')
 
-dnl GVolumeMonitor can be broken/impeded by defining a sub-type.
+dnl Use if the C base type is declared G_DECLARE_FINAL_TYPE.
 define(`_DO_NOT_DERIVE_GTYPE',`dnl
 _PUSH()
 dnl Define this macro to be tested for later.
@@ -65,7 +65,14 @@ define(`__BOOL_DO_NOT_DERIVE_GTYPE__',`$1')
 _POP()
 ')
 
-dnl GVolumeMonitor can be broken/impeded by defining a sub-type.
+dnl If you add _DO_NOT_DERIVE_GTYPE to an existing class, and ABI must not be broken.
+define(`_ABI_AS_WITH_DERIVED_GTYPE',`dnl
+_PUSH()
+dnl Define this macro to be tested for later.
+define(`__BOOL_ABI_AS_WITH_DERIVED_GTYPE__',`$1')
+_POP()
+')
+
 define(`_DYNAMIC_GTYPE_REGISTRATION',`dnl
 _PUSH()
 dnl Define this macro to be tested for later.
@@ -108,8 +115,13 @@ public:
   using CppObjectType = __CPPNAME__;
   using BaseObjectType = __REAL_CNAME__;
 ifdef(`__BOOL_DO_NOT_DERIVE_GTYPE__',`dnl
+ifdef(`__BOOL_ABI_AS_WITH_DERIVED_GTYPE__',`dnl
+  using BaseClassType = __REAL_CNAME__`'Class;
   using CppClassParent = __CPPPARENT__`'_Class;
+  using BaseClassParent = __REAL_CPARENT__`'Class;
 ',`dnl
+  using CppClassParent = __CPPPARENT__`'_Class;
+')',`dnl
   using BaseClassType = __REAL_CNAME__`'Class;
   using CppClassParent = __CPPPARENT__`'_Class;
   using BaseClassParent = __REAL_CPARENT__`'Class;
@@ -125,7 +137,10 @@ ifdef(`__BOOL_DYNAMIC_GTYPE_REGISTRATION__',`
 ',`')
 
 ifdef(`__BOOL_DO_NOT_DERIVE_GTYPE__',`dnl
+ifdef(`__BOOL_ABI_AS_WITH_DERIVED_GTYPE__',`dnl
+  static void class_init_function(void* g_class, void* class_data);
 ',`dnl
+')',`dnl
   static void class_init_function(void* g_class, void* class_data);
 ')dnl
 
@@ -153,9 +168,16 @@ const Glib::Class& __CPPNAME__`'_Class::init()
   if(!gtype_) // create the GType if necessary
   {
 ifdef(`__BOOL_DO_NOT_DERIVE_GTYPE__',`dnl
-    // Do not derive a GType, or use a derived klass:
-    gtype_ = CppClassParent::CppObjectType::get_type();
+ifdef(`__BOOL_ABI_AS_WITH_DERIVED_GTYPE__',`dnl
+    // Glib::Class has to know the class init function to clone custom types.
+    class_init_func_ = &__CPPNAME__`'_Class::class_init_function;
+
+    // Do not derive a GType, or use a derived class:
+    gtype_ = _LOWER(__CCAST__)_get_type();
 ',`dnl
+    // Do not derive a GType, or use a derived class:
+    gtype_ = _LOWER(__CCAST__)_get_type();
+')',`dnl not __BOOL_DO_NOT_DERIVE_GTYPE__
     // Glib::Class has to know the class init function to clone custom types.
     class_init_func_ = &__CPPNAME__`'_Class::class_init_function;
 
@@ -180,9 +202,16 @@ const Glib::Class& __CPPNAME__`'_Class::init(GTypeModule* module)
   if(!gtype_) // create the GType if necessary
   {
 ifdef(`__BOOL_DO_NOT_DERIVE_GTYPE__',`dnl
-    // Do not derive a GType, or use a derived klass:
-    gtype_ = CppClassParent::CppObjectType::get_type();
+ifdef(`__BOOL_ABI_AS_WITH_DERIVED_GTYPE__',`dnl
+    // Glib::Class has to know the class init function to clone custom types.
+    class_init_func_ = &__CPPNAME__`'_Class::class_init_function;
+
+    // Do not derive a GType, or use a derived class:
+    gtype_ = _LOWER(__CCAST__)_get_type();
 ',`dnl
+    // Do not derive a GType, or use a derived class:
+    gtype_ = _LOWER(__CCAST__)_get_type();
+')',`dnl
     // Glib::Class has to know the class init function to clone custom types.
     class_init_func_ = &__CPPNAME__`'_Class::class_init_function;
 
@@ -202,7 +231,19 @@ _IMPORT(SECTION_CC_IMPLEMENTS_INTERFACES)
 ',`')
 
 ifdef(`__BOOL_DO_NOT_DERIVE_GTYPE__',`dnl
+ifdef(`__BOOL_ABI_AS_WITH_DERIVED_GTYPE__',`dnl
+
+void __CPPNAME__`'_Class::class_init_function(void* g_class, void* class_data)
+{
+  const auto klass = static_cast<BaseClassType*>(g_class);
+  CppClassParent::class_init_function(klass, class_data);
+
+_IMPORT(SECTION_PCC_CLASS_INIT_VFUNCS)
+
+_IMPORT(SECTION_PCC_CLASS_INIT_DEFAULT_SIGNAL_HANDLERS)
+}
 ',`dnl
+')',`dnl not __BOOL_DO_NOT_DERIVE_GTYPE__
 
 void __CPPNAME__`'_Class::class_init_function(void* g_class, void* class_data)
 {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]