Event-driven Tasks and Graphical User Interfaces


Introduction

Originally, all tasks within GIPSY were programmed in a procedural fashion. The only event-driven pieces of software were the user interface Hermes, the display server GIDS and the GDS server. (The latter being invisible to the user.)

Event-driven tasks are fundamentally different from procedural tasks. A traditional procedural task, once it has been started, is always in control. It knows when input is expected and what the order of the different pieces of input is. From the beginning things have been made easier in GIPSY by allowing the user to specify inputs in advance at any moment, but the basic scheme was that the task determined what it expected and when it expected it.

An event-driven task, by contrast, is programmed so that it can handle any input at any moment. In this way the user, not the task, is in control.

In GIPSY a quite general way of event handling has been implemented, allowing the task to react to a limited set of different events, like the change of a keyword, the rejection of a keyword due to an error, the availablity of data on a file descriptor, etc.

Using this event handling, a collection of routines has been built, which allows the programmer to construct a graphical user interface for a task. Most of these routines are tightly coupled with user input keywords. In this way the user interface can be programmed and tested separately from the application code. Both components can then be integrated at a later time.

Events and event-handling

Event handling for GIPSY tasks is implemented in roughly three levels. An event-driven task usually consists of a piece of initialization code and a number of, often small, functions which are programmed to react to one or more kinds of events. E.g., there may be a function quit() which will be called when input is given on the keyword QUIT=. The function then may read the keyword by calling userlog_c() and terminate the task when the value TRUE has been read.

In order to accomplish this, quit() must have been registered (``scheduled'') by a call to ScheduleKeyevent(), specifying the function quit(), the keyword QUIT= and some other arguments. The last executable statement in an event-driven task is a call to MainLoop(), which usually does not return. MainLoop() receives all events and calls the functions which have been registered to handle these events.

When MainLoop() has been called, it is still possible that new event-handling functions are registered. This is then done from within other event handlers, e.g. as the result of some user action. Event handlers can also be de-registered, for keyword events for instance by calling DescheduleKeyevent().

It is also possible that there are more handlers for one keyword. In this case all handlers are called. The handler which was registered last, will be called first. Similarly one function can be registered more than once for different keywords. The function knows which keyword caused the event and can act accordingly.

Graphical User Interfaces and Ggi

Ggi (``GIPSY graphical interface'') is a collection of routines which allows the programmer to construct a simple graphical user interface for a task. It is based on the X Toolkit and the almost universally available Athena widgets. It makes use of GIPSY's event-handling facilities.

The following kinds of elements are available:

Every text field, button, menu or valuator is associated with a user input keyword. E.g. when a button is pressed, the associated keyword is set to the value TRUE. This keyword change then causes an event which can be received by the application code. Reversely, when a keyword is changed, either by the user or by the task itself by calling wkey_c(), an event is generated which is (also) received by Ggi. Ggi then updates all elements with which the keyword is associated.

A text output field is an element that can only display text.

A plot field is the Ggi-based implementation of a PGPLOT device. It has the same capabilities as GIPSY's X11 plot server, except that cursor interaction is implemented differently. An application can have multiple plot fields.

A text editor can be used to display and/or modify larger amounts of text, e.g. documentation, log files, directives, etc. It can work either on a text string in memory or on a file on disk.

A canvas is a simple element without any built-in behaviour. It can be used as a basic display window which must be manipulated using X library routines.

The elements in a graphical user interface can be positioned in two ways. The easiest way is letting Ggi place them automatically. The elements will then be put into one of three panes: the top pane will contain all menus, the bottom pane all buttons and the middle pane all other elements. This kind of placement is adequate for very simple interfaces and for testing.
It is also possible to position the elements explicitly. This can be done relative to the left and top edge of the task's main window or relative to the right and bottom edge of other elements.

SKYTOOL
Figure: example graphical user interface

Ggi mini-tutorial

The Ggi interface routines are described in the document ggi.dc2.
The following examples can be studied:
  1. A simple example showing the use of text fields, analog valuators and menus.
  2. Identical to the previous example, except that the positioning of the elements is explicitly done by the program.
  3. An illustration of the simple use of plot fields.
  4. Identical to the previous example, except that cursor interaction has been added to the plot field.
  5. Doing lengthy calculations.
  6. Suppressing keyword events.
  7. Plot fields, images and color maps
  8. Plot field color map manipulation
  9. Containers and pop-up shells
    1. Simple general purpose pop-ups: yes/no questions, prompts
    2. File browser, input sets and boxes.

Programming GIPSY Maintained by J. P. Terlouw