Skip to main content

 "To be, or what?"
                                               Sylvester Stallone

                             PART I
                   by Ciaran 'Ringpull' Wills

 Like it or (more likely) loathe it,  GEM is something all us  ST
owners have to live with,  and now with the advent of  "MultiTOS"
it is important that people write GEM applications and write them
   I have been using "MultiTOS" for a few months now and
it is extremely annoying to find that many of the programs I  use
will not work.   "Protext",  for example,  provides its own (non-
GEM)  user  interface  and "Pagestream 2"  does  its  own  memory
management  (not exactly management,  more a case of grabbing  it
all and not letting anyone else use it).

 This tutorial is aimed at anyone who wants to program with  GEM.
It is specifically aimed at the assembler programmer but users of
other languages should also be able to extract something from  it
as  the  GEM calls are the same whatever language  you  use.   So
whether  you have just read a magazine tutorial on assembler  and
learnt to print your name on the screen using GEMDOS calls or are
a  master demo coder who wants to write something  slightly  more
useful, here we go...

 First of all I shall assume that everyone knows what GEM is, and
what menus, windows and dialoge boxes are.  I shall also assume a
basic knowledge of 68000 assembler, so if you are a little unsure
about this you would probably find it useful to have a  reference
book  nearby.   This first part will contain a lot of theory  but
after  this we shall use some examples and (heaven forbid) I  may
even set you some tasks to put your newfound knowledge to use.

Part 1 - Lots of theory

 GEM  is  a set of routines present in the ROMs of  your  ST  and
provide  routines  to  do  all  the  hard  work  of  writing   an
application for you,  such as handling the mouse, the windows and
menus. GEM consists of two main parts: the AES and the VDI.

 The  AES (Application Environment Services) deal with  the  WIMP
(Windows, Icons, Menus/Mice and Pointer) aspects of GEM.  The VDI
(Virtual Device Interface) deals with various output devices such
as the screen, printer, plotters, etc...
 To put it simply you use the AES to open your window and the VDI
to put stuff in your window.

 OK,  so how do we tell GEM to do these things?   GEM is accessed
through trap #2,  but not in the same way as GEMDOS or the  BIOS.
Before the trap #2 instruction registers d0 and d1 must be set up
as follows:

d0 - function number:
        #$c8 for the AES
        #$73 for the VDI
d1 - Address of AES/VDI parameter block

 The  AES and VDI parameter blocks are arrays of pointers to  the
