changeset 7408:246f905cb984

[project @ 2008-01-22 19:42:47 by jwe]
author jwe
date Tue, 22 Jan 2008 19:42:48 +0000
parents 8433bb7865bd
children 73036cdd855d
files liboctave/ChangeLog scripts/ChangeLog scripts/plot/Makefile.in scripts/plot/drawnow.m scripts/plot/gnuplot_drawnow.m src/ChangeLog src/graphics.cc src/graphics.h.in
diffstat 8 files changed, 547 insertions(+), 250 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/ChangeLog	Tue Jan 22 19:29:51 2008 +0000
+++ b/liboctave/ChangeLog	Tue Jan 22 19:42:48 2008 +0000
@@ -1,4 +1,4 @@
-2008-01-22  Michael Goffioul <michael.goffioul@gmail.com>
+2008-01-22  Michael Goffioul  <michael.goffioul@gmail.com>
 
 	* oct-time.cc (octave_base_tim::init): Validate pointer argument;
 	this fixes the "localtime(-1)" crash under Windows.
--- a/scripts/ChangeLog	Tue Jan 22 19:29:51 2008 +0000
+++ b/scripts/ChangeLog	Tue Jan 22 19:42:48 2008 +0000
@@ -1,3 +1,10 @@
+2008-01-22  Michael Goffioul  <michael.goffioul@gmail.com>
+
+	* plot/gnuplot_drawnow.m: New function corresponding to the
+	implementation of the gnuplot-based graphics backend (derived from
+	drawnow.m).
+	* plot/drawnow.m: Deleted (converted to C++).
+
 2008-01-15  Rolf Fabian  <Rolf.Fabian@gmx.de>
 
 	* linear-algebra/__norm__.m: Only scale if inf norm is finite.
--- a/scripts/plot/Makefile.in	Tue Jan 22 19:29:51 2008 +0000
+++ b/scripts/plot/Makefile.in	Tue Jan 22 19:42:48 2008 +0000
@@ -85,7 +85,7 @@
   contourc.m \
   contourf.m \
   cylinder.m \
-  drawnow.m \
+  gnuplot_drawnow.m \
   ellipsoid.m \
   errorbar.m \
   ezcontourf.m \
