Tearoff Menu System ~~~~~~~~~~~~~~~~~~~ A while ago, as Tim was leaving after a hacking session, I mentioned how nice it would be if only RISC OS allowed menus to be tearoffable, like OpenLook menus are. He pointed out that impossibility shouldn't be much of a barrier to us, and we got coding. Tearoff menus look just like normal menus, except there's a grey bar along the top, just below the title, with a `Tear' button in it. When the user clicks the `Tear' button, the rest of the menu tree goes away, leaving the tornoff menu behind, so that options can be chosen from it whenever the user needs to. Tornoff menus have two buttons in their grey bar area: `Close' closes the menu, and `Fold' hides the menu part away, leaving just the title behind, a bit like Corel's rollups (only without the irritating animation). The main support code was written as part of STEEL, in C. It handles the obvious (but quite difficult) stuff related to highlighting the right items, opening the right submenus, and drawing the windows, and Tim wrote it all. (He later wrote the corresponding Sapphire code -- the user- and programmer-visible bits of our tearoff support are entirely written by him.) There's one aspect of tearoff handling which can't be handled from an application: making the main menu tree `transient'. There are three times when the Wimp closes a transient window `silently': * when the user clicks outside of the menu tree; * when the user presses the `Escape' key; and * when an application calls Wimp_CreateMenu. In the first case, the mouse click is passed on to the receiving window; in the second, the keypress is swallowed by the Wimp. These three cases are handled by some vector interceptions. Normally this would be done by a module. Tim wanted the vector traps to be hard to extract, though, and a small module would be easy for other programmers to reverse engineer and implement their own tearoffs. The `tearoff support code' is statically linked into the application which uses it, and copied into an RMA block if it's not there already. The interface to the TearSupt code is simple: * ts_init initialises the support code. * ts_opened says that the application has opened a transient window, and wants to be notified about events which might cause it to be closed. * ts_closed says that the transient window has been closed. * ts_switch switches Wimp_CreateMenu trapping on and off (an implemention detail requires this). * ts_unload removes the tearoff support code from memory. Tearoff Support traps several vectors. One is trapped all the time: * ChangeEnvironmentV is trapped, as part of a particularly hacky way of communicating with the TearSupt code. It traps a call with R0 = -1 and returns its address and version number. This is very nasty. Others are only trapped while there's a `fake transient' open, and cause Wimp messages to be sent to the owner of the window: * MouseV is trapped: all mouse clicks are picked up, and passed on as messages. * InsV is trapped: insertion of an `escape' keypress into the keyboard buffer causes a message to be sent. * The hardware SWI vector is trapped: a call to Wimp_CreateMenu causes a message to be sent. Just to make life more awkward, the code is encrypted (very weakly: it's not worth the effort and code space of doing it properly). I considered removing the encryption code, but (a) I preferred to leave everything the way it was (more or less) as a record of the nasty things Straylight sometimes do, and (b) I couldn't be bothered. Anyway, all the code is really nasty. I'd recommend that you avoid reading it too closely. Oh, the SWI patch may be instructive to those who've not seen the job done before: I think it works properly in all circumstances. Of course, anyone's allowed to use tearoff menus. You're even allowed to use our code to implement them, as long as you stick to the GPL. And finally, if someone comes up with a SWI chunk, I may be convinced to permit binary distribution of a tearoff support module using our code. -- [mdw]