Application icon for !ResEd

The !ResEd tool didn't have too much work done on it. Aside from being converted to the new build system - as well all of its sub-components - it didn't really need much work doing. The main shell application provides all the 'filer', and the load and save, and there are a number of sub-components for each of the Toolbox object types. It's quite well thought out and functions well as a single application (the !Configure application isn't quite so well integrated).

I did update the main shell to have a slightly more Filer-like interface, allowing a 'small icons' and 'full information' mode in its display. Whilst it was a little more standard, it didn't really look right, so I left the option turned off. I wondered, later, whether the window could have been given a little make over like !Paint, with a toolbar and maybe a status bar at the bottom. Even marking the edited objects in the main window view, and providing an 'undo' for changes to an object might help make the application a little more useful.

Each of the sub-components has its own part to play, but the only real object application that I spent any time working on was the Window editor. I really had a lot of fun with it <smile>.

The problem with the Window editor is that whilst there are applications that provide the plug-in interface for different objects, there isn't the equivalent for the gadgets. Internally, the gadgets were all described in one large file that contained all the definitions for all the gadgets. Whilst they were described in a nice simple set of structures, and had access to a bunch of functions to do their work, they weren't easy for anyone else to update.

If you wrote a new gadget you would have to talk to the person that built !Window to update the definition to contain new definition for the gadget and any messages and templates it needed would have to be merged into the main application. This seemed unreasonable to me, and would be a reason for people not to develop gadgets - which would be sad as they are a great way to extend the user interface. I was determined to remove the reasons to not use the Toolbox where I could, and this was an area that wasn't too hard.

I'd already made the BootMenu system support dynamic loading of extensions so that Podules could provide their own configuration menu entries. I used what I'd learnt from that to add in dynamic loading of the code which defined how the gadgets were edited. Because the window editor's gadget definitions were quite well structured, it wasn't that hard to move them out to separate files. There were new exports from the window editor component, so that the headers were available to the gadget editor definitions when they loaded.

Each of the gadgets was separated out into components in their own right - they had their own source directory, makefiles and resources. These components were then built into sub-directories within the window editor application, and were loaded when the editor started up. The templates and messages files were split out, so that they could be accessed separately and didn't need to be merged into the main files. Essentially, you should be able to delete the directory in the window editor application and the gadget's support would go away - or you could just copy over the top of the old one to upgrade.