--- a/scripts/plot/drawnow.m	Tue Jan 22 19:29:51 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,231 +0,0 @@
-## Copyright (C) 2005, 2006, 2007 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} {} drawnow ()
-## Update and display the current graphics.
-##
-## Octave automatically calls drawnow just before printing a prompt,
-## when @code{sleep} or @code{pause} is called, or while waiting for
-## command-line input.
-## @end deftypefn
-
-## Author: jwe
-
-function drawnow (term, file, mono, debug_file)
-
-  persistent drawnow_executing = 0;
-
-  unwind_protect
-
-    ## If this is a recursive call, do nothing.
-    if (++drawnow_executing > 1)
-      return;
-    endif
-
-    if (nargin < 3)
-      mono = false;
-    endif
-
-    if (nargin >= 2 && nargin <= 4)
-      [dnm, fnm, ext] = fileparts (file);
-      if (! (isempty (dnm) || isdir (dnm)))
-	error ("drawnow: nonexistent directory `%s'", dnm);
-      endif
-      h = get (0, "currentfigure");
-      if (h)
-	f = __get__ (h);
-	plot_stream = [];
-	fid = [];
-	unwind_protect
-	  [plot_stream, enhanced] = open_gnuplot_stream ([], term, file);
-	  __go_draw_figure__ (f, plot_stream, enhanced, mono);
-	  if (nargin == 4)
-	    fid = fopen (debug_file, "wb");
-	    enhanced = init_plot_stream (fid, [], term, file);
-	    __go_draw_figure__ (f, fid, enhanced, mono);
-	  endif
-	unwind_protect_cleanup
-	  if (! isempty (plot_stream))
-	    pclose (plot_stream);
-	  endif
-	  if (! isempty (fid))
-	    fclose (fid);
-	  endif
-	end_unwind_protect
-      else
-	error ("drawnow: nothing to draw");
-      endif
-    elseif (nargin == 0)
-      for h = __go_figure_handles__ ()
-	if (! (isnan (h) || h == 0))
-	  f = __get__ (h);
-	  if (f.__modified__)
-	    plot_stream = f.__plot_stream__;
-	    figure_is_visible = strcmp (f.visible, "on");
-	    if (figure_is_visible)
-	      if (isempty (plot_stream))
-		[plot_stream, enhanced] = open_gnuplot_stream (h);
-		set (h, "__enhanced__", enhanced);
-	      else
-		enhanced = f.__enhanced__;
-	      endif
-	      __go_draw_figure__ (f, plot_stream, enhanced, mono);
-	    elseif (! isempty (plot_stream))
-	      pclose (plot_stream);
-	      set (h, "__plot_stream__", []);
-	      set (h, "__enhanced__", false);
-	    endif
-	    set (h, "__modified__", false);
-	  endif
-	endif
-      endfor
-    else
-      print_usage ();
-    endif
-
-  unwind_protect_cleanup
-
-    drawnow_executing--;
-    __request_drawnow__ (false);
-
-  end_unwind_protect
-
-endfunction
-
-function [plot_stream, enhanced] = open_gnuplot_stream (h, varargin)
-
-  ## If drawnow is cleared, it is possible to register __go_close_all__
-  ## more than once, but that is not fatal.
-  persistent __go_close_all_registered__;
-
-  cmd = gnuplot_binary ();
-
-  plot_stream = popen (cmd, "w");
-
-  if (plot_stream < 0)
-    error ("drawnow: failed to open connection to gnuplot");
-  else
-
-    if (! isempty (h))
-      set (h, "__plot_stream__", plot_stream);
-    endif
-
-    enhanced = init_plot_stream (plot_stream, h, varargin{:});
-
-    if (isempty (__go_close_all_registered__))
-      atexit ("__go_close_all__");
-      __go_close_all_registered__ = true;
-    endif
-
-  endif
-
-endfunction
-
-function enhanced = init_plot_stream (plot_stream, h, term, file)
-
-  if (nargin == 4)
-    enhanced = enhanced_term (term);
-    if (! isempty (term))
-      if (enhanced)
-	fprintf (plot_stream, "set terminal %s enhanced;\n", term);
-      else
-	fprintf (plot_stream, "set terminal %s;\n", term);
-      endif
-    endif
-    if (! isempty (file))
-      fprintf (plot_stream, "set output \"%s\";\n", file);
-    endif
-  else
-
-    ## Guess the terminal type.
-    term = getenv ("GNUTERM");
-    if (isempty (term))
-      if (! isempty (getenv ("DISPLAY")))
-	term = "x11";
-      elseif (! isunix ())
-	term = "windows";
-      else
-	## This should really be checking for os x before setting
-	## the terminal type to aqua, but nobody will notice because
-	## every other unix will be using x11 and windows will be
-	## using windows.  Those diehards still running octave from
-	## a linux console know how to set the GNUTERM variable.
-	term = "aqua";
-      endif
-    endif
-
-    enhanced = enhanced_term (term);
-    if (enhanced)
-      enh_str = "enhanced";
-    else
-      enh_str = "";
-    endif
-
-    ## If no 'h' (why not?) then open the terminal as Figure 0.
-    if (isempty (h))
-      h = 0;
-    endif
-
-    if (strcmp (term, "x11"))
-      fprintf (plot_stream, "set terminal x11 %s title \"Figure %d\"\n",
-	       enh_str, h);
-    elseif (strcmp (term, "aqua"))
-      ## Aqua doesn't understand the 'title' option despite what the
-      ## gnuplot 4.2 documentation says.
-      fprintf (plot_stream, "set terminal aqua %d %s\n", h, enh_str);
-    elseif (strcmp (term, "wxt"))
-      fprintf (plot_stream, "set terminal wxt %s title \"Figure %d\"\n", 
-	       enh_str, h);
-
-    elseif (enhanced)
-      fprintf (plot_stream, "set terminal %s %s\n", term, enh_str);
-    endif
-    ## gnuplot will pick up the GNUTERM environment variable itself
-    ## so no need to set the terminal type if not also setting the
-    ## figure title or enhanced mode.
-
-  endif
-
-endfunction
-
-function have_enhanced = enhanced_term (term)
-  persistent enhanced_terminals;
-
-  if (isempty (enhanced_terminals))
-    ## Don't include pstex, pslatex or epslatex here as the TeX commands
-    ## should not be interpreted in that case.
-    if (compare_versions (__gnuplot_version__ (), "4.0", ">"))
-      enhanced_terminals = {"aqua", "dumb", "png", "jpeg", "gif", "pm", ...
-	                    "windows", "wxt", "svg", "postscript", "x11", "pdf"};
-    else 
-      enhanced_terminals = {"x11", "postscript"};
-    endif
-  endif
-
-  term = tolower (term);
-
-  have_enhanced = false;
-  for i = 1 : length (enhanced_terminals)
-    t = enhanced_terminals{i};
-    if (strncmp (term, t, min (length (term), length (t))))
-      have_enhanced = true;
-      break;
-    endif
-  endfor
-endfunction
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/plot/gnuplot_drawnow.m	Tue Jan 22 19:42:48 2008 +0000
@@ -0,0 +1,183 @@
+## Copyright (C) 2005, 2006, 2007 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} {} drawnow ()
+## Update and display the current graphics.
+##
+## Octave automatically calls drawnow just before printing a prompt,
+## when @code{sleep} or @code{pause} is called, or while waiting for
+## command-line input.
+## @end deftypefn
+
+## Author: jwe
+
+function gnuplot_drawnow (h, term, file, mono, debug_file)
+
+  if (nargin < 4)
+    mono = false;
+  endif
+
+  if (nargin >= 3 && nargin <= 5)
+    f = __get__ (h);
+    plot_stream = [];
+    fid = [];
+    unwind_protect
+      [plot_stream, enhanced] = open_gnuplot_stream ([], term, file);
+      __go_draw_figure__ (f, plot_stream, enhanced, mono);
+      if (nargin == 5)
+        fid = fopen (debug_file, "wb");
+        enhanced = init_plot_stream (fid, [], term, file);
+        __go_draw_figure__ (f, fid, enhanced, mono);
+      endif
+    unwind_protect_cleanup
+      if (! isempty (plot_stream))
+        pclose (plot_stream);
+      endif
+      if (! isempty (fid))
+        fclose (fid);
+      endif
+    end_unwind_protect
+  elseif (nargin == 1)
+    f = __get__ (h);
+    plot_stream = f.__plot_stream__;
+    if (isempty (plot_stream))
+      [plot_stream, enhanced] = open_gnuplot_stream (h);
+      set (h, "__enhanced__", enhanced);
+    else
+      enhanced = f.__enhanced__;
+    endif
+    __go_draw_figure__ (f, plot_stream, enhanced, mono);
+  else
+    print_usage ();
+  endif
+
+endfunction
+
+function [plot_stream, enhanced] = open_gnuplot_stream (h, varargin)
+
+  cmd = gnuplot_binary ();
+
+  plot_stream = popen (cmd, "w");
+
+  if (plot_stream < 0)
+    error ("drawnow: failed to open connection to gnuplot");
+  else
+
+    if (! isempty (h))
+      set (h, "__plot_stream__", plot_stream);
+    endif
+
+    enhanced = init_plot_stream (plot_stream, h, varargin{:});
+
+  endif
+
+endfunction
+
+function enhanced = init_plot_stream (plot_stream, h, term, file)
+
+  if (nargin == 4)
+    enhanced = enhanced_term (term);
+    if (! isempty (term))
+      if (enhanced)
+	fprintf (plot_stream, "set terminal %s enhanced;\n", term);
+      else
+	fprintf (plot_stream, "set terminal %s;\n", term);
+      endif
+    endif
+    if (! isempty (file))
+      fprintf (plot_stream, "set output \"%s\";\n", file);
+    endif
+  else
+
+    ## Guess the terminal type.
+    term = getenv ("GNUTERM");
+    if (isempty (term))
+      if (! isempty (getenv ("DISPLAY")))
+	term = "x11";
+      elseif (! isunix ())
+	term = "windows";
+      else
+	## This should really be checking for os x before setting
+	## the terminal type to aqua, but nobody will notice because
+	## every other unix will be using x11 and windows will be
+	## using windows.  Those diehards still running octave from
+	## a linux console know how to set the GNUTERM variable.
+	term = "aqua";
+      endif
+    endif
+
+    enhanced = enhanced_term (term);
+    if (enhanced)
+      enh_str = "enhanced";
+    else
+      enh_str = "";
+    endif
+
+    ## If no 'h' (why not?) then open the terminal as Figure 0.
+    if (isempty (h))
+      h = 0;
+    endif
+
+    if (strcmp (term, "x11"))
+      fprintf (plot_stream, "set terminal x11 %s title \"Figure %d\"\n",
+	       enh_str, h);
+    elseif (strcmp (term, "aqua"))
+      ## Aqua doesn't understand the 'title' option despite what the
+      ## gnuplot 4.2 documentation says.
+      fprintf (plot_stream, "set terminal aqua %d %s\n", h, enh_str);
+    elseif (strcmp (term, "wxt"))
+      fprintf (plot_stream, "set terminal wxt %s title \"Figure %d\"\n", 
+	       enh_str, h);
+
+    elseif (enhanced)
+      fprintf (plot_stream, "set terminal %s %s\n", term, enh_str);
+    endif
+    ## gnuplot will pick up the GNUTERM environment variable itself
+    ## so no need to set the terminal type if not also setting the
+    ## figure title or enhanced mode.
+
+  endif
+
+endfunction
+
+function have_enhanced = enhanced_term (term)
+  persistent enhanced_terminals;
+
+  if (isempty (enhanced_terminals))
+    ## Don't include pstex, pslatex or epslatex here as the TeX commands
+    ## should not be interpreted in that case.
+    if (compare_versions (__gnuplot_version__ (), "4.0", ">"))
+      enhanced_terminals = {"aqua", "dumb", "png", "jpeg", "gif", "pm", ...
+	                    "windows", "wxt", "svg", "postscript", "x11", "pdf"};
+    else 
+      enhanced_terminals = {"x11", "postscript"};
+    endif
+  endif
+
+  term = tolower (term);
+
+  have_enhanced = false;
+  for i = 1 : length (enhanced_terminals)
+    t = enhanced_terminals{i};
+    if (strncmp (term, t, min (length (term), length (t))))
+      have_enhanced = true;
+      break;
+    endif
+  endfor
+endfunction
--- a/src/ChangeLog	Tue Jan 22 19:29:51 2008 +0000
+++ b/src/ChangeLog	Tue Jan 22 19:42:48 2008 +0000
@@ -1,3 +1,19 @@
+2008-01-22  Michael Goffioul  <michael.goffioul@gmail.com>
+
+	* graphics.h.in (base_properties::is_visible,
+	base_properties::set_modified): New accessors.
+	(class base_graphics_backend, class graphics_backend): New classes
+	for handling octave/backend interaction.
+	(figure::properties::close): Add "pop" argument controlling
+	whether the figure should be popped from the list of existing figures.
+	(class figure::properties): New backend field and accessors, holding
+	the graphics backend associated with the figure.
+	* graphics.cc (class gnuplot_backend): New class for the default
+	gnuplot backend.
+	(figure::properties::close): Add "pop" argument and transfer the
+	figure closing to the associated backend.
+	(Fdrawnow): New builtin function, converted from drawnow.m.
+
 2008-01-19  John W. Eaton  <jwe@octave.org>
 
 	* genprops.awk (emit_source): Use "pname" for property name argument.
