changeset 14014:907d03def9d5

explicitly close figures in clean_up_and_exit instead of using an atexit function * graphics.cc (Fdrawnow): Don't register __go_close_all__ as an atexit function. * __go_close_all__.m: Delete. * plot/module.mk (plot_FCN_FILES): Remove __go_close_all__.m from the list. * graphics.cc (gh_manager::create_instance): Do register cleanup function. * graphics.cc (delete_graphics_objects, delete_graphics_object, close_figure, force_close_figure): New functions. (F__go_delete__): Call delete_graphics_objects to do the work. * graphics.h, graphics.cc (gh_manager::close_all_figures, gh_manager::do_close_all_figures): New functions. * graphics.h.in, graphics.cc (close_all_figures): New function. * toplev.cc (clean_up_and_exit): Call close_all_figures. * graphics.h.in (uitoggletool::~uitoggletool, uipushtool::~uipushtool, uitoolbar::~uitoolbar, uipanel::~uipanel, uicontrol::~uicontrol, uicontextmenu::~uicontextmenu, uimenu::~uimenu, hggroup::~hggroup, surface::~surface, image::~image, text::~text, line::~line, axes::~axes, figure::~figure, root_figure::~root_figure): Don't delete children. * toplev.cc (SAFE_CALL, IGNORE_INTERRUPT): Rename to OCTAVE_SAFE_CALL and OCTAVE_IGNORE_INTERRUPT and move to toplev.h. Temporarily set Vdebug_on_error and Vdebug_on_warning. Reset error_state to zero. Change all callers. * graphics.h.in (base_graphics_toolkit::close): New virtual function. (graphics_toolkit::close, graphics_toolkit::close_all_toolkits): New functions. * graphics.cc (gnuplot_toolkit::close): New function. ): * __init_fltk__.cc (F__init_fltk__): Don't register __remove_fltk__ as an atexit function. (F__remove_fltk__): Move to fltk_toolkit::close.
author John W. Eaton <jwe@octave.org>
date Thu, 08 Dec 2011 06:28:18 -0500
parents 1734ebe27134
children 77adde2e79ac
files scripts/plot/__go_close_all__.m scripts/plot/module.mk src/DLD-FUNCTIONS/__init_fltk__.cc src/graphics.cc src/graphics.h.in src/toplev.cc src/toplev.h
diffstat 7 files changed, 237 insertions(+), 167 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/plot/__go_close_all__.m	Thu Dec 08 00:52:39 2011 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-## Copyright (C) 2007-2011 John W. Eaton
-##
-## This file is part of Octave.
-##
-## Octave is free software; you can redistribute it and/or modify it
-## under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 3 of the License, or (at
-## your option) any later version.
-##
-## Octave is distributed in the hope that it will be useful, but
-## WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-## General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with Octave; see the file COPYING.  If not, see
-## <http://www.gnu.org/licenses/>.
-
-## -*- texinfo -*-
-## @deftypefn {Function File} {} __go_close_all__ ()
-## Undocumented internal function.
-## @end deftypefn
-
-## Author: jwe
-
-function __go_close_all__ ()
-  close ("all", "hidden");
-endfunction
-
-
-## No test needed for internal helper function.
-%!assert (1)
--- a/scripts/plot/module.mk	Thu Dec 08 00:52:39 2011 -0500
+++ b/scripts/plot/module.mk	Thu Dec 08 06:28:18 2011 -0500
@@ -56,7 +56,6 @@
 
 plot_FCN_FILES = \
   plot/__gnuplot_drawnow__.m \
-  plot/__go_close_all__.m \
   plot/__plt_get_axis_arg__.m \
   plot/allchild.m \
   plot/ancestor.m \
--- a/src/DLD-FUNCTIONS/__init_fltk__.cc	Thu Dec 08 00:52:39 2011 -0500
+++ b/src/DLD-FUNCTIONS/__init_fltk__.cc	Thu Dec 08 06:28:18 2011 -0500
@@ -1934,14 +1934,31 @@
     sz(1) = Fl::h ();
     return sz;
   }
