Before we can move on to look at sprite icons in any more detail, there’s a glaring omission with our example application which needs to be fixed. So far, we’ve just been compiling our code into an Absolute executable called ExampleApp, which we then run directly by double-clicking on it. This works, up to a point, but there are a few problems which so far we’ve skirted around.
Almost invariably, applications on RISC OS come packaged in an application directory: the familiar object in a filer window whose name starts with an exclamation mark. An application directory is just like any other directory – except that double-clicking on it doesn’t open it up, but instead causes other things to happen.
Creating an application
Creating an application directory is surprisingly easy. First, clean the project by double-clicking on the MkClean TaskObey file. Next, click Menu over the folder, slide over New directory, enter the name “!ExamplApp” and press Return. This will create a new directory but, because the first character of the name is an exclamation mark, it automatically becomes an application directory. The project folder at this stage should look similar to that shown in Figure 17.1. Note that the name has been chosen to keep it within a ten character limit which still exists in some parts of the system.
The next thing to do is to change the Makefile so that the Absolute file is built inside this new application directory. The COMPONENT variable sets the location of the output file, and this can be changed from
!ExamplApp.!RunImage as shown in Listing 17.1.
# Makefile for Example App COMPONENT = !ExamplApp.!RunImage OBJS = main ibar win CINCLUDES = -IC:,OSLib:,SFLib: LIBS = SFLib:o.SFLib OSLib:o.OSLib32 include CApp C_NO_FNAMES = # Dynamic dependencies:
Listing 17.1 (Makefile): Updated Makefile for an application directory
The name !RunImage needs a little explanation. RISC OS has a number of filename conventions when working with the contents of application folders, some of which are fixed within parts of the operating system itself and some of which have just grown up over the years. It’s conventional to call the main Absolute executable inside an application !RunImage, and the Filer will actually make use of this by reporting the date of the !RunImage file when the date of the application directory itself is requested.
It’s worth noting before we progress that amongst the example skeleton build environments supplied with the DDE is one called “exampleapp”. Whilst this is for building applications, it takes a slightly different approach which is somewhat different to this one. Which one to use is a matter of personal taste, but the approach taken in this tutorial is probably the easiest to understand – as well as being suitable for most projects.
Our new application directory can be opened up by double-clicking on it while holding down Shift, which should reveal an empty directory. Double-clicking on the Mk TaskObey file should build the application as usual – except that the resulting Absolute file will be called !RunImage and placed within !ExamplApp. This can be seen in Figure 17.2.
It’s not the end of the story, however, because double-clicking on the !ExamplApp directory without Shift held down gives an error that !ExamplApp.!Run can’t be found. There’s clearly something missing!
The !Run file
When an application directory is double-clicked, the Filer will try to execute the !Run file contained within it. By convention, this file is an Obey file: this means that it contains a sequence of * commands which will be executed by RISC OS. We’re going to add the file shown in Listing 17.2.
| !ExamplApp.!Run RMEnsure UtilityModule 3.10 Error This application requires RISC OS 3.10 or later RMEnsure UtilityModule 5.00 RMEnsure CallASWI 0.03 RMLoad System:Modules.CallASWI RMEnsure UtilityModule 5.00 RMEnsure CallASWI 0.03 Error This app requires CallASWI 0.03 or later RMEnsure FPEmulator 4.03 RMLoad System:Modules.FPEmulator RMEnsure FPEmulator 4.03 Error This application requires FPEmulator 4.03 or later RMEnsure SharedCLibrary 5.17 RMLoad System:Modules.CLib RMEnsure SharedCLibrary 5.34 Error This application requires SharedCLibrary 5.34 or later WimpSlot -min 128K -max 128K Run <Obey$Dir>.!RunImage
Listing 17.2 (!Run): Our application’s !Run file
The file does a number of important things which, up to this point, we’ve been ignoring whilst crossing our fingers and hoping for the best. First are a block of *RMEnsure which should be considered mandatory for any modern application that’s written in C. The first line is:
RMEnsure UtilityModule 3.10 Error This application requires RISC OS 3.10 or later
The *RMensure takes a module name and a version number and checks the system to see if that module, with the specified version or newer, is already loaded. If it isn’t, the rest of the command is executed as a new * command. Here we’re checking to see if a version of the UtilityModule is present with a version of 3.10 or better: since this module is always present in ROM and its version is the same as the installed version of RISC OS, this is a standard way to check the current OS version.
Checking the OS version is a fairly blunt tool, and one which should only be considered a ‘last resort’ if no better alternative is present. In this case, however, we’re only interested in knowing that the OS version is at least RISC OS 3.1 – even Acorn considered this a ‘base’ version of the OS back in the mid-1990s, and many parts of modern software simply won’t work without it. If a suitable version of the UtilityModule isn’t present, the *Error command is called to warn the user and exit.
The remaining *RMEnsure lines come in pairs, the first being:
RMEnsure UtilityModule 5.00 RMEnsure CallASWI 0.03 RMLoad System:Modules.CallASWI RMEnsure UtilityModule 5.00 RMEnsure CallASWI 0.03 Error This app requires CallASWI 0.03 or later
The *RMEnsure against the UtilityModule ensures that this pair of commands is only executed on versions of RISC OS older than RISC OS 5. The first line then uses *RMEnsure to check for version 0.03 or better of the CallASWI module and, if it isn’t loaded, will attempt to *RMLoad it from within the System Resources folder (!System).
The second line repeats the test for the CallASWI version 0.03. By now it should have been loaded by the first of the two lines, so if it still isn’t present then it can only mean that a suitable version of the module wasn’t found in !System. As before, if the requirement can’t be met, *Error is used to warn the user and exit.
The CallASWI module was introduced by Acorn with the StrongARM updates, and evolved to version 0.03 with the arrival of RISC OS 5. It provides implementations of a select group of new SWI calls which are used by applications compiled from C, allowing those applications to function on older systems. The next pair of lines is very similar, except that they apply to all versions of RISC OS and not just those older than RISC OS 5:
RMEnsure FPEmulator 4.03 RMLoad System:Modules.FPEmulator RMEnsure FPEmulator 4.03 Error This application requires FPEmulator 4.03 or later
They check for the presence of version 4.03 of the Floating Point Emulator; since this is also essential, they again prevent the application from loading if it can’t be found. The final pair of lines is subtlety different:
RMEnsure SharedCLibrary 5.17 RMLoad System:Modules.CLib RMEnsure SharedCLibrary 5.34 Error This application requires SharedCLibrary 5.34 or later
Once again they test for the presence of an essential module: this time the 32-bit Shared C Library which code compiled using the DDE requires to be present. The reason for this is that it’s dangerous to soft-load the library twice in a session, so the first line tests for the earliest soft-loadable version. The second line tests for the version which is actually required – fixing this is left as an exercise for the user, but it’s better than potentially freezing their machine without warning!
All of the items being tested for here should be considered bare minimums for running an application executable compiled using a modern version of the DDE, and so they should always be present in an application’s !Run file. There are ways around some of them, but those are beyond the scope of this tutorial.
WimpSlot -min 128K -max 128K
The next line uses the *WimpSlot command to allocate memory for the application. Up to now, the application has been getting the amount of memory allocated to Next in the Task Manager; using this method, we can ensure it receives what it actually requires. The -min and -max parameters can be a little counter intuitive: if the Next slot is less than -min then the memory is increased to -min, whilst if it is greater than -max then it is decreased to -max. In general, they two values will be set the same, so that a predictable amount of memory is allocated.
The final line is the one which actually launches the application, using the *Run command. The Obey$Dir system variable is set to point to the directory containing the !Run file, which allows us to easily locate the application’s !RunImage file.
With this new !Run file in place, double-clicking on the !ExamplApp application directory will correctly load the application on to the iconbar. In addition, we can now be confident that all of the resources necessary for the code to run will be present. A Complete set of files for the modified project can be found in Download 17.1.
Download 17.1: The Project Converted to use an Application Directory
9 KBytes | 19th June, 2017
An application sprite
Now that we have an application directory, there’s something else that we can add to our simple application. So far, we’ve been relying on the ‘application’ sprite from the Wimp Sprite Pool for our iconbar icon, but there’s now somewhere to store our own alternative.
The first thing to do is to create a suitable set of sprite files. One possibility is shown in Figure 17.3, but others can easily be created using Paint or a package such as ArtWorks. An application should supply at least one ‘full size’ sprite with the same name as the application directory (in our case ‘!examplapp’); it can optionally supply a second ‘half size’ sprite, with the same name prefixed by ‘sm’ (in our case ‘sm!examplapp’).
The half size sprite is for use in the Filer’s directory viewers, and is optional because if it isn’t present, the Filer will show the full size sprite with the wimp_ICON_HALF_SIZE flag set (as discussed in Section 14.6). Supplying both sprites is desirable, because doing the scaling ourselves gives more control over the result.
Ideally, a modern application will also provide at least two sets of these full size and half size versions of its sprite: these are at different resolutions, and allow the Wimp to cater for different screen displays. As a minimum, an application should have a !Sprites22 file containing designs in a ‘square pixel’ mode, and a !Sprites file containing designs in a old ‘rectangular pixel’ mode (such as Mode 12 or Mode 15). Optionally, a !Sprites11 file can be supplied with larger designs for use in high-resolution modes. Table 17.1 summarises the files and their sprite sizes in pixels.
|File Name||Resolution||Full Size||Half Size|
|!Sprites||90 × 45 dpi||32 × 16 pixels||16 × 8 pixels|
|!Sprites22||90 × 90 dpi||32 × 32 pixels||16 × 16 pixels|
|!Sprites11||180 × 180 dpi||64 × 64 pixels||32 × 32 pixels|
Table 17.1: The standard application sprite sizes in pixels
Our sprite on the iconbar
Although we now have our new sprite design appearing on our application directory, we should also be using it within the application itself – not least for its iconbar icon. Fortunately, this is actually extremely simple to achieve.
Back in Section 10.4, we restructured things so that the name of the sprite used both on the iconbar and in report boxes was held in a single location. This means that using our own sprite is now just a case of amending the line near the top of c.main to read:
static char *main_application_sprite = "!examplapp";
With this change in place and compiled, our application will finally be able to install itself on the iconbar using its own sprite design.