--- a/src/graphics.cc	Tue Jan 22 19:29:51 2008 +0000
+++ b/src/graphics.cc	Tue Jan 22 19:42:48 2008 +0000
@@ -43,6 +43,8 @@
 #include "ov-fcn-handle.h"
 #include "parse.h"
 #include "unwind-prot.h"
+#include "file-ops.h"
+#include "file-stat.h"
 
 static void
 gripe_set_invalid (const std::string& pname)
@@ -1146,6 +1148,69 @@
 
 // ---------------------------------------------------------------------
 
+class gnuplot_backend : public base_graphics_backend
+{
+public:
+  gnuplot_backend (void)
+      : base_graphics_backend ("gnuplot") { }
+
+  ~gnuplot_backend (void) { }
+
+  bool is_valid (void) const { return true; }
+ 
+  void close_figure (const octave_value& pstream) const
+    {
+      if (! pstream.is_empty())
+	{
+	  octave_value_list args;
+	  args(1) = "\nquit;\n";
+	  args(0) = pstream;
+	  feval ("fputs", args);
+	  args.resize (1);
+	  feval ("fflush", args);
+	  feval ("pclose", args);
+	}
+    }
+
+  void redraw_figure (const graphics_handle& fh) const
+    {
+      octave_value_list args;
+      args(0) = fh.as_octave_value ();
+      feval ("gnuplot_drawnow", args);
+    }
+
+  void print_figure (const graphics_handle& fh, const std::string& term,
+		     const std::string& file, bool mono,
+		     const std::string& debug_file) const
+    {
+      octave_value_list args;
+      args.resize (4);
+      args(0) = fh.as_octave_value ();
+      args(1) = term;
+      args(2) = file;
+      args(3) = mono;
+      if (! debug_file.empty ())
+	args(4) = debug_file;
+      feval ("gnuplot_drawnow", args);
+    }
+
+  Matrix get_canvas_size (const graphics_handle& fh) const
+    { return Matrix (1, 2, 0.0); }
+};
+
+graphics_backend
+graphics_backend::default_backend (void)
+{
+  if (available_backends.size () == 0)
+    register_backend (new gnuplot_backend ());
+
+  return available_backends["gnuplot"];
+}
+
+std::map<std::string, graphics_backend> graphics_backend::available_backends;
+
+// ---------------------------------------------------------------------
+
 #include "graphics-props.cc"
 
 // ---------------------------------------------------------------------