+
+  void close (void)
+  {
+    if (toolkit_registered)
+      {
+        munlock ("__init_fltk__");
+
+        figure_manager::close_all ();
+        graphics_toolkit::unregister_toolkit (FLTK_GRAPHICS_TOOLKIT_NAME);
+        toolkit_registered = false;
+
+        octave_value_list args;
+        args(0) = "__fltk_redraw__";
+        feval ("remove_input_event_hook", args, 0);
+
+        // FIXME ???
+        Fl::wait (fltk_maxtime);
+      }
+  }
 };
 
 // Initialize the fltk graphics toolkit.
 
 DEFUN_DLD (__init_fltk__, , , "")
 {
-  static bool remove_fltk_registered = false;
-
   if (! toolkit_registered)
     {
       mlock ();
@@ -1952,13 +1969,6 @@
       octave_value_list args;
       args(0) = "__fltk_redraw__";
       feval ("add_input_event_hook", args, 0);
-
-      if (! remove_fltk_registered)
-        {
-          octave_add_atexit_function ("__remove_fltk__");
-
-          remove_fltk_registered = true;
-        }
     }
 
   octave_value retval;
@@ -1972,29 +1982,6 @@
   return octave_value ();
 }
 
-// Delete the fltk graphics toolkit.
-
-DEFUN_DLD (__remove_fltk__, , , "")
-{
-  if (toolkit_registered)
-    {
-      munlock ("__init_fltk__");
-
-      figure_manager::close_all ();
-      graphics_toolkit::unregister_toolkit (FLTK_GRAPHICS_TOOLKIT_NAME);
-      toolkit_registered = false;
-
-      octave_value_list args;
-      args(0) = "__fltk_redraw__";
-      feval ("remove_input_event_hook", args, 0);
-
-      // FIXME ???
-      Fl::wait (fltk_maxtime);
-    }
-
-  return octave_value ();
-}
-
 DEFUN_DLD (__fltk_maxtime__, args, ,"")
 {
   octave_value retval = fltk_maxtime;
--- a/src/graphics.cc	Thu Dec 08 00:52:39 2011 -0500
+++ b/src/graphics.cc	Thu Dec 08 06:28:18 2011 -0500
@@ -2323,6 +2323,114 @@
 }
 
 static void
+delete_graphics_object (const graphics_handle& h)
+{
+  if (h.ok ())
+    {
+      graphics_object obj = gh_manager::get_object (h);
+
+      // Don't do recursive deleting, due to callbacks
+      if (! obj.get_properties ().is_beingdeleted ())
+        {
+          graphics_handle parent_h = obj.get_parent ();
+
+          graphics_object parent_obj =
+            gh_manager::get_object (parent_h);
+
+          // NOTE: free the handle before removing it from its
+          //       parent's children, such that the object's
+          //       state is correct when the deletefcn callback
+          //       is executed
+
+          gh_manager::free (h);
+
+          // A callback function might have already deleted
+          // the parent
+          if (parent_obj.valid_object ())
+            parent_obj.remove_child (h);
+
+          Vdrawnow_requested = true;
+        }
+    }
+}
+
+static void
+delete_graphics_object (double val)
+{
+  delete_graphics_object (gh_manager::lookup (val));
+}
+
+static void
+delete_graphics_objects (const NDArray vals)
+{
+  for (octave_idx_type i = 0; i < vals.numel (); i++)
+    delete_graphics_object (vals.elem (i));
+}
+
+static void
+close_figure (const graphics_handle& handle)
+{
+  octave_value closerequestfcn = xget (handle, "closerequestfcn");
+
+  OCTAVE_SAFE_CALL (gh_manager::execute_callback, (handle, closerequestfcn));
+}
+
+static void
+force_close_figure (const graphics_handle& handle)
+{
+  // Remove the deletefcn and closerequestfcn callbacks and delete the
+  // object directly.
+
+  xset (handle, "deletefcn", Matrix ());
+  xset (handle, "closerequestfcn", Matrix ());
+
+  delete_graphics_object (handle);
+}
+
+void
+gh_manager::do_close_all_figures (void)
+{
+  // FIXME -- should we process or discard pending events?
+
+  event_queue.clear ();
+
+  // Don't use figure_list_iterator because we'll be removing elements
+  // from the list elsewhere.
+
+  Matrix hlist = do_figure_handle_list (true);
+
+  for (octave_idx_type i = 0; i < hlist.numel (); i++)
+    {
+      graphics_handle h = gh_manager::lookup (hlist(i));
+
+      if (h.ok ())
+        close_figure (h);
+    }
+
+  // They should all be closed now.  If not, force them to close.
+
+  hlist = do_figure_handle_list (true);
+
+  for (octave_idx_type i = 0; i < hlist.numel (); i++)
+    {
+      graphics_handle h = gh_manager::lookup (hlist(i));
+
+      if (h.ok ())
+        force_close_figure (h);
+    }
+
+  // None left now, right?
+
+  hlist = do_figure_handle_list (true);
+
+  assert (hlist.numel () == 0);
+
+  // Clear all callback objects from our list.
+
+  callback_objects.clear ();
+}
+
+static void
 adopt (const graphics_handle& p, const graphics_handle& h)
 {
   graphics_object parent_obj = gh_manager::get_object (p);
@@ -2417,6 +2525,7 @@
 
   finalize (go);
 }
