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?