@@ -1202,24 +1267,19 @@
 }
 
 void
-figure::properties::close (void)
+figure::properties::close (bool pop)
 {
-  if (! get___plot_stream__ ().is_empty ())
+  if (backend)
+    backend.close_figure (get___plot_stream__ ());
+
+  if (pop)
     {
-      octave_value_list args;
-      args(1) = "\nquit;\n";
-      args(0) = get___plot_stream__ ();
-      feval ("fputs", args);
-      args.resize (1);
-      feval ("fflush", args);
-      feval ("pclose", args);
+      gh_manager::pop_figure (__myhandle__);
+
+      graphics_handle cf = gh_manager::current_figure ();
+
+      xset (0, "currentfigure", cf.value ());
     }
-
-  gh_manager::pop_figure (__myhandle__);
-
-  graphics_handle cf = gh_manager::current_figure ();
-
-  xset (0, "currentfigure", cf.value ());
 }
 
 octave_value
@@ -2305,6 +2365,130 @@
   return octave_value (gh_manager::figure_handle_list ());
 }
 
+DEFUN (drawnow, args, ,
+   "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} __go_drawnow__ ()\n\
+@deftypefnx {Built-in Function} {} __go_drawnow__ (@var{term}, @var{file}, @var{mono}, @var{debug_file})\n\
+Undocumented internal function.\n\
+@end deftypefn")
+{
+  static int drawnow_executing = 0;
+  static bool __go_close_all_registered__ = false;
+
+  octave_value retval;
+
+  if (drawnow_executing >= 1)
+    return retval;
+
+  if (! __go_close_all_registered__)
+    {
+      // FIXME: is there a C++ way to do this?
+      int parse_status;
+      eval_string ("atexit (\"__go_close_all__\")", true, parse_status);
+      __go_close_all_registered__ = true;
+    }
+
+  ++drawnow_executing;
+
+  if (args.length () == 0)
+    {
+      Matrix hlist = gh_manager::figure_handle_list ();
+
+      for (int i = 0; ! error_state && i < hlist.length (); i++)
+	{
+	  graphics_handle h = gh_manager::lookup (hlist(i));
+
+	  if (h.ok () && h != 0)
+	    {
+	      graphics_object go = gh_manager::get_object (h);
+	      figure::properties& fprops = dynamic_cast <figure::properties&> (go.get_properties ());
+
+	      if (fprops.is_modified ())
+		{
+		  if (fprops.is_visible ())
+		    fprops.get_backend ().redraw_figure (h);
+		  else if (! fprops.get___plot_stream__ ().is_empty ())
+		    {
+		      fprops.close (false);
+		      fprops.set___plot_stream__ (Matrix ());
+		      fprops.set___enhanced__ (false);
+		    }
+		  fprops.set_modified (false);
+		}
+	    }
+	}
+    }
+  else if (args.length () >= 2 && args.length () <= 4)
+    {
+      std::string term, file, debug_file;
+      bool mono;
+
+      term = args(0).string_value ();
+
+      if (! error_state)
+	{
+	  file = args(1).string_value ();
+
+	  if (! error_state)
+	    {
+	      int pos = file.find_last_of (file_ops::dir_sep_chars);
+
+	      if (pos != NPOS)
+		{
+		  file_stat fs (file.substr (0, pos));
+
+		  if (! (fs && fs.is_dir ()))
+		    error ("drawnow: nonexistent directory `%s'",
+			   file.substr (0, pos).c_str ());
+		}
+
+	      mono = (args.length () >= 3 ? args(2).bool_value () : false);
+
+	      if (! error_state)
+		{
+		  debug_file = (args.length () > 3 ? args(3).string_value ()
+				: "");
+
+		  if (! error_state)
+		    {
+		      graphics_handle h = gcf ();
+
+		      if (h.ok ())
+			{
+			  graphics_object go = gh_manager::get_object (h);
+			  figure::properties& fprops = dynamic_cast<figure::properties&> (go.get_properties ());
+
+			  fprops.get_backend ()
+			      .print_figure (h, term, file, mono, debug_file);
+			}
+		      else
+			error ("drawnow: nothing to draw");
+		    }
+		  else
+		    error ("drawnow: invalid debug_file, expected a string value");
+		}
+	      else
+		error ("drawnow: invalid colormode, expected a boolean value");
+	    }
+	  else
+	    error ("drawnow: invalid file, expected a string value");
+	}
+      else
+	error ("drawnow: invalid terminal, expected a string value");
+    }
+  else
+    print_usage ();
+
+  // FIXME: is there a C++ way to do this?
+  octave_value_list fargs;
+  fargs(0) = false;
+  feval ("__request_drawnow__", fargs);
+
+  --drawnow_executing;
+
+  return retval;
+}
+
 octave_value
 get_property_from_handle (double handle, const std::string &property,
 			  const std::string &func)
