fix up major thinko's in ArdourCanvas::Group's handling of deletion (both its own...
authorPaul Davis <paul@linuxaudiosystems.com>
Wed, 12 Feb 2014 20:15:27 +0000 (15:15 -0500)
committerPaul Davis <paul@linuxaudiosystems.com>
Wed, 12 Feb 2014 20:15:27 +0000 (15:15 -0500)
libs/canvas/canvas/group.h
libs/canvas/group.cc

index b89f1467ba52bb5d5df163427a43fea414e7966c..94aabfded6da286198a5b992770b2732f577c4cf 100644 (file)
@@ -68,6 +68,7 @@ private:
        Group (Group const &);
        void ensure_lut () const;
        void invalidate_lut () const;
+       void clear_items (bool with_delete);
 
        /* our items, from lowest to highest in the stack */
        std::list<Item*> _items;
index bb917503f6adbe835336014e8074681f12e979ca..fbe252a17c96fc128d8ae5655237c7bb8efff1bb 100644 (file)
@@ -58,7 +58,7 @@ Group::Group (Group* parent, Duple position)
 
 Group::~Group ()
 {
-       clear (true);
+       clear_items (true);
 }
 
 /** @param area Area to draw in this group's coordinates.
@@ -199,7 +199,17 @@ Group::remove (Item* i)
                return;
        }
 
-       begin_change ();
+       /* we cannot call bounding_box() here because that will iterate over
+          _items, one of which (the argument, i) may be in the middle of
+          deletion, making it impossible to call compute_bounding_box()
+          on it.
+       */
+
+       if (_bounding_box) {
+               _pre_change_bounding_box = _bounding_box;
+       } else {
+               _pre_change_bounding_box = Rect();
+       }
 
        i->unparent ();
        _items.remove (i);
@@ -214,16 +224,7 @@ Group::clear (bool with_delete)
 {
        begin_change ();
 
-       for (list<Item*>::iterator i = _items.begin(); i != _items.end(); ++i) {
-
-               (*i)->unparent ();
-
-               if (with_delete) {
-                       delete *i;
-               }
-       }
-
-       _items.clear ();
+       clear_items (with_delete);
 
        invalidate_lut ();
        _bounding_box_dirty = true;
@@ -231,6 +232,32 @@ Group::clear (bool with_delete)
        end_change ();
 }
 
+void
+Group::clear_items (bool with_delete)
+{
+       for (list<Item*>::iterator i = _items.begin(); i != _items.end(); ) {
+
+               list<Item*>::iterator tmp = i;
+               Item *item = *i;
+
+               ++tmp;
+
+               /* remove from list before doing anything else, because we
+                * don't want to find the item in _items during any activity
+                * driven by unparent-ing or deletion.
+                */
+
+               _items.erase (i);
+               item->unparent ();
+               
+               if (with_delete) {
+                       delete item;
+               }
+
+               i = tmp;
+       }
+}
+
 void
 Group::raise_child_to_top (Item* i)
 {