data needed for the call.
 The AES parameter block contains the following pointers (in this

 Control - Pointer to an array of words giving details about  the
function. The control array contains the following data:

        word    contents

        0       Function number of AES call
        1       Number of words in the 'intin' array
        2       Number of words in the 'intout' array
        3       Number of words in the 'addrin' array
        4       Number of words in the 'addrout' array

 Global  - Pointer to an array of words which I haven't  found  a
use for yet!  I'm sure there is a reason for them being there but
I just leave them empty.

 Intin - Stands for integers in.   An array used for passing data
to the AES call.

 Intout  - Stands for integers out.   An array used to pass  data
back from the call.

 Addrin - Addresses in.   An array with any addresses to any data
required by call.

 Addrout - Addresses out.  An array for returning addresses.

 The VDI parameter block is similar:

 Control  -  Similar to the AES control array but  the  following
data is contained in it:

        word    contents

        0       Function code of VDI call required
        1       Number of items in ptsin array
        2       Not used (i.e. I don't know)
        3       Number of items of data in intin array
        6       Work-station handle (supplied when you open a VDI

 Intin - Same as AES intin.

 Ptsin - Array of coordinate points to pass to call.

 Intout - Same as AES intout

 Ptsout - Coordinate points passed back to program.

 So to make AES & VDI calls in your programs your program  should
contain the following:


* Subroutine to make an AES call, assume all arrays are filled as
* required
aes:    movem.l d0-a6,-(sp)     ; Save registers
        move.l  #aespb,d1       ; Address of AES parameter block
        move.l  #$c8,d0         ; AES function number
        trap    #2              ; Do it!
        movem.l (sp)+,d0-a6     ; Restore registers
* VDI subroutine
vdi:    movem.l d0-a6,-(sp)     ; Save registers
        move.l  #vdipb,d1       ; Address of VDI parameter block
        moveq   #$73,d0         ; VDI function number
        trap    #2              ; Do it!
        movem.l (sp)+,d0-a6     ; Restore registers
* This stuff goes in your DATA section
aespb:  DC.L    contrl,global,intin,intout,addrin,addrout
vdipb:  DC.L    contrl,intin,ptsin,intout,ptsout

contrl: DS.W    128
global: DS.W    16      ; This one doesn't have to be so big
intin:  DS.W    128
intout: DS.W    128
addrin: DS.W    128
addrout: DS.W   128
ptsin:  DS.W    128
ptsout: DS.W    128


 That  was  all a bit theoretical so now we will put some  of  it
into  practise.   We  will  disregard the VDI for  a  moment  and
concentrate on the AES.
 The  following program will simply display an alert box  on  the
screen and then quit. It makes a total of 3 AES calls:

appl_init:     This  call should be made by all GEM  programs  as
               soon  as they start.   It lets the AES  know  that
               they may require its services.

form_alert:    Displays an alert box for us.

appl_exit:     Tells AES that the program is about to quit.

 This program also starts off with a snippet of code known as the
'GEM header'.  You will (or at least you should) find this at the
start of all applications.  It is needed because when the ST runs
a program it gives it all the free memory.   The GEM header gives
back  the memory which is not required by the program.   We  will
not  worry about how it works here,  just remember to use  it  in
your programs!
 You   should  also  be  able  to  find  this  program   in   the
":\PROGRAMS\GEM\" folder on this disk (I hope!).


* A simple demonstration program to make some AES calls
* Displays an alert box

* The GEM header...
        move.l  sp,a5
        lea     stack,sp        ; Set up our own stack
        move.l  4(a5),a5
        move.l  12(a5),d0
        add.l   20(a5),d0
        add.l   28(a5),d0       ; Work out memory required
        add.l   #256,d0         ; Be on the safe side!
        move.l  d0,-(sp)
        move.l  a5,-(sp)
        clr     -(sp)           ; Dummy value
        move    #$4a,-(sp)      ; GEMDOS #$4a: Mshrink
        trap    #1
        lea     12(sp),sp       ; Fast way to add 12 to sp
* End of the GEM header

* appl_init call
        move.l  #appl_init,aespb
        bsr     aes

* form_alert call
        move.l  #form_alert,aespb
        move    #1,intin        ; Default button (outlined)
        move.l  #alert_string,addrin    ; Address of text string
        bsr     aes

* appl_exit call
        move.l  #appl_exit,aespb
        bsr     aes

* Now quit properly (Pterm)
        clr     -(sp)
        trap    #1

* The aes subroutine
aes:    movem.l d0-a6,-(sp)
        move.l  #aespb,d1
        move.l  #$c8,d0
        trap    #2
        movem.l (sp)+,d0-a6

* Control arrays for AES calls
appl_init: DC.W 10,0,1,0,0
appl_exit: DC.W 19,0,1,0,0
form_alert: DC.W 52,1,1,1,0

alert_string: DC.B '[1][This is a sample GEM program!][ Wow! ]',0

aespb:  DC.L    contrl,global,intin,intout,addrin,addrout
vdipb:  DC.L    contrl,intin,ptsin,intout,ptsout
contrl: DS.W    128
global: DS.W    16
intin:  DS.W    128
intout: DS.W    128
addrin: DS.W    128
addrout: DS.W   128
ptsin:  DS.W    128
ptsout: DS.W    128
        DS.B    1024


 Assemble  this and see what happens. Now we will have  a  closer
look at what is happening.
 First of all the appl_init call is made.   This is done using  a
ready-made control array and placing a pointer to it in its place
in the parameter block.   Then the call is carried out by calling
the AES subroutine.   The appl_init call returns our  application
ID in the intout array but we can ignore this.
 Next  comes the form_alert call which displays an alert box  and
waits  for  a button to be selected.   First the pointer  to  the
contrl  array  is placed in the parameter block then  the  inputs
required for this call are placed in the correct arrays:
 The first word in the intin array should contain the number (1,2
or  3)  of  the default exit button  (Outlined  and  selected  by
pressing return) or zero if the is to be no default button.
 The first longword of the addrin array should be the address  of
the text string to be used for the alert box.  The string has the
following format:

 '[icon number][message][text for buttons]'

 The string should end with a zero byte.

 The icon number can be any of the following:

        Number  Icon

        0       None
        1       Exclamation mark
        2       Question mark
        3       Stop sign

 In the above example an exclamation mark was used.

 The message can be 5 lines long with a max of 40 characters  per
line. Lines are separated by a vertical bar ('|') like so:

 [This is line 1|This is line 2]

 Note that the text is left justified so if you want your message
centered  in the box you will have to use spaces to pad  it  out.
Also,  when no icon is used in the box it is best to put a couple
of spaces before and after each line or the edges of the box come
unpleasently close to the text.

 A maximum of 3 buttons can be used and the text for each  button
is separated by a vertical bar ('|').  A maximum of 20 characters
can  be  used in a button although this is reduced if  there  are
more  than one button.   An example of a three-button  alert  box
string is:

 '[2][ Would you like | to continue? ][ YES | NO | MAYBE ]'

 The  form_alert call returns with the number (1,2 or 3)  of  the
button which was selected in the first word of the intout  array.
Try  changing  the alert box string in the  example  program  and
experiment with multiple buttons.

 The last call,  appl_exit, tells the AES that we are about quit.
No inputs are required for this call.   Note that this call  does
not  actually cause your program to exit,  it only tells the  AES
that it is about to,  so you must then exit with a GEMDOS call #0
(Pterm0) or #76 (Pterm).

 This  is  the  end of this first instalment but  while  you  are
waiting  for  your  next  issue  of  ST  NEWS  try  this  month's
programming exercise:
 Write  a program wich will ask the user whether he/she  owns  an
ST,  an  Amiga  or neither of these.   You may make  up  suitable
comments  for  each  answer.   You may wish  to  expand  this  by
providing furthur options if 'neither' was selected. 

The text of the articles is identical to the originals like they appeared in old ST NEWS issues. Please take into consideration that the author(s) was (were) a lot younger and less responsible back then. So bad jokes, bad English, youthful arrogance, insults, bravura, over-crediting and tastelessness should be taken with at least a grain of salt. Any contact and/or payment information, as well as deadlines/release dates of any kind should be regarded as outdated. Due to the fact that these pages are not actually contained in an Atari executable here, references to scroll texts, featured demo screens and hidden articles may also be irrelevant.