# HG changeset patch # User John W. Eaton # Date 1323343698 18000 # Node ID 907d03def9d54e0aa609288317daf13f48d7f586 # Parent 1734ebe2713407974b19fa7b19887bc71d7a3820 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. diff -r 1734ebe27134 -r 907d03def9d5 scripts/plot/__go_close_all__.m --- 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 -## . - -## -*- 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) diff -r 1734ebe27134 -r 907d03def9d5 scripts/plot/module.mk --- 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 \ diff -r 1734ebe27134 -r 907d03def9d5 src/DLD-FUNCTIONS/__init_fltk__.cc --- 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; diff -r 1734ebe27134 -r 907d03def9d5 src/graphics.cc --- 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 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); diff -r 1734ebe27134 -r 907d03def9d5 src/graphics.h.in --- 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 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 diff -r 1734ebe27134 -r 907d03def9d5 src/toplev.cc --- 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, ()); } } } diff -r 1734ebe27134 -r 907d03def9d5 src/toplev.h --- 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