+
 // ---------------------------------------------------------------------
 
 void
@@ -2736,6 +2845,8 @@
   Matrix get_screen_size (void) const
     { return Matrix (1, 2, 0.0); }
 
+  void close (void) { }
+
 private:
   void send_quit (const octave_value& pstream) const
     {
@@ -2779,6 +2890,19 @@
   return available_toolkits["gnuplot"];
 }
 
+void
+graphics_toolkit::close_all_toolkits (void)
+{
+  while (! available_toolkits.empty ())
+    {
+      available_toolkits_iterator p = available_toolkits.begin ();
+
+      p->second.close ();
+
+      available_toolkits.erase (p);
+    }
+}
+
 std::map<std::string, graphics_toolkit> graphics_toolkit::available_toolkits;
 
 // ---------------------------------------------------------------------
@@ -2937,7 +3061,8 @@
     {
       currentfigure = val;
 
-      gh_manager::push_figure (val);
+      if (val.ok ())
+        gh_manager::push_figure (val);
     }
   else
     gripe_set_invalid ("currentfigure");
@@ -7401,9 +7526,8 @@
 {
   instance = new gh_manager ();
 
-#if 0
-  singleton_cleanup_list::add (cleanup_instance);
-#endif
+  if (instance)
+    singleton_cleanup_list::add (cleanup_instance);
 }
 
 graphics_handle
@@ -8783,40 +8907,7 @@
             }
 
           if (! error_state)
-            {
-              for (octave_idx_type i = 0; i < vals.numel (); i++)
-                {
-                  h = gh_manager::lookup (vals.elem (i));
-
-                  if (h.ok ())
-                    {
-                      graphics_object obj = gh_manager::get_object (h);
-
-                      // Don't do recursive deleting, due to callbacks
-                      if (! obj.get_properties ().is_beingdeleted ())
-                        {
-                          graphics_handle parent_h = obj.get_parent ();
-
-                          graphics_object parent_obj =
-                            gh_manager::get_object (parent_h);
-
-                          // NOTE: free the handle before removing it from its
-                          //       parent's children, such that the object's
-                          //       state is correct when the deletefcn callback
-                          //       is executed
-
-                          gh_manager::free (h);
-
-                          // A callback function might have already deleted
-                          // the parent
-                          if (parent_obj.valid_object ())
-                            parent_obj.remove_child (h);
-
-                          Vdrawnow_requested = true;
-                        }
-                    }
-                }
-            }
+            delete_graphics_objects (vals);
         }
       else
         error ("delete: invalid graphics object");
