All at C?

               Roland Waddilove provides a guiding hand
              through the tangled GEM programming jungle

WELCOME to the first part of a new series exploring GEM from a
programmer's viewpoint. If you have ever wondered how dialog and alert
boxes pop up and windows zoom out and fill the desktop, and wanted to
produce these objects yourself, then read on. This series is for you.

I'll make the programming examples as simple as possible, but inevitably
there will be some quite complex looking functions and devious code.
This will be kept to a minimum and thoroughly explained as we progress
and build up our GEM programming knowledge.

Ideally you'll have a C compiler ready to hand when following this
series, but don't despair if you are a Pascal programmer, Forth fanatic
or even a BASIC boffin as the GEM functions we'll be using have the same
names and use the same parameters whatever the language.

I'll be writing most of the example programs using Digital Wizdom C, and
also providing corresponding HiSoft BASIC listings, too. This month in
the LISTINGS folder you'll find GEM1.C and GEM1.BAS - two programs that
perform identical tasks, one written in C and the other in BASIC. Let's
see how they work.

GEM can be split up into two parts, the AES and the VDI. The AES
(applications environment services) is responsible for creating,
displaying and manipulating windows, dialog boxes and menu bars. The VDI
(virtual device interface) has the task of handling all the graphic
output for GEM. Of the two, the VDI is the easiest to use so that is
where we will start our journey through the tangled jungle of GEM
functions. Once we have mastered the VDI then we'll move on to the AES
and create windows and dialog boxes.

GEM is capable of an amazing variety of graphic and text output - just
think of a paint package like Degas Elite or a DTP Package like Fleet
Street Publisher. Dozens of fill patterns, line types, text styles and
point sizes can easily be output to the screen so GEM needs to keep
track of what effects are currently in use and their settings. This
information is stored in five integer arrays and you'll find them at the
start of most C programs:

short    control[12],
        intin[128],
        ptsin[128],
        intout[128],
        ptsout[128];

These arrays need to be defined, but you shouldn't need to access them
from a high level language. Just define them, then forget about them.
Once these have been defined your application (program) can ask GEM to
initialise them by calling the appl_init() function. This returns an
application identification number which you may need later on so it's a
good idea to remember it:

short app_id;
app_id = appl_init();

When a program has finished and you want to go back to the desktop you
must tell GEM by calling the appl_exit() function. This performs some
tidying up operations, releases the memory reserved for the arrays and
so on.  Two more arrays need to be defined and these tell GEM whether
you are using a monitor or printer, solid lines or dashes, patterned or
solid fills and so on. The vast majority of programs use the following
startup code:

short    work_in[11],
        work_out[57];

short    i;

for ( i=0; i<10; ++i )
    work_in[i] = 1;
work_in[10] = 0;

This sets the various parameters GEM requires to suitable default
values.  Here is a list of the work_in[11] array's functions and the
possible values each item may take (notice that a value of one is
useually a good default):

------------------------------------------------------------------------
work_in[0]    Device id        1 = screen          11 = plotter
                             21 = printer         31 = metafile
                             41 = camera          51 = tablet
------------------------------------------------------------------------
work_in[1]    Linetype         1 = solid            2 = long dashes
                              3 = dots             4 = dashes+dots
                              5 = short dashes     6 = dash, dot, dot
                              7 = user defined    >7 = device dependent
------------------------------------------------------------------------
work_in[2]    Polyline color   0 = white            8 = white
                              1 = black            9 = black
                              2 = red             10 = light red
                              3 = green           11 = light green
                              4 = blue            12 = light blue
                              5 = cyan            13 = light cyan
                              6 = yellow          14 = light yellow
                              7 = magenta         15 = light magenta
------------------------------------------------------------------------
work_in[3]    Marker type      1 = dot              5 = diagonal cross
                              2 = plus sign        6 = diamond
                              3 = asterisk         7 = device dependent
                              4 = square
------------------------------------------------------------------------
work_in[4]    Polymarker       See Polyline colour
             colour
------------------------------------------------------------------------
work_in[5]    Text face
------------------------------------------------------------------------
work_in[6]    Text colour      See polyline colour
------------------------------------------------------------------------
work_in[7]    Fill interior    0 = hollow           1 = solid
             style            2 = patterned        3 = cross hatched
                              4 = user defined