I started out with the 'label' gadget, which was the simplest, and worked up to the more complex gadgets like writable icons. For most of the gadgets I found that I needed to export a few more functions so that they could do their job. Hopefully I had managed to include sufficient exports that an editor could be written for most future gadgets (but I've surely missed some things).

Each of the gadget definitions were also updated to be able to provide details of the modules that they needed. The modules were ensured and loaded if necessary when the editor was started. This meant that if you have the relevant module on the system, you would be able to render it, as well as edit it.

The idea was that as part of another SDK release, we would include the necessary details to explain how you wrote a gadget editor. The 'App notes' that Acorn had produced on writing gadgets were actually quite good, but obviously wouldn't cover writing gadget editors, so it would be necessary to write something explain how you create such an editor library, together with the necessary source and examples.

It was still necessary to update the !ResTest application with the details for each gadget type, which is frustrating as well. However, that was to be some future work (which I never got to do).

It also meant that writing the editor support for the newer gadgets, like AMPlayerGadget was really quite easy. Some of the other gadgets were just simple copies of the basic gadgets with some small updates. For the simple gadgets, all the dynamic library contained was a structure that described the interaction of icons. I considered writing a tool that would make the structure definitions from a header file, like CMHG does, but decided that writing the definition by hand was actually more likely to be useful.

All the template files were given treatment by FixUpTemplate to make sure they were tidy and consistent.

I added some tentative support for displaying the gadget number alongside the gadget, in the window. However, this didn't really look that good and I turned the option off before I got an opportunity to add the user interface to control it. I intended to return to that option, so that it would be easier to reference gadgets.

The key shortcuts window was updated slightly so that the shortcuts rendered a little better, and had standard names applied to them. This improved their appearance slightly, and to improve the usability, support was added for dragging multiple shortcuts between windows to copy them.

One thing I didn't get to update was the gadget palette. You still have to update the palette with a template gadget. Really, the palette should be created dynamically, but that would be a little trickier to do straight off. It needed a bit more thought in order to make that as flexible as it could be, not least because some gadget editors might want to provide a group of template gadgets.

The changes to the window editor made it far easier to make other gadgets available. It was, after all, meant to be a modular system. But there were other areas that really needed addressing. I wanted to provide more integration to other applications, particularly integrated tools for developing software, which could be provided by third parties. There were a few things that could be done there with close integration for Toolbox messaging, object and gadget identifiers, and the like, but I wanted to leave those until later. Not only were they hard, but they also needed for me to understand what the likely use cases were going to be, before designing a protocol to communicate such things.

At a level above that kind of close integration, was what I did do - providing External Edit support in !ResEd. The External Edit protocol allows an application to request that an editor perform its job on a file, and then to return the file to it once complete. Primarily the editing is performed by a text editor, and the requesting application is a tool which needs some larger input like an email client. But it doesn't need to be text at all, and I had already added External Edit support to !FormEdExt for template files.

In this case, !ResEd was the editor. It accepts External Edit requests for Resource files, and can return them on request, or abandon the edit. The cursor controls don't work because there isn't a cursor in the editor. Ideally it should be possible to trigger an edit of an object within the Resource file, but that isn't provided for (by the protocol or the implementation). I used the old editing test that I'd originally written to test the External Edit support when I added it to !FormEdExt.

It all worked rather well, although I'm pretty sure the support isn't actually mentioned anywhere as it was still an early feature and without any applications to support it, it didn't really do much.

Using External Edit with ResEd to edit a file
Editing a Resource file and then returning the edited file was quite simple.
(Animated version (95K))


Application icon for !ResTest

One thing I did add to ease the use of !ResEd was to add a 'Test' menu item at the bottom of the File menu. This would invoke the !ResTest application, and pass to it a copy of the current file. There was a simple protocol it used to communicate with !ResTest but I hadn't felt too comfortable with it to define it properly. It did the job, and it did make editing and testing Resource files a lot easier. Eventually it would have been tidied up and designed and documented properly.

With all the other gadgets that had been added, and the new messages being sent by the objects, !ResTest needed updating to add in the details in its debug window. I added most of the new Toolbox messages, like the Window_GadgetLostFocus and Window_GadgetMouseScroll messages, and all the new ones from the OptionsWindow object, ScrollList, TextArea and other gadgets.


Application icon for !MethodGen

Originally the Toolbox components were built by a group of ad hoc makefiles, much as the rest of RISC OS source was. I updated these to use some the 'standard' makefile format which reduced the amount of maintenance. Once I'd done that, I then made all the makefiles more complex by adding more options into the build! Actually it wasn't quite as bad as that - the builds of the Toolbox components were slightly different to many modules as they had a number of resources to export and headers.

Additionally, I'd moved around the way that the definitions were handled. Each object and gadget has a 'Method definitions' file which describes the input and output parameters. These files are used to build the method interfaces in source files which could then be built into object files. Internally these had just been stored in the Toolbox libraries component, but that didn't make much sense.

The method definitions are, generally, changed when the implementation changes. In general the methods don't actually change (as that would break ABI compatibility), but more are often added. I moved all the definitions from being just included in the Toolbox libraries to a 'definitions' export in each component. The !MethodGen tool was updated to be able to generate sources from the command line. Previously the workflow would be to load the !MethodGen tool, make modifications to the method file, save it, and then press the button to generate the sources from it. The sources would then have to be manually added to the Toolbox library component (assuming that you remembered to do so), and then the toolbox library rebuilt.

The new method meant that whilst you still needed to remember to check in the method file with the component (which is pretty much a given), the next rebuild of the Toolbox libraries would use the newly exported method definition to build the sources and construct the full library. To make the build work, the MakeGen tool was also tidied up.

The MakeGen tool was intended to take a set of directories, and build the relevant makefiles such that all of the files within those directories were built with the C compiler and linked into a target library. Unlike the rest of the build system, this tool could not use the standard library skeleton, because it was expected to be used without the rest of the makefile system being present. Essentially, the output from !MethodGen could be used, together with MakeGen, by anyone who didn't have the main build system.

The fact that it had to be able to used outside the standard build meant that it did not gain the ability to target 32bit or 26bit builds independently. MakeGen was updated so that, depending on how it is invoked, it can generate makefiles capable of building just 32bit, just 26bit or both libraries. It might seem a bit odd to be building modern components with 26bit variants, but there were still libraries which were 26bit only. Plus, of course, when the ROM was built for a 26bit environment it had to link against the 26bit libraries.

The MakeGen tool, and !MethodGen, would have been distributed as part of the development tools in the next Select release. Assuming, that is, there was enough time to test them and put together a distribution which was usable by other people. I'm not really certain that the distribution of the development tools was especially important to people, but it mattered to me that those tools be available. There's no point in having the extensible Toolbox if people have to fight to extend it, and the tools made that fight significantly easier.

ImageFileGadget methods
Editing the ImageFileGadget methods in the !MethodGen application.

Perl, and other tools

There were other support tools that were supplied as part of the build system, which need to be updated to support building things. In many cases, there weren't too many problems in rebuilding the components. The changes to the build system itself meant that creating a makefile for a new tool which could build in 26bit, 32bit or some other variant, was very easy.

Perl is used for quite a few tools, and the top level build system, to process and control a few things. The original build system had been supplied with a few awk scripts which were... well, I dislike awk with a passion, which is almost entirely attributable to its use in RISC OS' build system. The replacement Perl scripts were far clearer, although I'd not quite grasped how important it was to make sure that comments are used and relevant.

The Perl that we used within the build was the last good version that didn't use UnixLib - 5.001. Being a version 5 Perl, it's pretty capable, but doesn't have many of the nicer new features. Still, it's a good deal better than awk on any day of the week. Converting it over to the new build system was trivial, and at the same time I decided to investigate what it was that caused the disc to spin when the interpreter was started - even though it was doing nothing.

It's bad. I didn't realise quite how bad, but ... in order to populate the initial %ENV hash with the system variables, it would issue *Show { > some scrap file }, read the file in to memory, and then parse each line to create the key-value pairs. Not only is this wasteful by writing to disc, but introduces a race condition, and it is affected by any tool that changes the *Show command. I had such a tool, and fortunately it coped with the way that the output was produced, but it's still wrong.

I took the time to rewrite the hash population so that it used the SWI OS_ReadVarVal calls instead. It still produced the environment table in the same way as before - a key-value pair - but it no longer went to disc to do so, and so ran quite a bit faster.

I was interested, at one point, with using either the 'multiplicity' build options to build Perl as a module, or to use multiple instantiation to provide different instances in an application. Such things are of limited use, but having a Perl on hand with a low start up cost, could have been very useful.

There were a whole bunch of other tools that needed to be built, or created. The build system had been supplied with a tool called Kitten - it's a small 'cat' (in the Unix sense, concatenating the files that are supplied to it). I grabbed a small BSD version and used that in its place. The whole point of the tool was to have a consistent and known behaviour for the tool.

Other tools were just RISC OS standard tools which needed to be reproduced. CDir, IfThere, Copy, Destroy, and SetType spring to mind. The commands all exist on RISC OS, but when you're running the build on Linux or Windows, you need to have consistent commands which do the right thing, without having to worry about any special cases. Reproducing these tools was actually very simple - for example SetType would just rename a file to have the correct ,xxx ending for the filetype it was supplied.

All the tools used libraries which understood how to take RISC OS-like names and use them in native formats, which meant that all the makefiles that had been produced could be used almost exactly as they stood. Only in a few cases were any additional translations required.

Tools like sed weren't used much, but were needed for some specialised translations. The 'C in assembler' components would compile to assembler files which would then be slightly modified to remove things like AREA declarations and the like. The bison (parser generator) and flex (lexical analyser) tools were similarly specialised - I don't remember what they were used for exactly, but I have a vague feeling that libpcap used them as part of its parser.

The DefMod tool which was used by OSLib to build its sources had been updated to both 26bit and 32bit builds. This mattered a little more because OSLib was used to build a few components, and we needed to be able to build the library for either 26bit or 32bit targets, in the same way as all the other libraries were.

Having the tools and control to modify any part of the build system is always useful - it's not always necessary, but it's certainly useful. Even though in some cases it meant recreating tools that had already been implemented in RISC OS, it gave a lot more freedom in being able to run builds on Linux or Windows.


The IconBorders had been added to the system to make things look prettier and be easier to style for users. However, one effect that they had was to make the desktop slower. Initially this was because every rounded corner or blend on buttons would be plotted directly to the screen - sometimes pixel by pixel - which was quite slow. To alleviate this, the contents of the buttons to be rendered were cached on use in a sprite area controlled by the IconBorderRound module. This meant that when the same style of button was drawn it would render by just plotting the cached button sprite.

However, this showed up a problem in that the icons used throughout the system - in the applications and built in modules - were really inconsistent. Toolbox based applications were usually fine, because the standard buttons that you would take from the palette were generally left at the default size. This meant that most Toolbox applications had a quite consistent look and feel. Template based applications were less consistent - and that meant most of the OS.

In some cases, I'd already begun standardising the way that dialogue boxes were laid out, and the button sizes, but it wasn't always an accurate process. The style that the OS was following was quite consistent, and followed on from the general way in which applications had been going - particularly !Browse and the RISC OS 4 configuration components.

The style was pretty simple (figures and restrictions taken from FixUpTemplate so are what I was holding myself to, assuming I've read the code right).

  • Buttons should be the sizes used by the !ResEd palette by default, unless there were special reasons not to.
  • Action buttons would be 52 pixels high, with a width of 188. If they need to be larger, they should be 12+16*number of characters.
  • Default buttons would be 68 pixels high, with a width of 204. If they needed to be larger, they should be 12+16+16*number of characters.
  • No button should be larger than 22 characters, or smaller than 6 characters (in general) - in some languages that might be different, but for English that was fine.
  • In dismissible dialogue boxes, a divider line should be placed at the bottom of the box with the action buttons below it.
  • Dividers should be based at the left extent of the window.
  • The dismissal buttons below the divider must be right aligned, with the rightmost button being a default button.
  • Icons which are lined up in a row should be spaced 8 units apart.
  • Heights and vertical positions of the icons must be lined up sensibly - baselines should be at the same point.
  • Icons lined up vertically should have their left and right extents line up sensibly - they shouldn't extend further in one direction than the ones above (in general this helped with rows of radio icons whose right extent tended to be variable and wasn't obvious; making them consistent meant that the user didn't have to worry about clicking down a column of buttons).
  • Different types of common icons should have set sizes:
    • Option/Radio/Tick: 44 x 44
    • Labels: (0+characters * 16) x 40
    • Display: (0+characters * 16) x 52
    • Writables: (8+characters * 16) x 52
    • Sunken writables: (16+characters * 16) x 68
    • Menu button: 44 x 44
    • Adjuster arrows: 32 x 32
  • Icons must never straddle the edge of the visible workspace.
  • Icons should not be outside the visible workspace (allowances for windows that toggle sizes).
  • Icons must not be placed outside the extent of the window.
  • Labels beside Display icons must be right aligned.
  • Labels following Display icons (usually a separator for a 'width : height' style input) should be horizontally centred.
  • Particular icon types must have certain icon flags set:
    • Display fields: Must be filled, vertically and horizontally centred.
    • Raised icons: Not recommended.
    • Ridged icons: Not recommended.
    • Channel groups: Must not be filled, not have text or sprite content.
    • Action/Default buttons: Must be filled, horizontally and vertically centred, not right justified, use grey 1 background, black text.
    • Writable icons: must be writable (that is, if they look like a writable they must also act like it), must be filled, must be white background and black foreground, must be vertically centred, should be horizontally centred.
    • Radio/Options icons: Must be have sprites ordered 'off,on', be of type radio, Radio icons must be ESG != 0, Option icons must be ESG 0.
    • Dividers: must not be filled, must not be horizontally centred, or right justified, must be vertically centred, must not have a border.
    • Text+Sprite icons (eg file sprites): Must not be both horizontally and vertically centred (unless also right justified).
  • Dialogue boxes must only have one 'Default' button.
  • Dialogue boxes are allowed to have buttons aligned to the left of the 'below the divider' section, but only if they line up consistently. (usually for 'open help', 'advanced' or similar buttons).
  • Dismissal buttons on the right of the Dialogue boxes must never end in an ellipsis.
  • Label icons must never end in a colon, or a space, nor be prefixed by a space.
  • Buttons should in general be a single word.
  • Default buttons must never end in an ellipsis.
  • Sprite names must not contain spaces.
  • Only 2 sprites are allowed in the sprite validation.
  • Sprite names must be less than 12 characters.
  • Window flags must meet certain criteria:
    • Windows must always be 'new' (RISC OS 2) format.
    • Windows with a Close icon must always have a Back icon.
    • Windows with a Title and a Resize must always have a Toggle icon.
    • Windows with both horizontal and vertical scroll should have a Resize icon.
    • Resize should not be set when neither scroll bar is used.
    • Windows must not claim to be both foreground and background.
    • Windows should not have true colours flag set (special cases only).
  • Window titles must not end in a colon or space, and must not start with a space.
  • Windows should try to conform to the ratio 1.414:1 (which I incorrectly wrote as 'golden ratio', tut tut).

Those aren't all of the rules that it has - just those that I could see (and which I thought interesting). The details of these (and others) together with justification were collected into an addendum to the style guide. I don't know where that went.

The tool would check for all these things and even fix some of them up so that it wasn't necessary to do so manually. Most of the things that it reports are useful advisories, even if I didn't do anything about them. The tool helped to make sure that all the applications had a consistent look.

A small section of the output when processing the template file for !Nettle, just showing the 'open' and 'resize' templates.

Template fixer 0.10 (30 Oct 2005). (C) Justin Fletcher
Processing window 'open'
  Icon  0: type 5 ''/'<>'/'Nhost;Pptr_write;Kat;AA-Za-z0-9-. ,:@'
           Writable icon is not H-centred
           Spacing (V) with icon 8 should be 8 OS units (currently 12)
           Spacing (H) with icon 10 should be 8 OS units (currently 4)
  Icon  1: type 8 'Cancel'/'<>'/'R5,3;Ncancel'
           Action/Default button has odd width (recommend 156, default 188, secondary 140)
  Icon  2: type 7 'Connect'/'<>'/'R6,3;Nconnect'
           Action/Default button has odd width (recommend 172, default 204, secondary 156)
  Icon  3: type 4 'Task window'/'<>'/'R2;Ncontype'
           Spacing (H) with icon 5 should be 8 OS units (currently 4)
  Icon  4: type 12 '<>'/'gright,pgright'/'R5;sgright,pgright;Ncontypebut'
           Menu button does not use ptr_menu
           Menu button is R-Justified
  Icon  5: type 0 'Connection'/'<>'/''
           Spacing with window edge should be 12 OS units
  Icon  6: type 5 ''/'<>'/'Pptr_write;Kat;Ncommand'
           Writable icon is not H-centred
           Spacing (H) with icon 11 should be 8 OS units (currently 4)
  Icon  7: type 4 'xterm-colour'/'<>'/'R2;Ntermtype'
           Spacing (H) with icon 9 should be 8 OS units (currently 0)
  Icon  8: type 12 '<>'/'gright,pgright'/'R5;sgright,pgright;Ntermtypebut'
           Menu button does not use ptr_menu
           Menu button is R-Justified
  Icon 10: type 0 'Host'/'<>'/'Nhostlabel'
           Spacing with window edge should be 12 OS units
  Icon 11: type 0 'Command'/'<>'/'Ncommandlabel'
           Spacing with window edge should be 12 OS units
           Window is not shaped to the golden ratio (width = 192,384 or height = 628,1252)
           Window should not be larger than 800 by 600 OS units
           Window contains 1 Action button and 1 Default button but no divider
Processing window 'resize'
  Icon  0: type 5 '80'/'<>'/'Pptr_write;Ktar;A0-9;Nwidth'
           Spacing (H) with icon 1 should be 8 OS units (currently 4)
           Spacing (H) with icon 8 should be 8 OS units (currently 4)
  Icon  1: type 0 'Width'/'<>'/'<>'
           Spacing with window edge should be 12 OS units
  Icon  2: type 5 '24'/'<>'/'Pptr_write;Ktar;A0-9;Nheight'
           Spacing (H) with icon 3 should be 8 OS units (currently 4)
           Spacing (H) with icon 9 should be 8 OS units (currently 4)
  Icon  3: type 0 'Height'/'<>'/'<>'
           Spacing with window edge should be 12 OS units
  Icon  4: type 5 '96'/'<>'/'Pptr_write;Kta;A0-9;Nscroll'
           Spacing (H) with icon 5 should be 8 OS units (currently 4)
           Spacing (H) with icon 10 should be 8 OS units (currently 4)
  Icon  5: type 0 'Scrollback'/'<>'/'<>'
           Spacing with window edge should be 12 OS units
  Icon  6: type 8 'Cancel'/'<>'/'R5,3;Ncancel'
           Action/Default button has odd width (recommend 140, default 188, secondary 140)
  Icon  7: type 7 'Set'/'<>'/'R6,3;Nset'
           Spacing with window edge should be 12 OS units
           Action/Default button has odd width (recommend 140, default 204, secondary 156)
           Window contains 1 Action button and 1 Default button but no divider

Keeping to a consistent style is really important for a product which looks professional, and the tool helps ensure that this remains the case.


Back when Acorn released Ursula to developers for testing purposes, there was a tool supplied called ursmod which would display details about module services and be able to update modules from the old style service handlers to the new style Ursula service tables. When we got the code for the OS, this tool wasn't included so we had to make do with updating things by hand.

To make this easier, I wrote a little tool called ModServices which did a very similar job - except it wouldn't update the module with the service entries itself. Its main strength, though, was to locate decode the entry points - and (I believe) it did so better than the Acorn tool. I can't be certain because I don't have the original source, obviously <smile>.

Anyhow, it stepped through the instructions that the service entry would execute, to determine which service numbers it was trying to check for. In general, most modules (assembler ones) followed a similar pattern, even if written by hand. Most would do one of a few things:

  • Compare to an immediate constant. That's easiest.
  • Subtract or add (maybe multiple times) into a temporary register, then compare to an immediate constant.
  • As above, but instead of comparing to an immediate constant, set the flags based on the state.
  • Load a constant into a temporary register, then subtract (or add) to the service.
  • Build a constant using MOV, ADD and SUB, and then compare to the service number.
  • Use EOR to clear bits into a temporary register and then compare to a constant.

Around these instructions which are of interest, there might be stacking instructions, processor mode manipulation, operations on the private word, or a few other things which were ignorable. Once it had parsed out the results, and reached an obvious termination, it would be happy that it had got out the right services. If it hit instructions it didn't understand, or the arithmetic operations were just odd (eg SUB r14,r1,pc - subtract the current program counter from the service number), it would give up and flag the module as unparsable.

Typical output might look something like:

UtilityModule:              &6F, &81
Podule:                     &27, &45
UnSqueezeAIF:               &B7
AppPatcher:                 &B7, &B9
DiagnosticDump:             &DC
CFrontDemangler:            &DC
CLIV:                       &D8
VideoHWVIDC:                &45, &76
VideoHWVF:                  &45, &46, &B9, &E1, &E2, &400C3, &42680
VideoGuard:                 &DE, &DF, &400C0
BufferManager:              &27
Debugger:                 * &27
DMAManager:                 &27, &8E, &8F
RTCAdjust:                  &27
OSPointer:                  &46, &6F, &DE
Hourglass:                  &6
FileSwitch:                 &11, &12, &27, &68, &75, &7D
ResourceFS:                 &40, &75
ResourceFiler:              &27, &4B, &4C, &4F, &5E
Messages:                   &60
MessageTrans:               &59, &5A, &75
TerritoryManager:           &28, &73
UK:                         &64
International:              &43
SerialDeviceDriver:         &27, &70, &71, &77, &81, &8A
SerialDeviceSupport:        &27, &77
Mouse:                      &27
SerialMouse:                &27
PS2Driver:                  &27, &8A
InternationalKeyboard:      &27, &43, &44
FileCore:                   &C, &11, &27, &40, &69, &6A, &6B, &6C, &75
ADFS:                       &27, &8A, &10802
ADFSFiler:                  &27, &4B, &4C, &4F, &5E
RAMFSFiler:                 &27, &4B, &4C, &4F, &5E
CDFS:                       &40
CDFSFiler:                  &11, &27, &4B, &4C, &4F, &5E, &7D
DOSFS:                      &11, &12, &27, &40, &42, &5C, &68, &69, &6A, &6B, &6C
SystemDevices:              &40
PipeFS:                     &40
AIF:                        &40
TransientUtility:           &40
BASIC:                      &11
BASIC64:                    &11
Obey:                       &2A
DDEUtils:                   &27, &53
SysLog:                     &7E, &9F, &B0, &D7, &42680, &80C41
ScreenModes:                &50, &8D, &DE
ScreenBlanker:              &27, &46
ScrSaver:                   &49, &7B, &80, &A9
SoundDMA:                   &27, &8A
SoundChannels:              &27, &54
WaveSynth:                  &54, &59
StringLib:                  &54, &59
Percussion:                 &54, &59
SoundScheduler:             &27, &54
SharedSound:                &54, &42680, &80481
DeviceFS:                   &27, &40
ParallelDeviceDriver:       &27, &70, &71, &79, &8A
ColourTrans:                &27, &46, &59, &5C, &72
Draw:                       &27
SpriteExtend:               &27, &59, &72, &42680
InverseTable:               &27, &46, &59, &5A, &72, &73
DrawFile:                   &60, &80D60, &80D61, &80D62
FontMap:                    &60, &6E
ZLib:                       &53, &42680
PNG:                        &53, &42680
ROMFonts:                   &60
FontManager:                &27, &41, &46, &57, &64
ImageFileConvert:           &80D40, &80D41, &80D42
CompressJPEG:               &42680, &80D60, &80D61, &80D62
ConvertPNG:                 &80D60, &80D61, &80D62
ConvertBMP:                 &42680, &80D60, &80D61, &80D62
ConvertGIF:                 &46, &80D60, &80D61, &80D62
ConvertICO:                 &42680, &80D60, &80D61, &80D62
ConvertPNM:                 &42680, &80D60, &80D61, &80D62
ConvertSprite:              &80D40, &80D41, &80D42, &80D60, &80D61
ConvertSun:                 &42680, &80D60, &80D61, &80D62
ConvertXBM:                 &80D60, &80D61, &80D62
ConvertPCX:                 &42680, &80D60, &80D61, &80D62
ConvertClear:               &80D60
ImageFileRender_Artworks:   &80D40, &80D41
Zipper:                     &53, &42680
PrinterBuffer:              &6F
PDriver:                    &78
PDriverDP:                  &46, &57, &65, &78
PDumper24:                  &66
PDumperCX:                  &66
PDumperDM:                  &66
PDumperE2:                  &66
PDumperIW:                  &66
PDumperLJ:                  &66
PDriverPS:                  &46, &57, &65, &78
RemotePrinterSupport:       &95, &96
RemotePrinterMessages:      &60
WindowManager:              &27, &2A, &46, &59, &5A, &60, &6D, &72
FilterManager:              &86
RedrawManager:              &87, &88
IconBorderPlain:            &87
IconBorderRound:            &46, &72, &87
TaskManager:                &27, &46, &49, &4A, &4B, &4E, &4F, &5E, &90, &91, &92, &42680
ShellCLI:                   &11, &27, &53
DisplayManager:             &27, &46, &49, &4A, &5B, &5D, &94
Filer:                      &27, &49, &4A, &5E, &75, &7D, &801C8
FilerSWIs:                  &53
Filer_Action:               &11, &27
Free:                       &27, &49, &4A, &4E
Pinboard:                   &11, &27, &49, &4A, &4B
ClipboardHolder:            &49, &4A
WindowScroll:               &49, &4A
ColourPicker:               &46, &53, &59, &5D, &75, &93
TaskWindow:                 &11, &27, &53, &57, &72, &CC
NetStatus:                  &27
MbufManager:                &A1, &42680
Internet:                   &45, &5E, &9D, &A2, &55640
InetServices:               &80C41
Resolver:                   &9D, &9F, &A1, &B0, &80C41
MimeMap:                    &80C41
InternetTime:               &9F, &A1
InetConfigure:              &9D, &9F
DHCPClient:                 &9D, &9F, &A1, &B0
ZeroConf:                   &9D, &9F, &A1, &B0
RouterDiscovery:            &9D, &9F, &A1, &B0
Freeway:                    &9D, &9F, &B0
FreewayHosts:               &80, &95, &80C41
ShareFS:                    &40, &4B, &4C, &4F, &73, &7D, &80, &95, &96, &9F, &B0, &801C1
LanManFS:                   &40, &60, &9D, &9F, &A0, &B0, &80C41
AppleTalk:                  &40, &9D, &A0, &A1, &A2, &42680
Toolbox:                    &11, &53, &60, &73, &87, &92
Window:                     &46, &49, &60, &80, &A5, &44EC0, &44EC1, &44EC2, &44EC3
Menu:                       &60, &44EC0, &44EC1, &44EC2, &44EC3
Iconbar:                    &60, &44EC1, &44EC2, &44EC3
ColourDbox:                 &60, &44EC0, &44EC1, &44EC2, &44EC3
ColourMenu:                 &60, &44EC0, &44EC1, &44EC2, &44EC3
DCS:                        &60, &44EC1, &44EC2, &44EC3
FileInfo:                   &60, &44EC1, &44EC2, &44EC3
FontDbox:                   &60, &6E, &44EC1, &44EC2, &44EC3
FontMenu:                   &60, &44EC0, &44EC1, &44EC2, &44EC3
PrintDbox:                  &60, &44EC1, &44EC2, &44EC3
ProgInfo:                   &60, &44EC1, &44EC2, &44EC3
SaveAs:                     &60, &44EC1, &44EC2, &44EC3
Scale:                      &60, &44EC1, &44EC2, &44EC3
GDivider:                   &60, &82881
ToolAction:                 &46, &60, &82881
TextGadgets:                &46, &5D, &44EC6, &82881
ImageFileGadget:            &46, &5D, &60, &44EC6, &82881
CDFSResources:              &60
CDFSSoftATAPI:              &42680
LegacyBBC:                  &4
LegacyScreen:               &46, &DE
BBCEconet:                * &27
OwnerBanner:                &7C, &CF
!Alarm:                     &60
LibraryHelp:                &D6
RPCEmuHostFS:               &40
RPCEmuHostFSFiler:          &27, &4B, &4C, &4F
VProtect:                   Dunno? &059f168c at 0225f1cc, offset &00000678
VProtect:                 ? &49, &7C, &4A, &27, &7, &400, &C0FFEE, &DECAFF
BootLog:                    &49
ErrorLog:                   &400C0, &400C2, &42680
ROMPatch:                   &45
AcornURI:                   &27, &49, &4A, &53
AMPlayer:                   &54, &80, &92
LineEditor:               * &53, &27
WimpSWIVe:                * &27
NoCoverIB:                - 
Tiler:                      &7C
StartBanner:                &7C
TransTIFF:                * &8004C
!StrongHelp:               * &40, &11
ZapRedraw:                * &46
!Zap:                        &27, &49, &4A, &53, &7F
ControlAMPlayer:            &87, &89, &52E00
AcornSSL:                   &83E01
MIDI:                     * &45, &27, &54
MIDISynthesiser:          * &58

* indicates a set of services which were decoded from the handler, not the Ursula module table.
- indicates an empty service handler.
? indicates an unparsable service handler.

The only 'unparsable' module in the above dump is the VProtect which has a quite complicated service entry sequence - and one that I intentionally didn't try to support, because it's one of the harder cases, and all the other modules that I tried worked fine.

Just about all the ROM modules, and most of the support modules, were updated to the new format by checking with the tool. One other little feature that the tool supported was filtering by service number. This meant that you could give a service number to it, and it would report only the resident modules that handled that service - useful for narrowing the scope of a problem.


Application icon for !ROMEdit

Building a ROM just because you want to add a few new modules for testing, or to disable something that isn't quite working for you is quite frustrating. During the later 32bit work there were quite a few times when it was really handy to have a test tool available in the ROM - especially when you didn't have a disc or network in order to get the program in (I used serial input some of the time to grab a program quickly, but having it in ROM, ready to use, was a lot easier).

Around Select 3, whilst working on the BuildROM tool, I wrote a companion tool, !ROMEdit. This was a desktop and command line tool that let you take a ROM image, change its contents, and save it to a new file. Modules could be removed or added, applications or library tools could be added to ResourceFS, and the Kernel could be replaced - this was before the SystemInit entry had been added (although it would be reasonably trivial to add support for the SystemInit replacement as well).

The desktop tool let you view all the useful contents of the ROM, and save it out again, or you could save out a 'State' file which described the current configuration. The configuration file could then be loaded back in to reproduce the same changes, or edited manually to make small changes.

An example state file that was lying around:

# ROMEdit state file
# Syntax:
#    ROM <file>
#       - select the ROM to work with
#    Omit <module name>
#       - force a module to be removed from the ROM
#    AddMod <file>
#       - add a module to the ROM
#    AddLib <file>
#       - add a library file to the Library resources
#    AddApp <dir/app>
#       - add an application or directory to the Apps resources
#    ReplaceKernel <file>
#       - SReplace the kernel in the image
#    Save <file>
#       - save the resulting image to a file
#    SaveSquashed <file>
#       - save the resulting image to a file in compressed form
ROM ADFS::Virginia.$.!Boot.Softload.Adjust1i2
Omit IconBorderRound
Omit ZeroConf
Omit LibraryHelp
AddApp Share::ROMEdit.$.!ROMEdit
AddLib Share::ROMEdit.$.ROMEdit
AddMod ADFS::Virginia.$.Build.RISCOS.Sources.HWSupport.Joystick.rm.Joystick
Save ADFS::Virginia.$.!Boot.Softload.ROM

The command line version was useful because it could be used to provide quick modifications reliably, and it could be used under Linux to modify the ROM easily (albeit the compression wasn't used in that case). The tool was very useful for quick turn around when working with the 32bit version in QEmu.

A ROM loaded into the ROMEdit tool
Changing the configuration of a ROM was pretty simple, just tick a module to disable it.

Update: 2013-07-12 Anja Skrba has provided a Serbo-Croation translation of this page. That's quite neat! Thanks!