Yet another pane pain: allow deleting children using forall_vfunc
We not only need to make sure the iterator remains valid, but also the object pointed to. Valgrind trace: Invalid read of size 8 Gtkmm2ext::Pane::forall_vfunc(int, void (*)(_GtkWidget*, void*), void*) (pane.cc:617) Gtk::Container_Class::forall_vfunc_callback(_GtkContainer*, int, void (*)(_GtkWidget*, void*), void*) gtk_container_destroy (gtkcontainer.c:1073) g_closure_invoke (gclosure.c:804) ... g_object_run_dispose (gobject.c:1084)
This commit is contained in:
parent
4ee8a0e9fc
commit
6b5dce2c66
@ -22,6 +22,7 @@
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@ -55,7 +56,7 @@ class LIBGTKMM2EXT_API Pane : public Gtk::Container
|
||||
Child (Pane* p, Gtk::Widget* widget, uint32_t ms) : pane (p), w (widget), minsize (ms) {}
|
||||
};
|
||||
|
||||
typedef std::vector<Child*> Children;
|
||||
typedef std::vector<boost::shared_ptr<Child> > Children;
|
||||
|
||||
Pane (bool horizontal);
|
||||
~Pane();
|
||||
|
@ -51,9 +51,10 @@ Pane::~Pane ()
|
||||
for (Children::iterator c = children.begin(); c != children.end(); ++c) {
|
||||
(*c)->show_con.disconnect ();
|
||||
(*c)->hide_con.disconnect ();
|
||||
(*c)->w->remove_destroy_notify_callback (*c);
|
||||
if ((*c)->w) {
|
||||
(*c)->w->remove_destroy_notify_callback ((*c).get());
|
||||
(*c)->w->unparent ();
|
||||
delete (*c);
|
||||
}
|
||||
}
|
||||
children.clear ();
|
||||
}
|
||||
@ -158,8 +159,8 @@ Pane::handle_child_visibility ()
|
||||
void
|
||||
Pane::on_add (Widget* w)
|
||||
{
|
||||
children.push_back (new Child (this, w, 0));
|
||||
Child* kid = children.back ();
|
||||
children.push_back (boost::shared_ptr<Child> (new Child (this, w, 0)));
|
||||
Child* kid = children.back ().get();
|
||||
|
||||
w->set_parent (*this);
|
||||
/* Gtkmm 2.4 does not correctly arrange for ::on_remove() to be called
|
||||
@ -190,9 +191,8 @@ Pane::child_destroyed (Gtk::Widget* w)
|
||||
if ((*c)->w == w) {
|
||||
(*c)->show_con.disconnect ();
|
||||
(*c)->hide_con.disconnect ();
|
||||
Child* kid = *c;
|
||||
(*c)->w = NULL; // mark invalid
|
||||
children.erase (c);
|
||||
delete kid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -206,11 +206,10 @@ Pane::on_remove (Widget* w)
|
||||
if ((*c)->w == w) {
|
||||
(*c)->show_con.disconnect ();
|
||||
(*c)->hide_con.disconnect ();
|
||||
w->remove_destroy_notify_callback (*c);
|
||||
w->remove_destroy_notify_callback ((*c).get());
|
||||
w->unparent ();
|
||||
Child* kid = *c;
|
||||
(*c)->w = NULL; // mark invalid
|
||||
children.erase (c);
|
||||
delete kid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -610,12 +609,11 @@ Pane::forall_vfunc (gboolean include_internals, GtkCallback callback, gpointer c
|
||||
/* since the callback could modify the child list(s), make sure we keep
|
||||
* the iterators safe;
|
||||
*/
|
||||
|
||||
for (Children::iterator c = children.begin(); c != children.end(); ) {
|
||||
Children::iterator next = c;
|
||||
++next;
|
||||
Children kids (children);
|
||||
for (Children::const_iterator c = kids.begin(); c != kids.end(); ++c) {
|
||||
if ((*c)->w) {
|
||||
callback ((*c)->w->gobj(), callback_data);
|
||||
c = next;
|
||||
}
|
||||
}
|
||||
|
||||
if (include_internals) {
|
||||
|
Loading…
Reference in New Issue
Block a user