From octave-graphics-request at bevo dot che dot wisc dot edu Fri Aug 25 12:20:04 2000 Subject: GUI needs From: Paul Kienzle To: octave-graphics at bevo dot che dot wisc dot edu Date: Fri, 25 Aug 2000 18:20:22 +0100 Before wading into which graphing/GUI package to use, I want to summarize what we need from the GUI and what the GUI needs from Octave. Ideally, we should allow multiple independent figures to each have a interactive widgets. These should all be able to run in parallel without interfering with the octave command line. The GUI should be responsive even when a large computation is going on in the background. Widgets need to be able to signal callbacks which are arbitrary expressions evaluated in octave. For compatibility with matlab, the callbacks should execute in the top level context, with read/write/create access to all top level and global variables. Keeping the GUI responsive is straightforward. It's event loop must be in a separate process or thread from eval so that window exposures can be handled even while callbacks are being evaluated. Keyboard and mouse events which trigger callbacks should be ignored while evals are in progress, except for Ctrl-C, which should signal an interrupt in the eval process. Communication from octave to the GUI is straightforward as well. Because events in the event loop are quick to process, the event loop can be combined with a message queue containing commands from Octave. The trick is callbacks. Ideally, each callback would execute in its own thread so that figures would not block one another. To do this properly, the octave interpreter and every built-in and external function would have to be thread-safe, with semaphore access to globals and top level variables. This isn't going to happen any time soon, since not only all of the interpreter and liboctave must be safe, but everything in libcruft as well. If, however, we make the interpreter and liboctave thread-safe, we can use coarse grain locking around things in libcruft which are not known to be safe. An alternative approach is to fork for each callback, which removes the thread-safe requirement, but globals and top level variables would need to be communicated (via pipes or via shared memory and locking). This is feasible, especially in linux where fork() is cheap, but still a lot of work. The quickest solution is to only process callbacks during the idle time of the read-eval-print loop. When eval starts, it sends a "wait" to the GUI so that it can (after a reasonable delay) change to an hourglass cursor and supress input. When no callbacks are pending, it sends a "clear" to the GUI to return to the usual mouse pointer. You can think of this as really coarse-grained locking. I'm not sure what happens if a callback triggers another callback. The question remains, however, how the GUI signals a callback. One strategy is to use a signal. If Octave is multi-threaded, the signal could trigger the creation of a new thread which asks the GUI which callback should be evaluated. If Octave is single-threaded, the signal sets a flag which tells the read-eval-print loop to query the GUI for the next callback during the next idle period. This keeps the communication on the Octave-GUI pipe synchronous, but requires a callback queue on the GUI side. Another callback strategy is to write the next callback directly to the pipe. If Octave is multi-threaded, one thread will have to sleep on the pipe, waking up for each message and spawning a new process if it is a callback, or storing it and waking the query if it is a query response. If Octave is single-threaded, the read-eval-print loop simply checks for a callback on the pipe during idle. Note that it is possible for a callback to be posted to the pipe just when a query has been posted to the GUI. In this case, the Octave side of the query will have to queue any callback requests it receives while waiting for the response. The second strategy is made nicer if Octave maintains the entire state of the GUI, using the GUI process as a simple print engine. Then queries do not have to be passed to the GUI and there is no conflict on the pipe. Any state change in the GUI could be signalled with a callback. Note that this discussion is independent the sort of GUI we implement. It applies just as much to TCL/TK or VTK as to an integrated GUI. An integrated GUI would be faster: communication over a pipe is 50% slower than copying memory directly (at least on my machine). For complicated GUIs, e.g., a simulink interface or a .WAV file editor, built with m-files, callbacks and low level line drawing routines, the overhead may be too much. However, the flexibility of using a separate application is a big win. It is not clear to me how much of the graphics support we want in Octave and how much in the GUI application. If we want any hope of running existing matlab GUIs, I think we will need most of it to be done in Octave itself. I would start with GTK because it is the beast I know, using GtkPlot for 2D plots and the display widget from superficie for 3D plots. I would avoid plplot because its font support is weak, and because 3D is best done with openGL so that you can get the benefits of hardware acceleration. wxWindows is tempting for cross-platform support, but gtk works under windows now, so this isn't a clear win. Paul Kienzle pkienzle at kienzle dot powernet dot co dot uk