# HG changeset patch
# User Markus Mützel <markus.muetzel@gmx.de>
# Date 1552771286 -3600
#      Sat Mar 16 22:21:26 2019 +0100
# Node ID ead8f91c55562771ea70f3198257bc7b3962e0bd
# Parent  c8055304ad211652b2475d8a4637788f5ca398b9
Improve performance when closing figures (bug #55908).

* graphics.cc (gh_manager::do_free): Don't execute remove_child when deleting
  from groot.
* graphics.[cc,in.h] (delete_children, free): Add optional argument to indicate
  that an object is deleted from graphics root.

diff -r c8055304ad21 -r ead8f91c5556 libinterp/corefcn/graphics.cc
--- a/libinterp/corefcn/graphics.cc	Sat Mar 16 09:56:00 2019 -0700
+++ b/libinterp/corefcn/graphics.cc	Sat Mar 16 22:21:26 2019 +0100
@@ -1798,10 +1798,16 @@
 }
 
 void
-children_property::do_delete_children (bool clear)
-{
-  while (! children_list.empty ())
-    gh_manager::free (children_list.front ());
+children_property::do_delete_children (bool clear, bool from_root)
+{
+  for (graphics_handle hchild : children_list)
+    {
+      graphics_object go = gh_manager::get_object (hchild);
+
+      if (hchild.value () > 0 && go.valid_object ()
+          && ! go.get_properties ().is_beingdeleted ())
+        gh_manager::free (hchild, from_root);
+    }
 
   if (clear)
     children_list.clear ();
@@ -2746,7 +2752,7 @@
 }
 
 void
-gh_manager::do_free (const graphics_handle& h)
+gh_manager::do_free (const graphics_handle& h, bool from_root)
 {
   if (h.ok ())
     {
@@ -2764,7 +2770,9 @@
         return;
 
       graphics_handle parent_h = p->second.get_parent ();
-      graphics_object parent_go = gh_manager::get_object (parent_h);
+      graphics_object parent_go = nullptr;
+      if (! from_root)
+        parent_go = gh_manager::get_object (parent_h);
 
       bp.set_beingdeleted (true);
 
@@ -2781,9 +2789,11 @@
       // Notify graphics toolkit.
       p->second.finalize ();
 
-      // NOTE: Call remove_child before erasing the go from the map.
+
+      // NOTE: Call remove_child before erasing the go from the map if not
+      // removing from groot.
       // A callback function might have already deleted the parent
-      if (parent_go.valid_object () && h.ok ())
+      if (! from_root && parent_go.valid_object () && h.ok ())
         parent_go.remove_child (h);
 
       // Note: this will be valid only for first explicitly deleted
@@ -2910,7 +2920,7 @@
 }
 
 static void
-delete_graphics_object (const graphics_handle& h)
+delete_graphics_object (const graphics_handle& h, bool from_root = false)
 {
   if (h.ok ())
     {
@@ -2922,7 +2932,7 @@
           // NOTE: Freeing the handle also calls any deletefcn.  It also calls
           //       the parent's delete_child function.
 
-          gh_manager::free (h);
+          gh_manager::free (h, from_root);
 
           Vdrawnow_requested = true;
         }
@@ -2930,16 +2940,16 @@
 }
 
 static void
-delete_graphics_object (double val)
-{
-  delete_graphics_object (gh_manager::lookup (val));
+delete_graphics_object (double val, bool from_root = false)
+{
+  delete_graphics_object (gh_manager::lookup (val), from_root);
 }
 
 // Flag to stop redraws due to callbacks while deletion is in progress.
 static bool delete_executing = false;
 
 static void
-delete_graphics_objects (const NDArray vals)
+delete_graphics_objects (const NDArray vals, bool from_root = false)
 {
   // Prevent redraw of partially deleted objects.
   octave::unwind_protect frame;
@@ -2947,7 +2957,7 @@
   delete_executing = true;
 
   for (octave_idx_type i = 0; i < vals.numel (); i++)
-    delete_graphics_object (vals.elem (i));
+    delete_graphics_object (vals.elem (i), from_root);
 }
 
 static void
@@ -2967,7 +2977,7 @@
   xset (h, "deletefcn", Matrix ());
   xset (h, "closerequestfcn", Matrix ());
 
-  delete_graphics_object (h);
+  delete_graphics_object (h, true);
 }
 
 void
@@ -3926,7 +3936,7 @@
 */
 
 void
-root_figure::properties::remove_child (const graphics_handle& h)
+root_figure::properties::remove_child (const graphics_handle& h, bool)
 {
   gh_manager::pop_figure (h);
 
@@ -3934,7 +3944,7 @@
 
   xset (0, "currentfigure", cf.value ());
 
-  base_properties::remove_child (h);
+  base_properties::remove_child (h, true);
 }
 
 void
@@ -3962,9 +3972,9 @@
 }
 
 void
-figure::properties::remove_child (const graphics_handle& h)
-{
-  base_properties::remove_child (h);
+figure::properties::remove_child (const graphics_handle& h, bool from_root)
+{
+  base_properties::remove_child (h, from_root);
 
   if (h == currentaxes.handle_value ())
     {
@@ -5483,7 +5493,7 @@
 }
 
 void
-axes::properties::delete_text_child (handle_property& hp)
+axes::properties::delete_text_child (handle_property& hp, bool from_root)
 {
   graphics_handle h = hp.handle_value ();
 
@@ -5492,7 +5502,7 @@
       graphics_object go = gh_manager::get_object (h);
 
       if (go.valid_object ())
-        gh_manager::free (h);
+        gh_manager::free (h, from_root);
     }
 
   // FIXME: is it necessary to check whether the axes object is
@@ -5512,36 +5522,36 @@
 }
 
 void
-axes::properties::remove_child (const graphics_handle& h)
+axes::properties::remove_child (const graphics_handle& h, bool from_root)
 {
   graphics_object go = gh_manager::get_object (h);
 
-  if (go.isa ("light") && go.get_properties ().is_visible ())
-    decrease_num_lights ();
-
   if (xlabel.handle_value ().ok () && h == xlabel.handle_value ())
     {
-      delete_text_child (xlabel);
+      delete_text_child (xlabel, from_root);
       update_xlabel_position ();
     }
   else if (ylabel.handle_value ().ok () && h == ylabel.handle_value ())
     {
-      delete_text_child (ylabel);
+      delete_text_child (ylabel, from_root);
       update_ylabel_position ();
     }
   else if (zlabel.handle_value ().ok () && h == zlabel.handle_value ())
     {
-      delete_text_child (zlabel);
+      delete_text_child (zlabel, from_root);
       update_zlabel_position ();
     }
   else if (title.handle_value ().ok () && h == title.handle_value ())
     {
-      delete_text_child (title);
+      delete_text_child (title, from_root);
       update_title_position ();
     }
+  else if (get_num_lights () > 0 && go.isa ("light")
+           && go.get_properties ().is_visible ())
+    decrease_num_lights ();
 
   if (go.valid_object ())
-      base_properties::remove_child (h);
+    base_properties::remove_child (h, from_root);
 
 }
 
@@ -10198,17 +10208,17 @@
 // ---------------------------------------------------------------------
 
 void
-hggroup::properties::remove_child (const graphics_handle& h)
+hggroup::properties::remove_child (const graphics_handle& h, bool from_root)
 {
   graphics_object go = gh_manager::get_object (h);
-  if (go.isa ("light") && go.get_properties ().is_visible ())
+  if (! from_root && go.isa ("light") && go.get_properties ().is_visible ())
     {
       axes::properties& ax_props =
         dynamic_cast<axes::properties&>
         (go.get_ancestor ("axes").get_properties ());
       ax_props.decrease_num_lights ();
     }
-  base_properties::remove_child (h);
+  base_properties::remove_child (h, from_root);
   update_limits ();
 }
 
diff -r c8055304ad21 -r ead8f91c5556 libinterp/corefcn/graphics.in.h
--- a/libinterp/corefcn/graphics.in.h	Sat Mar 16 09:56:00 2019 -0700
+++ b/libinterp/corefcn/graphics.in.h	Sat Mar 16 22:21:26 2019 +0100
@@ -1759,9 +1759,9 @@
     return octave_value (get_children ());
   }
 
-  void delete_children (bool clear = false)
-  {
-    do_delete_children (clear);
+  void delete_children (bool clear = false, bool from_root = false)
+  {
+    do_delete_children (clear, from_root);
   }
 
   void renumber (graphics_handle old_gh, graphics_handle new_gh)
@@ -1885,7 +1885,7 @@
     children_list.push_front (val);
   }
 
-  void do_delete_children (bool clear);
+  void do_delete_children (bool clear, bool from_root);
 };
 
 // ---------------------------------------------------------------------
