
                         GEM PROGRAMMING         Article II
                               By Jonathan White

                               Initialising GEM
                               ================

    This month we have  a  slight  change.  As  well  as  the straight text
    provided last month, this  month  we  have  several more word-processor
    friendly formats. As I recently bought  Atari  Works (a good example of
    GEM programming in itself) I'm going  to  use  that to put the articles
    together. I'm also using the  standard  SpeedoGDOS  font set, so if you
    have Atari Works, you should be able to  print  it out just as I set it
    up. For those without AW,  but  who  do have a relatively sophisticated
    word processor, I'll be providing a copy in RTF format. Plus, for those
    who would rather lay the stuff  out themselves, I'll include a straight
    text, saved from AW. This  also  allows  me  to incorporate diagrams if
    they come in useful. I don't think we'll need any this month, but as we
    get more into the GEM programming of menus, windows and dialogs, I hope
    they'll help to make things  clearer.  This,  of course, presumes I can
    draw..

    */ As there is insufficient room on the disk for all three formats only
    the ASCII version is published here.  If any member would like the  RTF
    or Atari Works version  please send a blank  disk and postage to us and
    we will return it with the required version. ICTARI /*

    Also, we shall be providing 'quick  reference'  cards to any function I
    mention. These won't be a comprehensive  list of GEM's functions by any
    means, but they will help to give you a base to expand from.

    Before we  start,  One  important  point.  The  initialisation  of  GEM
    requires the use of  several  arrays,  which  are  filled either by the
    programmer  during  initialisation,  or  by   the  system  with  useful
    information. I searched through the  Atari Compendium for ages, looking
    for them in the relevant section.  Turns  out  they are detailed in the
    section for the function which uses them. So, if you are confused (as I
    often am..) that should put you  on  the  right  track. As to the Atari
    Compendium itself, well I  haven't  set  a  textbook,  and you won't be
    examined at the end, but  if  you  were  and  I  was,  that'd be it :).
    Seriously, it is the only  complete  up-to-date  reference on the Atari
    system, and although it is on the  expensive side, I can't recommend it
    enough.

    So, after the preliminaries, on we go. For any GEM program to function,
    it is usually the case  that  three  'stages' of initialisation must be
    followed. The order these  three  stages  are  performed  in is not too
    important  and there are certain limited cases where one or more can be
    ignored totally. However, as they fall vaguely into the same topic, and
    most major GEM programs need all three, we'll look at them all here.

    They are :-

    a)   Initialising  the  AES  (if  this   fails,   your  app  MUST  quit
    immediately)

    b)   Initialising the VDI and  opening  a  virtual workstation (if this
    fails, your app  might  still  be  OK,  depending  upon  it's function.
    However it's not advised to continue.)

    c)   Loading a resource file  (if  you  can't,  you  can  at least quit
    gracefully).

    While on the general subject  of  resources  (which  we will come to in
    detail in a  future article) some  programmers prefer to embed resource
    files in programs. I prefer not  to.  Although  it  is one more file to
    lose / become corrupted /delete  by  accident, a separate resource file
    has several advantages.

    a)   It  allows  for  easy  translation  of  your  program  to  foreign
    languages (in fact, you  don't  even  have  to  do  it. Often, users in
    another country will do it themselves.  Dubious in  terms of copyright,
    of course.)

    b)   It often allows you to add features to your program without having
    to recompile. Mainly in this case I am thinking of the colour icons and
    3D resources of  AES  4.0  onwards.  Here,  these  features are totally
    independent of the code the  program  runs,  as their interpretation is
    handled entirely by the AES.

    c)   It allows you to 'mock up' addons to your program. You add, say, a
    new menu item. then you code  the  routine which detects that item into
    your If.. then..  else (proper C  programmers  use a CASE statement, by
    the way) loop. If it detects the  new menu item correctly, you can then
    go onto the code that 'reacts' to the new menu item.

    A)   Initialising the AES

    The first thing we must do  is  declare  to  the system we are going to
    start a  GEM  application.  This  involves  calling  the  AES  function
    appl_init. This function  returns  the  applications global identifier.
    This is a variable that identifies your application. If you require it,
    you can ask the system  for  other  application's identifiers, and send
    messages to them. This allows desk accessories to co-operate, and under
    a multi-tasking OS, allows programs  to  co-operate. So, for example, a
    program could start a separate  program  to  print  out  a file - often
    called a child process - and continue  on with it's own processing. The
    child process could  send  messages  to  the  main  program, called the
    parent process, on how it was  doing.  To identify if a certain program
    is running, that  function appl_find()  is  used,  with the filename of
    the program you wish to find as  a parameter. This returns the programs
    global identifier. If you are  not  sure  of this, the further function
    appl_search  allows  you  to  'step   through'  all  currently  running
    programs. However, this function is  only  available in AES version 4.0
    and above. Then, the function appl_write  is  used to send a message to
    that application. That application then  uses  appl_read to examine the
    message. The message itself can be very  variable,  and it is up to the
    programmer  to  make  sure  his  applications  are  speaking  the  same
    language.

    Quite a good idea, and simple yes?  well, no actually. In typical Atari
    style appl_init has a bug. In  early  versions of the function bindings
    provided by Atari, the function always  returned  1. That made all this
    stuff useless. However, there's another  way  to find a programs global
    identifier and that also provides us  with much useful information. All
    current C compilers initialise a global array when appl_init is called.
    The first item in that array  of  WORD values is the global identifier.
    Also in this array is the version  of  the AES running, whether the AES
    running can multitask, and a  few  other  important items. However, the
    exact name of this array depends  upon  the  compiler you are using, so
    you should check the  documentation  for  your  compilers GEM bindings.
    Also, later version of the  AES  (TOS  4.0  and MTOS above) provide the
    function appl_getinfo which provides more  information about the system
    to the programmer. Now you  begin  to  see  the benefits of upgrades to
    operating systems. All of  these  functions  are  fully detailed in the
    Compendium, and the  important  details  are  summarised  on  the quick
    reference sheets.

    So, to initialise the AES we can follow the following steps..

    Call appl_init
                   If appl_init returns -1, the AES cannot be used, and the
    application must quit immediately.

                   If appl_init returns other, we can read the global array
                   and,  if  it  is  available,  call  app_getinfo to  gain
                   information about the system.  (all the  information  is
                   listed in the reference sheets)

    If appl_init works OK, we can go on to make a call to a function called
    graf_handle. this gives us  some  information  as  to  the  size of the
    characters GEM is using, and returns the handle (a handle is like an ID
    number) of the screen, which we  need  to  initialise the VDI. Which is
    what we move on to next.

    2)   Initialising the VDI

    This is, unfortunately, a little  more  complex. The VDI is initialised
    by the call v_opnvwk, which requires one  array set up as input, called
    work_in, and one  to  fill  with  output  called work_out (surprisingly
    enough). It  also  returns  another  handle,  which  you  need  to draw
    graphics or print  text  on  the  screen.  This  handle  is  set in the
    beginning to the value  returned  by  graf_handle above. However, after
    the function is called, the variable has changed value. It now contains
    the VDI workstation handle. Obviously,  since  you might still need the
    AES handle (officially called the physical  screen handle) you would be
    better using separate variables, and setting them accordingly.

    An important thing  to  note  is  that  this  function  opens a virtual
    workstation - since the  system  needs  to  keep  the  screen for other
    programs or DA's, it filters any  output  you give. If you are printing
    to a printer via  GDOS,  you  open  the  printer  as a REAL workstation
    (using v_opnwk ) because two applications can't print to the printer at
    once, so you are free to have unrestrained access to it.

    The contents  of  work_in  and  work_out  are  detailed  in  the  quick
    references. However, we can at least  say  that  they can be studied to
    find the number of colours  a  device  can display, the various graphic
    functions which it can do, plus other useful pieces of information. One
    value of work_in is  important  because  it  defines whether the system
    will use actual screen co-ordinates, or what is called Normalise Device
    Co-ordinates. The NDC system basically  treats  the  screen as a device
    that is 32767 dots across and wide.  This means that, regardless of the
    actual resolution, a square that is  16384  by 16384 'pixels' wide will
    always cover a quarter of the screens area. This system also helps when
    producing 'wysiwyg' graphics, as you can  use the same co-ordinates for
    screen  and  printer.  GEM   scales   the  output  correctly,  although
    maintaining the aspect ratio is not catered for.

    The final function which you  might  use  when  initialising the VDI is
    called vq_extnd(). This  provides  further  info  about  the device you
    specify the VDI handle for.

    If v_opnvwk returns 0, you cannot  use  the VDI and something is wrong.
    In this case it is best  to  quit  the application, possibly showing an
    alert box to inform the user  that  the  VDI  is not available for some
    reason.

    Between these two sets of functions, you  can gain a lot of information
    about the system you are running on.  We can find out how many  colours
    the screen can show, how tall or wide it is, whether there is a palette
    or the screen is 'truecolour'.  Thus,  you  can  write a program which,
    like Gemview, for example,  runs  on  all  Atari  hardware. With clever
    programming, you can write a program  that  not  only runs on all Atari
    computers, but will even take advantage of any extra graphic facilities
    that the display might have.

    3)   Loading the Resource File

    I've already said why I  think  you  should  use resource files, but up
    until now, I haven't mentioned them much. The manipulation of resources
    (menus and dialog boxes) is perhaps  the  most complicated part of GEM,
    but it's also the most important. Resources are the part of the program
    which you show to the user  and  therefore  are important. But we'll be
    looking at them in detail in the  future, and it's not worth going into
    them now. So I won't. What we are  doing  now is to discuss how to load
    them into the system and make them available to your application.

    A resource file is a set  of  standard  structures which are defined in
    the AES include file called  OBJECTS. Each  dialog box is an OBJECT, as
    is the menu,  you  can  define  a  variable  of  type   OBJECT for each
    resource you have,  including  the  menu.  These  pointers  are used to
    indicate to the AES  which  object  you  would  like  to display on the
    screen.

    Anyway, all we need to know right now is how to load and initialise the
    resource file. To make GEM  load  a  resource,  use the call rsrc_load.
    This function takes the name of  the  resource file as a parameter, and
    returns a value of 0 if it  cannot  find the resource (i.e. it isn't in
    the same directory as the  executable).  It  is possible to specify the
    full path, and therefore put the resource in a different place, but you
    must then rely on every  user  of  the  program  putting it in the same
    place as you. It is also normal  practice to give the resource file the
    same name as your program, with the appropriate extension. However, the
    system doesn't require you to do so.

    C programmers amongst you will  be  pleased  to  note you don't have to
    allocate any  memory  to  this,  the  system  does  it  for  you. Other
    functions find the address  of  the  loaded  resource file sections for
    you, but they are best left to the proper time.


    Disassembly Is The Reverse of the Above

    Once you have gone through these three  stages, you should have a green
    GEM backdrop screen, with a blank  menu.  However, right now, you don't
    know what to do with it. Never  mind, that'll come later. Right now, we
    have to quit the application and tidy  up after ourselves - GEM is like
    your mum, not only does it look after  you and help you when it can, it
    also gets somewhat upset if you leave things in a mess..

    First of all, we unload the resource  and  free the memory it used. You
    do this with the call rsrc_free.  If  this returns 0, the memory cannot
    be freed, and you should inform the user of the fact before continuing.
    Then, you close the VDI workstation using v_clsvwk, which takes the VDI
    handle passed  back  by  v_opnwk  as  a  parameter.  Finally,  you  use
    appl_exit to quit the application, just as  you used appl_init to start
    it. Then you are back to square one.


    NEXT..

    We go on to look at  opening  and  closing  windows, and take our first
    foray into the land of windows events  and  messages, as we look at how
    the AES communicates changes to  the window (sizing, dragging, closing)
    to the application.
