SQUONK - Implementation Notes
-----------------------------

Note:     The  hardest  part  isn't writing  the  code,  or  even 
          debugging  it;  the hardest part is thinking of a  name 
          for  the program.  In this instance,  "Squonk"  is  the 
          title of an old Genesis song - please don't ask me  why 
          it sprang to mind at that particular moment.

MAIN.C

The bulk of the code for the program is in this  file.  Normally, 
my  programs consist of a largeish number of  separately-compiled 
files, but since this is a fairly small program I've coded all of 
the C routines in a single file.  Those with other  (non-SOZOBON) 
compilers  may wish to know that the two header  files  #included 
are  simply those containing all of the AES/VDI stuff  (xgemfast) 
and  all of the Gemdos/Tos bindings (osbind).  At the top of  the 
file  we define a few globals,  then the function  prototypes  (I 
really *hate* having to prototype my functions, by the way).

main()  does its traditional job;  it calls  some  initialisation 
routines, then sets up the event loop necessary for an accessory. 
I've  used  an  evnt_mesag call because  I'm  not  interested  in 
anything other than AC_OPEN messages.

The routines called from main() are:

gem_open()
     This routine does the traditional Gem stuff: the appl_init() 
and opening the VDI (we need a VDI handle to install our vectored 
routines).  Additionally,  we call menu_register to get installed 
as an accessory.

fix_clicks()
     There is an infamous bug in later versions of TOS whereby  a 
single click on a scroll-bar is seen as a double-click. There are 
several fixes for this floating around, but since it's easy to do 
I thought I may as well include it here. The trick is to wait for 
a double-click at least once at the start of the program,  or  at 
least, that's the way I remember reading it somewhere. That's the 
way  I've done it here,  and it seems to work;  if someone  knows 
better,  please let me know.  I've used a double-click monitoring 
evnt_multi  call which also includes a very brief timer  wait  so 
that the thing doesn't literally hang waiting for a double-click.

install()
     This routine makes the VDI calls which plug our wedges  into 
the  system vectors.  The original vectors are saved in  sysmouse 
and  sysbuttn for later.  This routine is called once before  the 
main event loop, and may be called again from process().

deinstall()
     This routine replaces the original values into the  vectors, 
thereby deinstalling our special routines.

process()
     This is the routine which services AC_OPEN messages. It does 
just  about the simplest thing an accessory can do - it  displays 
an  alert box with three buttons allowing the user to switch  the 
accessory  on or off,  or quit without  changing  anything.  This 
routine calls install() and deinstall() as necessary.


                              -=*=-

Ok,  that's the main C program which holds it all together;  it's 
fairly simple and straightforward,  but things get a little  more 
complex  in  the  assembler routines.  This is  actually  a  very 
simple-minded (almost brain-dead, in fact) approach, but it seems 
to work on the Falcon at least.

I've supplied two versions of the assembler routines:  "falcon.s" 
which is the (almost) working version,  and "stfm.s" which is the 
nearest  I  can  get on the STFM.  On  the  latter  machine,  the 
falcon.s  version doesn't really work at all (not in  any  useful 
sense);  the  stfm.s  version sort-of works,  but if you  try  to 
select  a menu entry by clicking and holding,  then  the  thing's 
behaviour gets a little bizarre. Try it, and you'll see: compiled 
versions supplied for those sufficiently adventurous.

mousetrap
---------
     This routine is called whenever the mouse changes  position, 
and the system obligingly gives us the new x and y coordinates in 
registers  d0 and d1 respectively.  We save the  coordinates  for 
future  reference,  then  do  a (rough and ready)  check  to  see 
whether the mouse has moved onto the menu bar. If it has, we exit 
stage  left  without  informing the system  of  the  mouse's  new 
position,  and  this seems to be sufficient to prevent  the  menu 
being activated. If the mouse is below the menu bar, then we push 
the address of the system mouse handler onto the stack and rts to 
it  so that the system knows where the mouse is.  Note  that,  at 
present,  there is a hard-coded assumption that the menu bar ends 
20  pixels  below  the  top  of the screen  -  this  is  a  tacky 
assumption  which is probably only approximately true  in  higher 
resolutions,  and patently untrue in low resolution.  As I  said, 
this is quick-and-dirty code at the moment.

buttntrap (falcon version)
--------------------------
     This is where the really sneaky stuff takes place. First, we 
push  a  return address to the stack,  then the  address  of  the 
system's button handler,  then we rts to it. This lets the system 
know  about the button click,  and then returns to our  code.  We 
then  check whether the last recorded position of the  mouse  was 
within  the  menu  bar area;  if it was,  then  we  pick  up  the 
corresponding x coordinate and invoke the system's mouse movement 
routine. This, on the Falcon, is sufficient to cause a menu-drop. 
Note that, even though I don't explicitly save registers, I don't 
actually (on the face of it!) trash anything other than registers 
that I know are safe (d0 & d1).

buttntrap (STFM version)
------------------------
     This is the closest I've managed to get to a working version 
on the STFM. The code tries to achieve much the same thing as the 
Falcon  version,  but:  (1)  we tell the system about  the  mouse 
position  (if it's in the menu bar area) BEFORE  registering  the 
click,  and  (2)  we  register an imaginary  "button  up"  before 
registering  the real button change (which may be "button up"  or 
"button down"). This *almost* has the desired effect...

SO...
     Can  anyone suggest either (a) a simple fix to my  code,  or 
(b) a better approach to the whole problem?