@@ -9023,7 +9114,6 @@
 @end deftypefn")
 {
   static int drawnow_executing = 0;
-  static bool __go_close_all_registered__ = false;
 
   octave_value retval;
 
@@ -9036,13 +9126,6 @@
 
   if (++drawnow_executing <= 1)
     {
-      if (! __go_close_all_registered__)
-        {
-          octave_add_atexit_function ("__go_close_all__");
-
-          __go_close_all_registered__ = true;
-        }
-
       if (args.length () == 0 || args.length () == 1)
         {
           Matrix hlist = gh_manager::figure_handle_list (true);
--- a/src/graphics.h.in	Thu Dec 08 00:52:39 2011 -0500
+++ b/src/graphics.h.in	Thu Dec 08 06:28:18 2011 -0500
@@ -2132,6 +2132,10 @@
 
   void finalize (const graphics_handle&);
 
+  // Close the graphics toolkit.
+  virtual void close (void)
+  { gripe_invalid ("base_graphics_toolkit::close"); }
+
 private:
   std::string name;
   octave_refcount<int> count;
@@ -2229,6 +2233,11 @@
   void finalize (const graphics_handle& h)
     { rep->finalize (h); }
 
+  // Close the graphics toolkit.
+  void close (void) { rep->close (); }
+
+  void close_all_toolkits (void);
+
   OCTINTERP_API static graphics_toolkit default_toolkit (void);
 
   static void register_toolkit (const graphics_toolkit& b)
@@ -3011,7 +3020,7 @@
 
   root_figure (void) : xproperties (0, graphics_handle ()), default_properties () { }
 
-  ~root_figure (void) { xproperties.delete_children (); }
+  ~root_figure (void) { }
 
   void mark_modified (void) { }
 
@@ -3259,10 +3268,7 @@
     xproperties.override_defaults (*this);
   }
 
-  ~figure (void)
-  {
-    xproperties.delete_children ();
-  }
+  ~figure (void) { }
 
   void override_defaults (base_graphics_object& obj)
   {
@@ -3863,7 +3869,7 @@
     xproperties.update_transform ();
   }
 
-  ~axes (void) { xproperties.delete_children (); }
+  ~axes (void) { }
 
   void override_defaults (base_graphics_object& obj)
   {
@@ -4000,7 +4006,7 @@
     xproperties.override_defaults (*this);
   }
 
-  ~line (void) { xproperties.delete_children (); }
+  ~line (void) { }
 
   base_properties& get_properties (void) { return xproperties; }
 
@@ -4140,7 +4146,7 @@
     xproperties.override_defaults (*this);
   }
 
-  ~text (void) { xproperties.delete_children (); }
+  ~text (void) { }
 
   base_properties& get_properties (void) { return xproperties; }
 
@@ -4264,7 +4270,7 @@
     xproperties.override_defaults (*this);
   }
 
-  ~image (void) { xproperties.delete_children (); }
+  ~image (void) { }
 
   base_properties& get_properties (void) { return xproperties; }
 
@@ -4382,7 +4388,7 @@
     xproperties.override_defaults (*this);
   }
 
-  ~patch (void) { xproperties.delete_children (); }
+  ~patch (void) { }
 
   base_properties& get_properties (void) { return xproperties; }
 
@@ -4535,7 +4541,7 @@
     xproperties.override_defaults (*this);
   }
 
-  ~surface (void) { xproperties.delete_children (); }
+  ~surface (void) { }
 
   base_properties& get_properties (void) { return xproperties; }
 
@@ -4603,7 +4609,7 @@
     xproperties.override_defaults (*this);
   }
 
-  ~hggroup (void) { xproperties.delete_children (); }
+  ~hggroup (void) { }
 
   base_properties& get_properties (void) { return xproperties; }
 
@@ -4667,7 +4673,7 @@
     xproperties.override_defaults (*this);
   }
 
-  ~uimenu (void) { xproperties.delete_children (); }
+  ~uimenu (void) { }
 
   base_properties& get_properties (void) { return xproperties; }
 
@@ -4713,7 +4719,7 @@
     xproperties.override_defaults (*this);
   }
 
-  ~uicontextmenu (void) { xproperties.delete_children (); }
+  ~uicontextmenu (void) { }
 
   base_properties& get_properties (void) { return xproperties; }
 