--- a/src/graphics.h.in	Tue Jan 22 19:29:51 2008 +0000
+++ b/src/graphics.h.in	Tue Jan 22 19:42:48 2008 +0000
@@ -1052,7 +1052,8 @@
   octave_value get_uicontextmenu (void) const { return uicontextmenu.get (); }
 
   octave_value get_userdata (void) const { return userdata.get (); }
-  
+ 
+  bool is_visible (void) const { return visible.is_on (); }
   std::string get_visible (void) const { return visible.current_value (); }
 
   bool is_beingdeleted (void) const { return beingdeleted.is_on (); }
@@ -1071,6 +1072,8 @@
 
   void set_parent (const octave_value& val);
 
+  void set_modified (const octave_value& val) { __modified__ = val; }
+
   void set_busyaction (const octave_value& val)
   {
     if (! error_state)
@@ -1632,6 +1635,121 @@
 
 // ---------------------------------------------------------------------
 
+class graphics_backend;
+
+class base_graphics_backend
+{
+public:
+  friend class graphics_backend;
+
+public:
+  base_graphics_backend (const std::string& nm)
+      : name (nm), count (0) { }
+
+  virtual ~base_graphics_backend (void) { }
+
+  std::string get_name (void) const { return name; }
+
+  virtual bool is_valid (void) const { return false; }
+
+  virtual void close_figure (const octave_value&) const
+    { error ("close_figure: invalid graphics backend"); }
+
+  virtual void redraw_figure (const graphics_handle&) const
+    { error ("redraw_figure: invalid graphics backend"); }
+
+  virtual void print_figure (const graphics_handle&, const std::string&,
+			     const std::string&, bool,
+			     const std::string& = "") const
+    { error ("print_figure: invalid graphics backend"); }
+
+  virtual Matrix get_canvas_size (const graphics_handle&) const
+    {
+      error ("get_canvas_size: invalid graphics backend");
+      return Matrix (1, 2, 0.0);
+    }
+
+private:
+  std::string name;
+  int count;
+};
+
+class graphics_backend
+{
+public:
+  graphics_backend (void)
+      : rep (new base_graphics_backend ("unknown"))
+    {
+      rep->count++;
+    }
+
+  graphics_backend (base_graphics_backend* b)
+      : rep (b)
+    {
+      rep->count++;
+    }
+
+  graphics_backend (const graphics_backend& b)
+      : rep (b.rep)
+    {
+      rep->count++;
+    }
+
+  ~graphics_backend (void)
+    {
+      if (--rep->count == 0)
+	delete rep;
+    }
+
+  graphics_backend& operator = (const graphics_backend& b)
+    {
+      if (rep != b.rep)
+	{
+	  if (--rep->count == 0)
+	    delete rep;
+
+	  rep = b.rep;
+	  rep->count++;
+	}
+
+      return *this;
+    }
+
+  operator bool (void) const { return rep->is_valid (); }
+
+  std::string get_name (void) const { return rep->get_name (); }
+
+  void close_figure (const octave_value& pstream) const
+    { rep->close_figure (pstream); }
+
+  void redraw_figure (const graphics_handle& fh) const
+    { rep->redraw_figure (fh); }
+  
+  void print_figure (const graphics_handle& fh, const std::string& term,
+		     const std::string& file, bool mono,
+		     const std::string& debug_file = "") const
+    { rep->print_figure (fh, term, file, mono, debug_file); }
+
+  Matrix get_canvas_size (const graphics_handle& fh) const
+    { return rep->get_canvas_size (fh); }
+
+  OCTINTERP_API static graphics_backend default_backend (void);
+
+  static void register_backend (const graphics_backend& b)
+    { available_backends[b.get_name ()] = b; }
+
+  static void unregister_backend (const std::string& name)
+    { available_backends.erase (name); }
+
+private:
+  base_graphics_backend *rep;
+
+private:
+  static std::map<std::string, graphics_backend> available_backends;
+};
+
+// ---------------------------------------------------------------------
+
 class OCTINTERP_API root_figure : public base_graphics_object
 {
 public:
@@ -1744,9 +1862,20 @@
   class properties : public base_properties
   {
   public:
-    void close (void);
+    void close (bool pop = true);
+
     void set_visible (const octave_value& val);
 
+    graphics_backend get_backend (void) const
+      {
+	if (! backend)
+	  backend = graphics_backend::default_backend ();
+
+	return backend;
+      }
+
+    void set_backend (const graphics_backend& b) { backend = b; }
+
     // See the genprops.awk script for an explanation of the
     // properties declarations.
 
@@ -1813,6 +1942,9 @@
 	pointershapehotspot.add_constraint (dim_vector (1, 2));
 	position.add_constraint (dim_vector (1, 4));
       }
+
+  private:
+    mutable graphics_backend backend;
   };
 
 private:
@@ -1881,6 +2013,12 @@
 
   bool valid_object (void) const { return true; }
 
+  graphics_backend get_backend (void) const
+    { return xproperties.get_backend (); }
+
+  void set_backend (const graphics_backend& b)
+    { xproperties.set_backend (b); }
+
 private:
   property_list default_properties;
 };