[gtkmm] Gtk::Object::_release_c_instance(): Don't release if in a container



commit f75eb806f8fbdfe5455f54825c4b870787fef438
Author: Kjell Ahlstedt <kjellahlstedt gmail com>
Date:   Thu Mar 1 09:39:31 2018 +0100

    Gtk::Object::_release_c_instance(): Don't release if in a container
    
    Don't release the C instance, if it's a widget in a container widget.
    Just steal the GQuark that points from the C instance to the C++ wrapper,
    and accept that a new wrapper is later created, if necessary.
    Nowadays it's difficult to know which container the widget has been added to.
    It's not necessarily the one returned by gtk_widget_get_parent().
    Bug 773642 comments 20-22. See also gtk+ bug 786048 comment 5.

 gtk/gtkmm/object.cc |   27 +++++++++++++++++++++------
 gtk/gtkmm/object.h  |    2 +-
 2 files changed, 22 insertions(+), 7 deletions(-)
---
diff --git a/gtk/gtkmm/object.cc b/gtk/gtkmm/object.cc
index 27bf8a7..30ea269 100644
--- a/gtk/gtkmm/object.cc
+++ b/gtk/gtkmm/object.cc
@@ -92,6 +92,7 @@ void Object::_release_c_instance()
   if (object)
   {
     g_assert(G_IS_OBJECT(object));
+    bool prevent_creation_of_another_wrapper = true;
 
     if(referenced_)
     {
@@ -120,7 +121,17 @@ void Object::_release_c_instance()
         #endif
 
         g_assert(G_IS_OBJECT(object));
-        g_object_run_dispose(object); //Container widgets can respond to this.
+        if (GTK_IS_WIDGET(object) && gtk_widget_get_parent(GTK_WIDGET(object)))
+          // It's a widget which has been added to a container widget.
+          // It can't be safely destroyed, unless you know which container it
+          // was added to and remove it from there. That may or may not be its
+          // immediate parent, returned by gtk_widget_get_parent().
+          // Accept that another wrapper is possibly created if a signal
+          // is emitted or a vfunc is called.
+          // The widget will be destroyed, when the container widget is destroyed.
+          prevent_creation_of_another_wrapper = false;
+        else
+          g_object_run_dispose(object); //Container widgets can respond to this.
       }
     }
     else
@@ -132,12 +143,15 @@ void Object::_release_c_instance()
       #endif
 
       g_assert(G_IS_OBJECT(object));
-      g_object_run_dispose(object);
+      if (GTK_IS_WIDGET(object) && gtk_widget_get_parent(GTK_WIDGET(object)))
+        prevent_creation_of_another_wrapper = false;
+      else
+        g_object_run_dispose(object);
     }
 
     //If the GObject still exists, disconnect the C++ wrapper from it.
     //The C++ wrapper is being deleted right now.
-    disconnect_cpp_wrapper();
+    disconnect_cpp_wrapper(prevent_creation_of_another_wrapper);
 
     //Glib::Object::~Object() will not g_object_unref() it too. because gobject_ is now 0.
   }
@@ -166,7 +180,7 @@ Object::~Object() noexcept
   _release_c_instance();
 }
 
-void Object::disconnect_cpp_wrapper()
+void Object::disconnect_cpp_wrapper(bool prevent_creation_of_another_wrapper)
 {
   //GTKMM_LIFECYCLE:
 
@@ -181,8 +195,9 @@ void Object::disconnect_cpp_wrapper()
     //Prevent gtk vfuncs and default signal handlers from calling our instance methods:
     g_object_steal_qdata((GObject*)gobj(), Glib::quark_); //It will no longer be possible to get the C++ 
instance from the C instance.
 
-    //Allow us to prevent generation of a new C++ wrapper during destruction:
-    g_object_set_qdata((GObject*)gobj(), Glib::quark_cpp_wrapper_deleted_, (gpointer)true);
+    if (prevent_creation_of_another_wrapper)
+      //Allow us to prevent generation of a new C++ wrapper during destruction:
+      g_object_set_qdata((GObject*)gobj(), Glib::quark_cpp_wrapper_deleted_, (gpointer)true);
 
     //Prevent C++ instance from using GTK+ object:
     gobject_ = nullptr;
diff --git a/gtk/gtkmm/object.h b/gtk/gtkmm/object.h
index e4f4ba3..a818d40 100644
--- a/gtk/gtkmm/object.h
+++ b/gtk/gtkmm/object.h
@@ -117,7 +117,7 @@ protected:
   #ifndef DOXYGEN_SHOULD_SKIP_THIS
   void _init_unmanage();
   void destroy_notify_() override;
-  void disconnect_cpp_wrapper();
+  void disconnect_cpp_wrapper(bool prevent_creation_of_another_wrapper = true);
   void _release_c_instance();
 
   // set if flags used by derived classes.


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