DragASprite

The DragASprite module is intended for dragging an arbitrary sprite around the screen, providing the necessary interface through the SWI Wimp_DragBox user draw functions. To do so, it captures the section of the screen under the dragged sprite, draws the sprite over it, and restores the relevant bits as necessary when the pointer is moved. The whole operation is actually reasonably efficient and smooth - you don't usually notice what it's doing behind the scenes.

Making sprites drag transparently with DragASprite wasn't actually all that hard - intentionally so, as that's how the interface had been added to the SWI OS_SpriteOp calls. The call that plotted the sprite was changed from merely plotting it to use a translucency level. That worked reasonably well, but it was obvious immediately that the 'shadow' that had been applied to the sprite looked wrong now.

So the shadow got forcibly disabled if the drag was requested to be hatched, which improved things a bit. The drag was still solid if it was requested, though, and in that case the shadow would appear again. Strictly if it were to be a real shadow we should plot a translucent version of the mask behind the sprite, in black. That would give the right effect, but as the purpose of the translucency was to allow you to see where you were dropping the sprite, obscuring it with a shadow would probably be the wrong thing to do.

The translucency itself fell down when in a very low colour mode - 4 and 2 colours really hurt it. Because the translucency level was 'a little more solid than half and half' (3/8ths), in 2 colour modes it always appeared solid. In 4 colour modes it was generally solid, but you didn't have a lot of colours to make the effect work. This bothered me a little, but not enough to change the behaviour based on it - such modes wouldn't be used by many people, and in any case would not be supported by more modern hardware, so the problem would go away later.

There was a small experiment with making the translucency cycle over time, so that the dragged sprite became more solid and then less, and so on. It seemed like an interesting effect to try. Using a full range of the translucency it looked pretty ugly. Reducing the range to just a little more transparent and a little more solid made it look just bad. So effect was abandoned.

What might have been more interesting might have been a glow around the sprite, which would have been reasonably easy to do if I thought about it. On the other hand, it might have also looked ugly, so maybe it is better that I didn't try that <smile>.

FilterManager and RedrawManager

The FilterManager and RedrawManager modules go together, really. The FilterManager has been around for quite some time as a module which provides a means by which clients can replace, or augment, certain functions which the Wimp provides. The only real extension that I provided for it was to add support for the icon bordering functions, which are provided through new filter functions. Oh, and to make it understand the new format of the Window handles so that it can dispatch things properly.

RedrawManager allows controlled use of the post-icon and post-rectangle redraw filters, allowing multiple claimants to easily control what areas of the window they want to redraw. Primarily the module is intended for use with Toolbox Window Gadgets, allowing them to be more complex than regular icons without the need to use a nested window. The RedrawManager module was one of the original modules that were supplied with the RISC OS 4 source, but with no use for it, and bigger issues to address, it was put on one side.

Eventually it got integrated into the main source when I needed it for the gadget redraw handling. All of the experimental modules which had redraw handlers went through the RedrawManager - indirectly, because the Window module took care of all the registrations, etc.

The module itself, I remember as being a little strange. The indentation style was completely different to most of the other code that made up RISC OS, and it was obvious when I tried to use it for handlers that it was unfinished. There were a few places where its behaviour was non-deterministic (and downright weird), and in obvious cases it would cause redraw problems where the rectangles were not managed properly. Similarly, the remove handler could remove the wrong redraw handler if there were multiple handlers with similar parameters. There were even fun issues in EX0 EY0 modes which meant that regions of the window might not get redrawn properly. All of these problems were fixed, because gadget redraw was going to be used in the upcoming releases.

All in all, though, it was a very easy to use module which provided a lot of functionality which would otherwise not have been easy to add. Whilst the main users were Window Gadgets, any other module could use it. So it is quite possible that a user redrawn region extension module could be added - animated 'icons' immediately spring to mind as a simple use, albeit one that I'm not particularly keen on myself (beyond the experimental, obviously!).

TaskWindow

Oh my... what can I say about TaskWindow?

Well, the thing about TaskWindow is that it was written to provide a preemptive system on top of the cooperative system that the desktop used. As no part of RISC OS is really designed to be preempted, this had some interesting effects. Operations that you had assumed couldn't be performed reentrantly could actually happen - especially if you added debug code which wrote to the screen.

TaskWindow itself, though, was reasonably old. Dating from about RISC OS 2, I think (although it may have dated back to Arthur - there are certainly Arthur-esque things in it), it had a lot of legacy cruft in it, and existed in just a single source file for the bulk of its implementation. The interfaces it used to perform its job were generally the very old ones, or undocumented interfaces like trapping the Kernel SWI dispatch table which was... ugly. The implementation still includes a whole load of collusion, but it's generally better than it was before.

In addition to the collusion, the behaviour where it replaced functionality often differed from that when the task was outside of a TaskWindow. This often meant that it was important to know where your program was running in order for it to work properly. I tried quite hard to get the implementation to be safe - a lot of the work involved in making TaskWindow safer in the future would have been focused on changing the way that the environment handlers worked, but that was going to be a reasonable chunk of work.

I wrote quite a bit at the time of release about the way in which the TaskWindow was updated, but it really was a lot of fun (and pain) to get right.