@@ -4806,7 +4812,7 @@
     xproperties.override_defaults (*this);
   }
 
-  ~uicontrol (void) { xproperties.delete_children (); }
+  ~uicontrol (void) { }
 
   base_properties& get_properties (void) { return xproperties; }
 
@@ -4872,7 +4878,7 @@
     xproperties.override_defaults (*this);
   }
 
-  ~uipanel (void) { xproperties.delete_children (); }
+  ~uipanel (void) { }
 
   base_properties& get_properties (void) { return xproperties; }
 
@@ -4911,7 +4917,7 @@
     xproperties.override_defaults (*this);
   }
 
-  ~uitoolbar (void) { xproperties.delete_children (); }
+  ~uitoolbar (void) { }
 
   void override_defaults (base_graphics_object& obj)
   {
@@ -5009,7 +5015,7 @@
     xproperties.override_defaults (*this);
   }
 
-  ~uipushtool (void) { xproperties.delete_children (); }
+  ~uipushtool (void) { }
 
   base_properties& get_properties (void) { return xproperties; }
 
@@ -5062,7 +5068,7 @@
     xproperties.override_defaults (*this);
   }
 
-  ~uitoggletool (void) { xproperties.delete_children (); }
+  ~uitoggletool (void) { }
 
   base_properties& get_properties (void) { return xproperties; }
 
@@ -5387,6 +5393,12 @@
     return retval;
   }
 
