"To be, or what?"
Sylvester Stallone
GEM PROGRAMMING - AN IDIOT'S GUIDE
FOR THE ASSEMBLER PROGRAMMER
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
properly! 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
order):
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
'workstation')
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
rts
* 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
rts
* This stuff goes in your DATA section
DATA
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
rts
DATA
* 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
BSS
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
stack:
-----------------------------------------------------------------
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.
Disclaimer
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.