TaskWindow itself had always been very inefficient on a lot of its operations. There were known blocking operations which the module could use to let the system have control back - waiting for input and explicitly calling SWI OS_UpCall 6 being the primary ones. The input calls didn't actually work as advertised really. An INKEY() operation which used a timeout would block for a number of VSyncs, rather than a number of centiseconds. Additionally, whilst the VSyncs were enabled for the timing in every TaskWindow opened, they wouldn't be disabled until the last TaskWindow was closed - resulting in the VSyncs being enabled (number of TaskWindows opened - 1) times.

Both of these were fixed, and the timeout in SWI Wimp_PollIdle updated to reflect the amount of time to wait. The SWI OS_UpCall 6 mechanism for yielding to the system, especially on a pollword, didn't actually work either. It would never use the pollword, which meant that it was pretty useless as it stood.

There was a little bit of confusion involved in the handling of the Escape key. For various reasons, the behaviour of the escape key differed significantly in the TaskWindow. One simple example was that the escape state prevented I/O from being processed, which meant that once an Escape had been triggered, you could type whatever you liked but nothing would happen until the application acknowledged it - differing from the non-TaskWindow behaviour. Changing the Escape character (and thus disabling it) was not supported at all - it was Escape (code 27) and that was that, within a TaskWindow.

A little bit of brain dead code which handled the callback deferral prevented the Escape key from being detected at all some of the time - one of the reasons why when you were building an application in the TaskWindow you might have to hammer the Escape key a few times in order for it to be recognised.

Because environment handlers are still so very poor, there is only a global command line environment, not one per task. TaskWindow managed this by claiming the SWI OS_GetEnv and SWI OS_WriteEnv which was very tacky. I never got around to properly fixing these claims to use the SWI OS_ClaimOSSWI calls, but they did use the API to read the SWI tables, which was at least flexible, even if it wasn't nice.

One related crasher was to use a *Command in the first TaskWindow in which you called which invoked a module entry point and that called SWI OS_GetEnv, before the TaskWindow preempted you. Ok, so the possibility of doing that might be low, but you just see the code and it is obvious that there's something wrong, and you sigh, because it's TaskWindow and that's just the way that it goes <smile>.

VDU handling was amusing - the module would remember the VDU sequence being performed and if we were in a control sequence it would prevent the preemption from happening until the sequence was complete - because there was no way to properly preserve the VDU sequence state.

As had been lamented many times, Sprite redirection was not supported within the TaskWindow. If you did try to use redirection and were preempted, you would find that things very quickly blew up - as the output redirection no longer existed as the task was switched out. Over the years a few solutions were suggested for this, but the right answer - always - was the fix the code so that sprite redirection was properly supported. Even in recent comp.sys.acorn.programmer I saw some insane suggestions, which just made me want to cry. Such things are easy to fix, so you do it.

Starting new tasks from within a TaskWindow with SWI Wimp_StartTask was generally unreliable, and could result in a whole bunch of VDU operations happening in the TaskWindow. Those were fixed, I believe, by marking the TaskWindow as suspended whilst the new task started up. This actually wasn't fixed explicitly for itself - there was a much bigger problem where starting a new task from within the TaskWindow would cause the second task to be preempted by the earlier TaskWindow. Understandably, this did not go well from then on. The fixes for both problems were the same.

To make it easier to control, when the TaskWindow was sat at a command prompt, I allowed the TaskWindow to change its slot size. This meant that you could change the memory allocation whilst it was safe to do so, either increasing or reducing it depending on what you wanted.

Finally (although it was one of the earliest bugs to be fixed) there was 'The MessageTrans Bug'. This was a great one. You have a TaskWindow running, doing a compile, let us say. You want it to stop, so you close the TaskWindow... and the desktop turns to treacle. Slowly, you open the TaskManager and quit the TaskWindow - and the machine locks solid. Or, if you were lucky your close of the TaskWindow would just cause an abort and exit - and then every subsequent operation you tried would report an abort within MessageTrans.

This was a quite useful one to fix and, coupled with the fix for the Escape handling, meant that TaskWindows were actually safe to use. The problem with looking at TaskWindow was that you began to be so very scared of using it at all. I kept a list of the 'Things not to do' where I found significant issues which would cause bad (usually catastrophic) failure of the system. TaskWindow manages to appear in the list 3 times - although all of those particular cases were fixed.

It still scares me but when I left it, it was in the best shape it had ever been. There are still bits that needed to be reworked, but I would trust it far more than I had any prior version.

On the other hand, there's still no TaskWindow_IOQuench message, which leaves me feeling very wary of its use in some circumstances.

ShellCLI

The ShellCLI module is probably one that a few people have seen and not really wondered what it did. If you did wonder, but didn't know, it handles the prompt you get when you press F12 in the desktop. That is, it is distinct from the Supervisor, which is provided by the Kernel - as part of the UtilityModule (and to be a little stranger, the command to enter the Supervisor, GOS, is provided by the OSCommands module). And it is distinct from the command prompt in TaskWindow.

Nobody ever said these things were obvious. In any case, the 3 do slightly different things, so it's forgivable - barely.

Anyhow, all I wanted to say about this was that if we were going to attract anyone to the system who didn't use it as a programmable computer but as a tool (gosh, heaven forbid!) then accidentally pressing F12 and being left with a non-obvious '*' prompt wasn't at all friendly. In particular, it wasn't clear how to exit - especially when pressing Escape wouldn't actually return you to the desktop. It might look like you've exited everything.

I added a very simple message to remind users that you exit by pressing return on a blank line. Nothing too fancy, but I thought it very useful.