# HG changeset patch # User Pantxo Diribarne # Date 1516566381 -3600 # Node ID 58dd3c2d5db8c512eac1e30118ec4cae26b6cd76 # Parent be37df6e1fb4fd1e7e2b31f977702928ec8b065b 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. diff -r be37df6e1fb4 -r 58dd3c2d5db8 doc/interpreter/genpropdoc.m --- 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; diff -r be37df6e1fb4 -r 58dd3c2d5db8 doc/interpreter/plot.txi --- 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) diff -r be37df6e1fb4 -r 58dd3c2d5db8 libinterp/corefcn/graphics.cc --- 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)); }