+  static void close_all_figures (void)
+  {
+    if (instance_ok ())
+      instance->do_close_all_figures ();
+  }
+
 public:
   class auto_lock : public octave_autolock
   {
@@ -5552,6 +5564,8 @@
 
   int do_process_events (bool force = false);
 
+  void do_close_all_figures (void);
+
   static void restore_gcbo (void)
   {
     if (instance_ok ())
@@ -5577,4 +5591,6 @@
 // This function is NOT equivalent to the scripting language function gca.
 OCTINTERP_API graphics_handle gca (void);
 
+OCTINTERP_API void close_all_figures (void);
+
 #endif
--- a/src/toplev.cc	Thu Dec 08 00:52:39 2011 -0500
+++ b/src/toplev.cc	Thu Dec 08 06:28:18 2011 -0500
@@ -53,6 +53,7 @@
 #include "defun.h"
 #include "error.h"
 #include "file-io.h"
+#include "graphics.h"
 #include "input.h"
 #include "lex.h"
 #include "oct-conf.h"
@@ -661,25 +662,6 @@
   return retval;
 }
 
-// Call a function with exceptions handled to avoid problems with
-// errors while shutting down.
-
-#define IGNORE_EXCEPTION(E) \
-  catch (E) \
-    { \
-      std::cerr << "error: ignoring " #E " while preparing to exit" << std::endl; \
-      recover_from_exception (); \
-    }
-
-#define SAFE_CALL(F, ARGS) \
-  try \
-    { \
-      F ARGS; \
-    } \
-  IGNORE_EXCEPTION (octave_interrupt_exception) \
-  IGNORE_EXCEPTION (octave_execution_exception) \
-  IGNORE_EXCEPTION (std::bad_alloc)
-
 // Fix up things before exiting.
 
 void
@@ -687,16 +669,17 @@
 {
   do_octave_atexit ();
 
-  // Clean up symbol table.
-  SAFE_CALL (symbol_table::cleanup, ())
+  OCTAVE_SAFE_CALL (gh_manager::close_all_figures, ());
 
-  SAFE_CALL (cleanup_parser, ())
+  OCTAVE_SAFE_CALL (symbol_table::cleanup, ());
+
+  OCTAVE_SAFE_CALL (cleanup_parser, ());
 
-  SAFE_CALL (sysdep_cleanup, ())
+  OCTAVE_SAFE_CALL (sysdep_cleanup, ());
 
-  SAFE_CALL (singleton_cleanup_list::cleanup, ())
+  OCTAVE_SAFE_CALL (singleton_cleanup_list::cleanup, ());
 
-  SAFE_CALL (octave_chunk_buffer::clear, ())
+  OCTAVE_SAFE_CALL (octave_chunk_buffer::clear, ());
 
   if (octave_exit)
     (*octave_exit) (retval == EOF ? 0 : retval);
@@ -1057,11 +1040,11 @@
 
       octave_atexit_functions.pop_front ();
 
-      SAFE_CALL (reset_error_handler, ())
+      OCTAVE_SAFE_CALL (reset_error_handler, ());
 
-      SAFE_CALL (feval, (fcn, octave_value_list (), 0))
+      OCTAVE_SAFE_CALL (feval, (fcn, octave_value_list (), 0));
 
-      SAFE_CALL (flush_octave_stdout, ())
+      OCTAVE_SAFE_CALL (flush_octave_stdout, ());
     }
 
   if (! deja_vu)
@@ -1071,23 +1054,23 @@
       // Do this explicitly so that destructors for mex file objects
       // are called, so that functions registered with mexAtExit are
       // called.
-      SAFE_CALL (clear_mex_functions, ())
+      OCTAVE_SAFE_CALL (clear_mex_functions, ());
 
-        SAFE_CALL (command_editor::restore_terminal_state, ())
+      OCTAVE_SAFE_CALL (command_editor::restore_terminal_state, ());
 
       // FIXME -- is this needed?  Can it cause any trouble?
-      SAFE_CALL (raw_mode, (0))
+      OCTAVE_SAFE_CALL (raw_mode, (0));
 
-      SAFE_CALL (octave_history_write_timestamp, ())
+      OCTAVE_SAFE_CALL (octave_history_write_timestamp, ());
 
       if (! command_history::ignoring_entries ())
-        SAFE_CALL (command_history::clean_up_and_save, ())
+        OCTAVE_SAFE_CALL (command_history::clean_up_and_save, ());
 
-      SAFE_CALL (close_files, ())
+      OCTAVE_SAFE_CALL (close_files, ());
 
-      SAFE_CALL (cleanup_tmp_files, ())
+      OCTAVE_SAFE_CALL (cleanup_tmp_files, ());
 
-      SAFE_CALL (flush_octave_stdout, ())
+      OCTAVE_SAFE_CALL (flush_octave_stdout, ());
 
       if (! quitting_gracefully && (interactive || forced_interactive))
         {
@@ -1096,7 +1079,7 @@
           // Yes, we want this to be separate from the call to
           // flush_octave_stdout above.
 
-          SAFE_CALL (flush_octave_stdout, ())
+          OCTAVE_SAFE_CALL (flush_octave_stdout, ());
         }
     }
 }
--- a/src/toplev.h	Thu Dec 08 00:52:39 2011 -0500
+++ b/src/toplev.h	Thu Dec 08 06:28:18 2011 -0500
@@ -418,4 +418,38 @@
   void do_backtrace_error_message (void) const;
 };
 
+// Call a function with exceptions handled to avoid problems with
+// errors while shutting down.
+
+#define OCTAVE_IGNORE_EXCEPTION(E) \
+  catch (E) \
+    { \
+      std::cerr << "error: ignoring " #E " while preparing to exit" << std::endl; \
+      recover_from_exception (); \
+    }
+
+#define OCTAVE_SAFE_CALL(F, ARGS) \
+  do \
+    { \
+      try \
+        { \
+          unwind_protect frame; \
+ \
+          frame.protect_var (Vdebug_on_error); \
+          frame.protect_var (Vdebug_on_warning); \
+ \
+          Vdebug_on_error = false; \
+          Vdebug_on_warning = false; \
+ \
+          F ARGS; \
+        } \
+      OCTAVE_IGNORE_EXCEPTION (octave_interrupt_exception) \
+      OCTAVE_IGNORE_EXCEPTION (octave_execution_exception) \
+      OCTAVE_IGNORE_EXCEPTION (std::bad_alloc) \
+ \
+      if (error_state) \
+        error_state = 0; \
+    } \
+  while (0)
+
 #endif