changeset 24626:58dd3c2d5db8

Document and fix "busyaction" an "interruptible" properties (bug #52804). * graphics.cc (gh_manager::do_execute_listener): Don't take "interruptible" into account for listeners (revert a56d283ff18a). (gh_manager::do_execute_callback): Make sure the mutex is unlocked after the graphics object has been accessed. (F__get_frame__): Process graphics events for ML compatibility. * genpropdoc.m: Document "busyaction" and "interruptible" properties. * plot.txi (Callback section): Document how the graphics callbacks are executed depending on busyaction and interruptible properties.
author Pantxo Diribarne <pantxo.diribarne@gmail.com>
date Sun, 21 Jan 2018 21:26:21 +0100
parents be37df6e1fb4
children a79f782653ce
files doc/interpreter/genpropdoc.m doc/interpreter/plot.txi libinterp/corefcn/graphics.cc
diffstat 3 files changed, 89 insertions(+), 59 deletions(-) [+]
line wrap: on
line diff
--- a/doc/interpreter/genpropdoc.m	Sat Jan 20 09:29:07 2018 +0100
+++ b/doc/interpreter/genpropdoc.m	Sun Jan 21 21:26:21 2018 +0100
@@ -136,6 +136,15 @@
     switch (field)
       case "beingdeleted"
       case "busyaction"
+        s.doc = "Define how Octave handles the execution of this object's \
+callback properties when it is unable to interrupt another object's \
+executing callback.  This is only relevant when the currently executing \
+callback object has its @code{interruptible} property set to \
+\@qcode{\"off\"}.  The __prop__ property of the interrupting callback object \
+indicates whether the interrupting callback is queued (@qcode{\"queue\"} \
+(default)) or discarded (@qcode{\"cancel\"}).\n\
+@xref{Callbacks, , @w{Callbacks section}}.";
+        
       case "buttondownfcn"
         s.doc = "__fcnmsg__";
         s.valid = valid_fcn;
@@ -174,6 +183,12 @@
 property.  @xref{XREF__objname__pickableparts, , @w{pickableparts property}}.";
 
       case "interruptible"
+        s.doc = "Specify whether this object's callback functions may be \
+interrupted by other callbacks.  By default __prop__ is @qcode{\"on\"} \
+and callbacks that make use of @code{drawnow}, @code{figure}, @code{waitfor}, \
+@code{getframe} or @code{pause} functions are eventually interrupted.\n\
+@xref{Callbacks, , @w{Callbacks section}}.";
+        
       case "parent"
         s.doc = "Handle of the parent graphics object.";
         s.valid = valid_handle;
--- a/doc/interpreter/plot.txi	Sat Jan 20 09:29:07 2018 +0100
+++ b/doc/interpreter/plot.txi	Sun Jan 21 21:26:21 2018 +0100
@@ -1184,12 +1184,12 @@
 
 Graphics handles may be distinguished from function handles
 (@pxref{Function Handles}) by means of the function @code{ishghandle}.
-@code{ishghandle} returns true if its argument is a handle of a graphics object.
-In addition, a figure or axes object may be tested using @code{isfigure} or
-@code{isaxes} respectively.  To test for a specific type of graphics handle,
-such as a patch or line object, use @code{isgraphics}.  The more specific test
-functions return true only if the argument is both a graphics handle and of the
-correct type (figure, axes, specified object type).
+@code{ishghandle} returns true if its argument is a handle of a graphics
+object.  In addition, a figure or axes object may be tested using
+@code{isfigure} or @code{isaxes} respectively.  To test for a specific type of
+graphics handle, such as a patch or line object, use @code{isgraphics}.  The
+more specific test functions return true only if the argument is both a
+graphics handle and of the correct type (figure, axes, specified object type).
 
 The @code{whos} function can be used to show the object type of each currently
 defined graphics handle.  (Note: this is not true today, but it is, I hope,
@@ -1870,7 +1870,7 @@
 @example
 @group
 function mycallback (hsrc, evt)
-@dots{}
+  @dots{}
 endfunction
 @end group
 @end example
@@ -1880,38 +1880,52 @@
 gives some event specific data.
 
 The function can be provided as a function handle to a plain Octave function,
-as an anonymous function or as a string representing an Octave command.  The
+as an anonymous function, or as a string representing an Octave command.  The
 latter syntax is not recommended since syntax errors will only occur when the
 string is evaluated.
 @xref{Function Handles Anonymous Functions Inline Functions, , Function Handles section}.
 
-This can then be associated
-with an object either at the objects creation or later with the
-@code{set} function.  For example,
+This can then be associated with an object either at the object's creation, or
+later with the @code{set} function.  For example,
 
 @example
 plot (x, "DeleteFcn", @@(h, e) disp ("Window Deleted"))
 @end example
 
 @noindent
-where at the moment that the plot is deleted, the message "Window
-Deleted" will be displayed.
-
-Additional user arguments can be passed to callback functions, and will
-be passed after the 2 default arguments.  For example:
+where at the moment that the plot is deleted, the message "Window Deleted" will
+be displayed.
+
+Additional user arguments can be passed to callback functions, and will be
+passed after the two default arguments.  For example:
 
 @example
 @group
 plot (x, "DeleteFcn", @{@@mycallback, "1"@})
 @dots{}
-function mycallback (h, e, a1)
-  fprintf ("Closing plot %d\n", a1);
+function mycallback (h, evt, arg1)
+  fprintf ("Closing plot %d\n", arg1);
 endfunction
 @end group
 @end example
 
-The basic callback functions that are available for all graphics objects
-are
+@strong{Caution:} The second argument in callback functions---@code{evt}---is
+only partially implemented in the Qt graphics toolkit:
+
+@itemize @bullet
+@item Mouse click events:
+@code{evt} is a class @code{double} value: 1 for left, 2 for middle, and 3 for
+right click.
+
+@item Key press events:
+@code{evt} is a structure with fields @code{Key} (string), @code{Character}
+(string), and @code{Modifier} (cell array of strings).
+
+@item Other events:
+@code{evt} is a class @code{double} empty matrix.
+@end itemize
+
+The basic callback functions that are available for all graphics objects are
 
 @itemize @bullet
 @item CreateFcn:
@@ -1926,30 +1940,37 @@
 
 @item ButtonDownFcn:
 called if a mouse button is pressed while the pointer is over this
-object.  Note, that the gnuplot interface does not respect this
+object.  Note, that the gnuplot interface does not implement this
 callback.
 @end itemize
 
-@strong{Caution:} the second @code{evt} argument in callback functions is only
-loosely implemented in the Qt graphics toolkit:
-
-@itemize @bullet
-@item Mouse click events:
-@code{evt} is a class @code{double} value, 1 for left, 2 for middle and 3
-for right click.
-
-@item Key press events:
-@code{evt} is a structure with fields @code{Key} (string), @code{Character}
-(string) and @code{Modifier} (cell array of strings).
-
-@item Other events:
-@code{evt} is a class @code{double} empty matrix.
-@end itemize
-
-
-The object and figure that the event occurred in that resulted in the
-callback being called can be found with the @code{gcbo} and @code{gcbf}
-functions.
+By default callback functions are queued (they are executed one after the other
+in the event queue) unless the @code{drawnow}, @code{figure}, @code{waitfor},
+@code{getframe}, or @code{pause} functions are used.  If an executing callback
+invokes one of those functions, it causes Octave to flush the event queue,
+which results in the executing callback being interrupted.
+
+It is possible to specify that an object's callbacks should not be interrupted
+by setting the object's @code{interruptible} property to @qcode{"off"}.  In
+this case, Octave decides what to do based on the @code{busyaction} property of
+the @strong{interrupting} callback object:
+
+@table @asis
+@item @code{queue} (the default)
+The interrupting callback is executed after the executing callback has
+returned.
+
+@item @code{cancel}
+The interrupting callback is discarded.
+@end table
+
+The @code{interruptible} property has no effect when the interrupting callback
+is a @code{deletefcn}, or a figure @code{resizefcn} or @code{closerequestfcn}.
+Those callbacks always interrupt the executing callback.
+
+The handle to the object that holds the callback being executed can be
+obtained with the @code{gcbo} function.  The handle to the ancestor figure
+of this object may be obtained using the @code{gcbf} function.
 
 @DOCSTRING(gcbo)
 
--- a/libinterp/corefcn/graphics.cc	Sat Jan 20 09:29:07 2018 +0100
+++ b/libinterp/corefcn/graphics.cc	Sun Jan 21 21:26:21 2018 +0100
@@ -10223,20 +10223,6 @@
 gh_manager::do_execute_listener (const graphics_handle& h,
                                  const octave_value& l)
 {
-  if (! callback_objects.empty ())
-    {        
-      const graphics_object& current = callback_objects.front ();
-
-      if (current.valid_object () 
-          && ! current.get_properties ().is_interruptible ())
-        {
-          if (get_object (h).get_properties ().busyaction_is ("queue"))
-            do_post_event (graphics_event::create_callback_event (h, l));
-
-          return;
-        }
-    }
-
   if (octave::thread::is_thread ())
     gh_manager::execute_callback (h, l, octave_value ());
   else
@@ -10266,11 +10252,16 @@
       octave::unwind_protect_safe frame;
       frame.add_fcn (gh_manager::restore_gcbo);
 
-      gh_manager::auto_lock guard;
       graphics_object go (get_object (h));
-      callback_objects.push_front (go);
-      if (go.get ("handlevisibility").string_value () != "off")
-        xset_gcbo (h);
+      if (go)
+        {
+          // FIXME: Is the lock necessary when we're only calling a
+          //        const "get" method?
+          gh_manager::auto_lock guard;
+          callback_objects.push_front (go);
+          if (go.get ("handlevisibility").string_value () != "off")
+            xset_gcbo (h);
+        }
 
       // Copy CB because "function_value" method is non-const.
 
@@ -12460,5 +12451,8 @@
   if (! go || ! go.isa ("figure"))
     error ("__get_frame__: HFIG is not a figure");
 
+  // For Matlab compatibility, getframe must flush the event queue.
+  gh_manager::process_events ();
+
   return ovl (go.get_toolkit ().get_pixels (go));
 }