@@ -2234,7 +2234,7 @@
 
   bool is_modified (void) const { return is___modified__ (); }
 
-  virtual void remove_child (const graphics_handle& h)
+  virtual void remove_child (const graphics_handle& h, bool = false)
   {
     if (children.remove_child (h.value ()))
       {
@@ -2306,9 +2306,9 @@
 
   virtual void update_uicontextmenu (void) const;
 
-  virtual void delete_children (bool clear = false)
-  {
-    children.delete_children (clear);
+  virtual void delete_children (bool clear = false, bool from_root = false)
+  {
+    children.delete_children (clear, from_root);
   }
 
   void renumber_child (graphics_handle old_gh, graphics_handle new_gh)
@@ -2541,12 +2541,12 @@
     return get_properties ().get___myhandle__ ();
   }
 
-  virtual void remove_child (const graphics_handle& h)
+  virtual void remove_child (const graphics_handle& h, bool from_root = false)
   {
     if (! valid_object ())
       error ("base_graphics_object::remove_child: invalid graphics object");
 
-    get_properties ().remove_child (h);
+    get_properties ().remove_child (h, from_root);
   }
 
   virtual void adopt (const graphics_handle& h)
@@ -2895,7 +2895,7 @@
   class OCTINTERP_API properties : public base_properties
   {
   public:
-    void remove_child (const graphics_handle& h);
+    void remove_child (const graphics_handle& h, bool from_root = false);
 
     Matrix get_boundingbox (bool internal = false,
                             const Matrix& parent_pix_size = Matrix ()) const;
@@ -3076,7 +3076,7 @@
       integerhandle = val;
     }
 
-    void remove_child (const graphics_handle& h);
+    void remove_child (const graphics_handle& h, bool from_root = false);
 
     void set_visible (const octave_value& val);
 
@@ -3401,7 +3401,7 @@
   public:
     void set_defaults (base_graphics_object& obj, const std::string& mode);
 
-    void remove_child (const graphics_handle& h);
+    void remove_child (const graphics_handle& h, bool from_root = false);
 
     void adopt (const graphics_handle& h);
 
@@ -3599,7 +3599,7 @@
     void set_text_child (handle_property& h, const std::string& who,
                          const octave_value& v);
 
-    void delete_text_child (handle_property& h);
+    void delete_text_child (handle_property& h, bool from_root = false);
 
     // See the genprops.awk script for an explanation of the
     // properties declarations.
@@ -5264,7 +5264,7 @@
   class OCTINTERP_API properties : public base_properties
   {
   public:
-    void remove_child (const graphics_handle& h);
+    void remove_child (const graphics_handle& h, bool from_root = false);
 
     void adopt (const graphics_handle& h);
 
@@ -5338,9 +5338,9 @@
   class OCTINTERP_API properties : public base_properties
   {
   public:
-    void remove_child (const graphics_handle& h)
+    void remove_child (const graphics_handle& h, bool from_root = false)
     {
-      base_properties::remove_child (h);
+      base_properties::remove_child (h, from_root);
     }
 
     void adopt (const graphics_handle& h)
@@ -6224,10 +6224,10 @@
            : graphics_handle ();
   }
 
-  static void free (const graphics_handle& h)
+  static void free (const graphics_handle& h, bool from_root = false)
   {
     if (instance_ok ())
-      instance->do_free (h);
+      instance->do_free (h, from_root);
   }
 
   static void renumber_figure (const graphics_handle& old_gh,
@@ -6479,7 +6479,7 @@
 
   graphics_handle do_get_handle (bool integer_figure_handle);
 
-  void do_free (const graphics_handle& h);
+  void do_free (const graphics_handle& h, bool from_root);
 
   void do_renumber_figure (const graphics_handle& old_gh,
                            const graphics_handle& new_gh);