------------------------------------------------------------------------
work_in[8]    Fill style index (37 different fill styles)
------------------------------------------------------------------------
work_in[9]    Fill colour      See Polyline colour
------------------------------------------------------------------------
work_in[10]   Coordinate       0 = map normalised device coordinates to
             system               raster coordinates
                              1 = reserved
                              2 = use raster coordinates
------------------------------------------------------------------------

Unfortunately, I haven't the space here to list the contents of the 57
work_out[] array elements so you'll need a reference manual if you're
interested in the information in that array. It contains data like the
number of colours available, the width and height of characters, the
number of fill patterns on offer and so on.

Fortunately, you can forget work_out[57] for the moment and simply set
work_in[0] to work_in[9] to one and work_in[10] to zero. Once this has
been done you then ask GEM to open a virtual workstation.

A VDI graphic environment is called a workstation which has an
associated number called a handle. The GEM Desktop opens a workstation
for the screen and since all programs are run from the Desktop a program
can't open another workstation for the screen as only one is allowed for
each device. The problem is solved by opening a virtual workstation that
inherits all the features of the currently open workstation. A new
handle is returned for the virtual workstation. Here is the function to
open it:

v_opnvwk(work_in, &handle, work_out);

It requires the address of the work_in[] and work_out[] arrays and also
the address of a variable in which it can store the virtual workstation
handle.

Now that we have initialised the various GEM arrays, got our application
id and opened a virtual workstation what can we do now? The first task
is to clear the screen and this is performed by the v_clrwk(handle)
function. Notice that it requires the handle of the virtual workstation
to clear as there can be more than one at a time.

It would be nice to display a simple message on the screen and we can
easily do this with v_gtext(x,y,string) like:

v_gtext(handle, 16, 16,"This is a test...");
v_gtext(handle, 16, 48,"Click the mouse button...");

Again, notice that the handle is passed as the first parameter. Then
comes the x and y coordinates and the text string. The origin (0,0) is
in the top left corner of the screen and y increases down the screen and
x increases across the screen.

We need time to read the message we are displaying so let's wait until
the mouse button is pressed. The function vq_mouse() reports the
coordinates of the mouse and the state of its buttons:

short x, y, button;
do {
   vq_mouse(handle, &button, &x, &y);
} while ( button==0 );

The value of button is one if the left mouse button is pressed, two if
the right button is pressed and three if both are pressed. This do{ ...
} while() loop waits until any or both buttons are pressed.

When the program has finished the virtual workstation must be closed
down with v_clsvwk(handle) before calling appl_exit() to tell GEM we've
finished.

That is quite enough for one month as there is a lot of information here
to get to grips with. Part two of this series will be on the August
Atari ST User Cover Disc and will document some useful VDI functions.
Don't miss it!

------------------------------------------------------------------------------
A:\LISTINGS\GEM1.C      (HiSoft BASIC version - A:\LISTINGS\GEM1.BAS)
------------------------------------------------------------------------------

/* Using the VDI: Program I */
/*     By R.A.Waddilove     */
/*     Digital Wizdom C     */

/* short is a 16-bit integer and is    */
/* equivalent to most C compilers' int */

short    control[12],             /* These arrays are used by  */
        intin[128],              /* GEM and you don't need to */
        ptsin[128],              /* worry about them. Define  */
        intout[128],             /* them, then forget them.   */
        ptsout[128];

short    handle,                  /* virtual workstation handle */
        app_id;                  /* application's id number */

short    work_in[12],        /* holds various parameters which set the */
        work_out[57];       /* line type, fill pattern, text style etc. */

main()
{
    short i;                     /* loop counter, nothing important */
    app_id = appl_init();        /* initialise GEM AES arrays, return id */
    for ( i=0; i<10; ++i )       /* set line type, text style, fill style */
         work_in[i] = 1;         /* text style and other parameters */
    work_in[10] = 0;             /* raster coordinates ie. pixels */
    v_opnvwk(work_in, &handle, work_out);  /* open virtual workstation */

    v_clrwk(handle);             /* clear the screen */
    v_gtext(handle, 16, 16,"This is a test..."); /* print some text */
    v_gtext(handle, 16, 32,"Click the mouse button..."); /* more text */
    wait();                      /* wait for mouse click */

    v_clsvwk(handle);            /* close virtual workstation */
    appl_exit();                 /* tell GEM we've finished */
}

wait()
{
    short x, y, button;
    do {
         vq_mouse(handle, &button, &x, &y); /* get mouse x,y,button state */
    } while ( button==0 );       /* wait until a button is pressed */
}

------------------------------------------------------------------------------