WindowManager
Icon selection, tinting and shading
One of the early features that was added after the release of RISC OS 4 was the ability
to 'tint' icons towards a particular colour. This was a simple 50% blend
which would be applied to the icon's text and background, specified with the
'T
' validation string. Later this was updated to be more flexible with the
blend type performed, and to allow the other types of blends which the ColourMap
module provides.
Tinting itself was not a big feature, and not one that was expected to be used very often, however certain application interfaces would benefit from the ability to easily manipulate colourings, we felt. In general there are quite a few features that the WindowManager offers which are not in keeping with the general desktop use, and in particular the style guide. For example, you could have raised writable icons, or use black window backgrounds. Such use is generally bad on the desktop, but for a customised environment they might be very useful. Obviously there are also times when, for a special case, it is very useful to have the facilities available to do things differently.
The tinting applied to the icon has to be applied to the icon as a whole, which means that it should also be applied to the sprites as well as the text and background. Fortunately, sprites have been able to have their colours manipulated through a colour transfer function applied to the tables generated with SWI ColourTrans_SelectTable. This was used for both the selected icons and the shaded icons (and obviously the selected shaded icons as well).
The code in the WindowManager was a bit of a mess when handling these operations, and made worse by the fact that text colour manipulation was different to that performed for the sprite and background colour. Add to this the fact that the SWI ColourTrans_SelectTable call with transfer functions is only suitable for paletted images, and there's a bit of a problem. (Strictly, you could use a transfer function for 16 bit sprites, but this would be quite slow as the tables generated would take a moment or two if they were not cached).
This problem means that 16 bit or 24 bit sprites would not be able to be used as selectable/shadeable icons in the desktop - they would never change colour. The 'shaded' icon transfer function also assumed that the background colour to which it was shading was Wimp grey 1. If your window background was anything else, the 'shaded' icon would look very wrong. RISC OS had, from the start, the ability to have different coloured window backgrounds. With the Nested Wimp (and therefore RISC OS 4 onwards) it gained the ability to use arbitrary colours for the background (and other window furniture and icons), rather than the fixed 16 Wimp colours. With this in mind, the issue of shaded and selected icons really needed to be addressed.
I was intending to add thumbnailing to the Filer, and the thumbnails would be images generated for the native mode (as this would be most efficient) which meant that the sprites needed to be able to be selectable at the very least. Alternatively the selection highlight code could have been implemented within Filer directly, but this would have been a crazy duplication of effect, made worse by the fact that it would be working around a limitation of the WindowManager. More sensible to address directly in the WindowManager.
The colour highlighting code for selections had been updated in RISC OS 4 to try to give the impression of a photographic negative. This was a change from the old behaviour which explicitly handled greys differently, which caused some jarring effects on some sprites.
Instead of this, I made the selection blend towards the configured foreground colour for the icon. This looked sensible when compared to the text and background colour of the icon, which would have been swapped by the selection.
Shaded icons needed to take account of the window to which they were being shaded. The whole point of the shading of an icon is to indicate that it is not available for use. Making it closer to the background colour of the window made this both obvious, and worked for whatever background colour the window used. Instead of being a greyscale fade, it makes a background colour scale fade.
The exact factors for the sprite and the text were still different, but the visual appearance was more consistent when used with different window background.
I remember there being a lot of to-ing and fro-ing about whether I should strip out the conditional code that had been left in the WindowManager for the various degrees of changes. It was still possible to build the pre-RISC OS 4 style selection and fading styles, or the RISC OS 4 form, or the Select 2 form. Similarly, features like the 24bit colour icon specification was toggleable. I believe I left a lot of these in (unlike, say, the Kernel where I had stripped older conditionals), partly because it was significantly more work to cut it out, and partly because being able to build the older styles was useful on a few (limited) occasions.
The results for the new style icons were significantly better (in my opinion) than any prior version of the Window Manager.
RISC OS 4 style shading of coloured icons didn't work at all well with coloured backgrounds.
The Select style shaded the icons into the background so that they looked a less harsh when shaded.
RISC OS 4 would just use a form of inversion for the sprites.
Select uses a tint towards the background colour instead.
RISC OS 4's rendering of photo-type sprites looked strange.
Left 4 images are an 8bit sprite; right 4 images are a 24bit sprite.
The 24bit sprite just doesn't work for any of the flags.
Select's tinting towards the background looked better on the photo-type sprites.
The 24bit variants work correctly as well, highlighting and shading as expected.
The 24bit images also render slightly better, in the 8bit mode that these were captured.
The functionality used by the selection code was exposed through a SWI Wimp_Extend call. Clients would be able to call the SWI and obtain a ColourMap descriptor which could be used to perform the exact translations that the Wimp performed. It is unlikely that clients would use this as plotting an icon through SWI Wimp_PlotIcon is significantly easier, but there are times when you cannot do this - like if you're performing all the redraw yourself. Normally you wouldn't need to emulate the behaviour of icons, but in some cases this would be necessary.
For example, all Toolbox Window Gadgets have the ability to be 'faded', and most have the ability to be selected. If the gadget is not composed of regular icons (that is, it is being redrawn by the gadget handler), the behaviour of the gadget must match - as closely as possible - that of icons. Thus Gadgets which provided such features needed to be able to fade (and select) in the right way. They could get the information from the SWI Wimp_Extend call.
During the tail end of development it was found that Castle had released versions of tools which called undocumented (at that time) SWI Wimp_Extend calls - which happened to clash with the one which was used for exporting the colour manipulation functions. Consequently, I bounced all the new SWI reason codes up much higher so that such clashes should not happen. As usual, I dropped an email to them to let them know - as they obviously could not know that they'd clashed otherwise they'd have done something about it (despite all evidence to the contrary).
As mentioned above, within the redraw loop, applications may wish to plot icons themselves using SWI Wimp_PlotIcon - this is also performed by the Gadgets when they draw themselves as part of !ResEd's Window editor. At other times it would be nice to be able to plot icons outside of the redraw loop. The SWI was extended to make it possible to pass in the window handle, or the background colour, so that the colour fading routines could do their job properly.
Irritatingly, when the SWI had been extended previously (for Select 1 I think), the implementation had been just plain broken, and could crash if called in the wrong way, or just plot in the wrong place. As this was pretty much irredeemable (frustratingly so), the later versions of the Wimp used a different magic word to indicate the extended API and the old one which never worked was consigned to the bin. It's frustrating to do that, but short of ensuring a patch to every version that had been distributed it was not an easy fix - plus the API was not being used on those versions by any distributed software, as it didn't work.
It's embarrassing when such things happen, but they do. If there had been some better testing - some nice integration tests at that point - it might have been caught. But nothing like that had been even planned beyond the 'it'd be good if we did...' stage.
Using SWI Wimp_PlotIcon outside the redraw loop might not seem like a common thing to do, but if you share your redraw code with the printing code, it might be reasonable. Similarly, DragAnObject could use this to draw the correct icon to the redirected sprite.
When the IconBorders module had been created, it was obvious that sometimes (within the desktop environment) it was useful to make a stylistic choice and override the default colours for the buttons. My personal style forces a lilac action button, and green default action button. Since these special overrides only apply when the standard colours are in use, they shouldn't affect other uses.
It was already possible to colour the selection a specific colour, so it seemed reasonable that there might be an override for the colour used for highlighting. Rather than blending to the background, the selection could blend to an arbitrary colour - if it would have blended to grey 1 in the first place. This allowed the selection of icons to be tailored to the user's preference. I used green as a good example myself. It was most obvious within the Filer that the selected icons came out in the special colour the user selected.
The changes to allow for specialised colour use, and much of the IconBorders work was intended to address the commonly requested feature to be able to provide more customisability for theming. It wasn't the goal, at the Select 2 stage, to provide theming myself - easier to allow others to use the facilities made available (and of course more flexible). If such work had come about usefully, some of it could have been taken as part of a standard.
There was a Wimp configuration flag which could be set to cause the solid colours used by the Wimp to be dithered. This improved the colours in some paletted modes, but generally wasn't all that useful. However, it was less likely that this would be used as the desktop was now focused on using sprites instead of solid regions. Because sprites were used a lot, and the support had been added for using deep sprites properly in the Wimp, it would be reasonable for users to use deep sprites and expect a good representation in the shallow modes (< 15 bits per pixel).
I introduced a configuration option which would cause deep sprites which were plotted at a lower depth to be rendered with dithering. This wasn't too complicated really - it's just setting a bit when the SWI OS_SpriteOp call is made. The effect was that the operations were slower than when undithered because there is extra work to be done. It also showed up problems with the ColourMapping of dithered sprites. When ColourMapping was applied to a deep sprite (such as would be the case if it was selected or shaded) nothing would be rendered. This was because SpriteExtend, which had been updated to handle the ColourMapping, hadn't been tested quite as well as it should .
SpriteExtend, as I have mentioned in the earlier rambles, compiles the sprite rendering code on demand. It constructs the necessary instructions needed to perform the plot, allocating registers for the operations and stacking some where necessary. However, certain parts of the code need more registers than it can track. When plotting scaled, ColourMapped, 16 bit-per-pixel images to a lower depth mode with dithering, the combination required too many register. SpriteExtend's reaction to this case is to exit as soon as the condition is detected rather than generating any code - resulting in nothing appearing.
Part of the problem is the ColourMapping, which requires that the 16 bit-per-pixel image data be converted to 32 bit-per-pixel in order that it can call the ColourMapping routine, and then to convert it back again. This doesn't take too much extra in the way of registers but it was more than the code was prepared for. Changing the behaviour so that certain registers were stacked under those circumstances fixed the problem - quite simple really, but it was amusing to try out the new dithering feature and find that actually it breaks and you get nothing .
The effect of the deep dithering of sprites is shown below. This is a 32K colour sprite (a screenshot of part of ColourPicker) being displayed in an icon (inside a template editor). The screenshot is from a 256 colour mode:With the deep dithering disabled, the sprite is a little blocky.
When enabled, the colour slice is significantly nicer. The image is a little lighter though.
Collecting wimp sprites
Prior to RISC OS 4, the WindowManager contained all the sprites which were used in the Wimp Sprite Pool, held in a pair of files - Sprites22 and Sprites24. These were difficult to manage as there were so many sprites in there, the order was random, and comparing between the two files was difficult. Additionally, because the sprites were in a single binary file, finding when a particular sprite changed - and how it changed - was tricky.
As part of RISC OS 4 we were including a few new modules and needed to squeeze a little more room out of the ROM (or drop those new modules). One way we wanted to solve this was to reduce the size of all the sprites by changing them to the 1 bit-per-mask-pixel sprites that had been introduced. The easiest way to do this (and to address a few of the problems above) was to... split all the sprites out into separate files each, apply a simple program to reduce the mask depth on each one (at compile time) and then recombine them into a sprite file in an ordered manner.
This made the sprites smaller, easier to manage in source control, trackable, and produced an output file which was ordered, so easy to compare to earlier versions (or between the '22' and the '24' variants). Unfortunately, we found that there was a problem with the rendering of 1 bit-per-mask-pixel masks (as discussed in a separate ramble), which we didn't believe we could fix easily in the time. So the reduction in mask depth was removed. The split of the sprites into individual files was retained though, because it was significantly more manageable. Later, when the rendering problem was fixed, the depth reduction was re-enabled (until the ROM was changed to 6MB, when it was disabled again - rendering of the smaller mask was slower than its full-width sibling).
The other frustration with the Wimp sprite pool being in the Wimp source was that whenever a sprite was updated or added, the version of the module was incremented. This meant that early on the module had a number of commits that were just sprite changes and which meant that the version increased more rapidly than you might hope. A possible solution would be to not increase the version with every change, but that makes it harder to know what you're working with - and in any case goes against the principle of generating a new version for every change.
To address this, the sprite pool was separated out from the WindowManager so that it was built separately. This also meant that building the module became faster as it never needed to consider the dependencies on all the source sprite files.
Later there were more problems when trying to reduce everything to fit into the 4MB Adjust ROM. Removing the mask from sprites that were otherwise completely solid helped there (and was obviously an improvement for performance). Eventually, I found that it was easier to just compress the entire Resources area rather than trying to find piecemeal savings. That, together with stopping the tokenising of the messages file made the space saving needed. The down side was that during start up the resources had to be decompressed into RAM, but that wasn't unreasonable given that we were booting from ROM anyhow.
Italic fonts in the desktop
I got a WindowManager that supported fonts in the Desktop (rather than the bitmap system font), back in the exciting days of RISC OS 3.1. WindowManager 3.22n (ah, the fun of a development release that has a non-numeric version!) had some of the features of RISC OS 3.5's Wimp, but ran on earlier systems. The Wimp source has a plethora of options which can be turned on and off - very much at the developer's risk, as many of the conditionals haven't been used in anger for some time.
My progressions through desktop fonts.
Over time I moved through a number of different styles for the desktop
font. There were some very nice fonts, but not all were suitable for
the desktop. At first I started out with Homerton
, which was fine but
pretty dull. A font called 'Milton-Keynes
' was used for some time
because of its particularly high ascenders which appealed to me.
After seeing a rather nice text editing application for
children, whilst I was helping out at my brother's primary school, I
changed to using the font that it used. 'Sassoon.Primary
'
retained the
high ascenders which I liked, but was slightly italic, and added a
gorgeous 'f
' which had a very nice descender that I thought gave it a
lot more personality.
Sassoon.Primary
, as a sans-serif font, was good for clarity
and lasted a little while until I discovered
Pembroke.Medium.Italic
which kept some of the features that I
liked about Sassoon, and added a finer serif that (I thought) looked very
nice in the desktop. I've just tried to reproduce the effect on Windows
XP using Palatino Linotype
in italic, which should be similar.
The result is a real pigs ear (in my opinion) compared to the RISC OS
version.
Although I liked the font and style, it was clear from the comments that had come back from people that this was not a generally favoured thing. A few people had said, after seeing a few example screenshots of upcoming features, how they really disliked the desktop font, and hoped it would never be the standard font. I let everyone involved know that if any screenshots were to be done of example features they should use the standard font (Homerton.Medium), standard window tools (and tool order), a plain (standard) window background, and standard icon set (including the icon borders). The only exception should be if they were showing off a variation on those. As the only people who really varied from that were myself and Chris Williams, the point was pretty moot. I think that was only the second or so guideline we had written for the promotional content, with a couple of things from Paul having come first.
I am not at all sure how ClearType manages to look quite so bad - it's never been great in my opinion (and I'm comparing to RISC OS' FontManager, which I'm used to and obviously have a liking for - despite its many failings) but the anti-aliasing on the font is quite atrocious (as a screenshot it's going to look a little odd on some screens if the colour ordering of pixels isn't the same, I realise, but believe me it looks bad here where it's being drawn the way it was intended). I couldn't work with the font like this for any significant length of time - it looks really tacky.
However, it manages to show off exactly the problem I wanted to talk
about - the text seems to have become truncated for 'Text
' and 'ToSort
'
for no apparent reason. Whilst it has coped by putting an ellipsis in,
it is still ugly and wrong - generally developers don't think about fonts
whose horizontal coverage is different to their baseline. Mostly that
means Italic and Oblique fonts. And for the more ugly example, the trailing
'f
' on 'Star,aff
' is an exact case of this.
The M is truncated.
On RISC OS the effect comes across in other ways. Usually a program will
size a box based on the baseline extent of a string, which still isn't
right when you are calculating a non-italic font's size, but the difference
is less prominent. The example on the right shows a bounding box which
has been calculated incorrectly for the string. The bounding box is a
different blue to show where the edges are.
There are a couple of ways that you should size strings. SWI Font_ScanString is (generally) the right thing to do. It is something of a black art to get the right details out of it, however, as the interface can answer so many different questions. In the desktop, when working with the standard font, though, applications should use SWI Wimp_TextOp to perform its calculations - specifically SWI Wimp_TextOp 1. The problem with this is that the call itself returns the offset of the baseline - where the next character's left baseline would start - and not the actual coverage of the line.
Interestingly, looking at the documentation, it explicitly states in PRM 5a that this should be used for calculating the widths of strings for columns and the like. Which sounds to me like it means the intention is to return the bounding box (whilst it actually returns the baseline). Looking at the documentation, I changed the API to have bit 31 mean that the bounding box was requested, and retained the bare implementation as a baseline calculation.
There are a few ways of looking at this - one is that I wanted to retain the implementation behaviour over that which was documented, as that was already deployed. Another is that I paid no attention to the documentation, and just implemented something that seemed sane (but was converse to the docs, as it turns out). The third - which I think I prefer - is that I chose to make the bounding box behaviour special so that a client that explicitly wanted the bounds could call it and would get back an error on systems that didn't support it, thus allowing them to decide what to do with the baseline variant of the call.
I would like to think I chose the third. I have a feeling that a cross between the first and the second is more likely, sadly. I have no other recollections to defend that decision to any greater degree. I did usually look at the documentation and the API, but my usual preference was to go with the intention of the documentation unless the usage was so prominent that changing behaviour would significantly break things.
There were a couple of additional changes for the SWI Wimp_TextOp calls, as Castle had added a couple of reasons and documented them clearly. Finding split points in the font and appending an ellipsis were related to one another and very simple to add. Though the addition of those entries did give an opportunity to tidy up the entry point to the SWI - for some reason it hadn't used a dispatch table but instead had a number of comparisons and branches.
The implementation of the split-point and 'truncate with ellipsis' calls were actually done in C, tested separately, and integrated with the WindowManager module. The split-point calculation is made fun by being affected by the text direction - when writing right-to-left the maximum offset of the text to split at must be given in negative coordinates, so to keep the call API the same for either direction it's necessary to compensate for this.
Priority sprite pools
When RISC OS 4 was released, one of the features that Acorn had added was the concept of a protected ROM sprite pool. This meant that, when enabled, the sprites that were provided in ROM could be made safe so that user loaded sprites would not override them. This was useful for enforcing the new style of icons, but not so useful for anyone that wanted to keep their own icon set. Basically it enforced that the style that would be used was the one that the OS defined.
That helps if you happen to like the distributed style (which, with the exception of the green directories, I did), but if you wanted anything different (like blue directories) you had to turn it off and therefore had no protection against an older application replacing the sprites with its own, older style. Although I did have that ulterior motive that I wanted my blue directories, the core reason that this wasn't useful was that people had expressed a desire for themable desktop. So, making that possible was important - as I may have mentioned before.
The solution I came up with was to introduce another sprite area which would take priority over any other sprites. In this way, you could place any custom sprites in there and they would always take precedence over any others that were loaded. This allowed styled groups of icons to be managed in the other pool without affecting the basic set of sprites.
The downside to this was that any application which wanted direct access to the sprite pool wouldn't know about the additional priority pool. Whereas such an application might call the SWI Wimp_BaseOfSprites to get at the details it needed, this wouldn't be sufficient if there were 3 pools in use (ROM and RAM pools, plus the new priority pool). Instead, a new SWI Wimp_ReadSysInfo call was added which returned the relevant pools, should any application need to access them. Doing so with any write operation might be bad, as the addresses of sprites were cached by the Wimp for faster lookup (but that had always been the case).
Rather than using the sprite pools directly, the most commonly needed operation is 'does this sprite exist' (with the common extra requirement being 'and which pool is it in'). This was needed for Filer, DragASprite, and a couple of other places where the Wimp sprite areas are checked by components. SWI Wimp_Extend 256 was created (originally as a lower number, but this was moved later) to perform the lookup so that applications didn't need to know how it was done.
'Theme' type sprites could be loaded into the priority pool using the *IconSprites -priority <filename> command. All other *IconSprites worked on the RAM pool as they had previously.
Internally, the whole handling of sprite area lookups was taken out of the assembler and rewritten in C. Essentially it would build up the same tables that the Wimp expected, but do so for the new priority pool, and the ROM and RAM pools, ordered as configured. This meant that all the code that previously used the tables continued to work (although I think I stopped Filer from knowing about these tables and changed it to call the new Wimp_Extend call - Filer shouldn't cheat by knowing how the Wimp is implemented, as it's obviously wrong, but also fixes the implementation in ways that are unreasonable). The C code was marginally faster than the original, and significantly more maintainable.
Tiled backgrounds
Back for RISC OS 4, Matthew Bullock incorporated his 3D patch in the WindowManager. One of the nice things that was gained from that was that the menus could have a tiled background, just like the regular windows could. This made the menus look a little nicer in many cases, and could be turned off if needed. I used a quite nice very pale blue background for the menus, which made it look a bit different and added colour to a generally dull menu.
Changing the WindowManager over to using the new tiled sprite plotting calls added with the abstracted video drivers meant that the main windows, and the menus, could be rendered much more quickly. The code reduction in the source wasn't all that great, but it made a lot more difference for the accelerated hardware drivers.
Filename suffixes
There are different suffixes that are used on sprite file filenames to
indicate the mode type they are used in. Originally there was only the empty
suffix (eg '!Sprites
'), which remains the fallback if no other
types are known. This was extended in RISC OS 3 to use a suffix based on the
pixel density of the mode that is in use - accepting that the mode might
change. I had considered that it might be interesting to retain the details
for other modes, so that if you changed resolutions you got different
sprites, but this would be a more significant step, and would have changed
the behaviour of the system in a more complex way.
Anyhow, for the normal rectangular modes of RISC OS 2, the implicit suffix
was '24', indicating that a pixel was 2 OS units across and 4 OS units up.
In RISC OS 3 this moved towards square pixels, 2 OS units by 2 OS units (a
'22' suffix). Hence there were many '!Sprites
' files that
contained the RISC OS 2 style sprites, and new '!Sprites22
'
files that contained the RISC OS 3 sprite set. There was also a magic
'23' suffix which would be used if you selected the 'high resolution
monochrome' mode. These weren't actually used by many people because such
displays were quite expensive and rare.
The style of icons changed in RISC OS 4, but nothing else about the filename conventions did. This meant that we had sprites which were styled for the old style being used with the RISC OS 4 icon set. This looked wrong, and as mentioned above, Acorn introduced the protected ROM pool. After release of RISC OS 4, some applications used the new style. Some used the old style. Things began to look a bit of a mess unless you took the time to standardise your own icon sets. Not something that most people would want to do.
Pace had begun to introduce the use of the highest resolution modes which first saw the light of day in the Iyonix. I was not at all confident at the time of the overall system behaviour in these modes, so didn't want to embrace it so as to suggest it be used by people commonly. It worked, but there was more work needed to make it work well. The resolution of those modes meant that the suffix for the sprite files was '11', but this was further confused by the fact that the style of icons used by RISC OS 5 was completely different to that of the RISC OS 4 branch, and further from the style used by RISC OS 3 and before.
This, and the fact that the order of files to try for a given mode was tedious to repeat in different applications, indicated that it would be useful to expose the Wimp internal routine which constructed filenames for resolution dependent files. SWI Wimp_Extend 14 was created... and changed to 257 when it was found that this clashed with an undocumented API in RISC OS 5, again. As usual, I emailed Castle - and all the related reason codes were bumped up to be higher than 256, so that they wouldn't clash when they added other things. And as usual, no response. Oh well.
Anyhow, the API itself was used by a few of the internal tools and applications - RISC_OSLib became a little simpler, and the Toolbox operations on sprite files could go through it, simplifying their operation. Well, they would have done, except that the Toolbox has to run on the earlier versions of the OS, so the fallback method had to be retained . The interface gave a central interface to construct variant names, but I wanted to extend this in the future.
The API requires that the buffer allow for up to 8 extra characters on the filename, despite the fact that the current system only expects 2 to be appended. This was to allow for the future extension to add a theme name to the identifier (in a simple way). The 'name' would probably only be a code, starting with maybe a 2 character sequence or something - I'd not decided on the exact details. This would allow for files that were specific to a particular variant of the system - a RISC OS 3 style set could be produced and differentiated from a RISC OS 4 style set, or even groups could produce their own icon themes which would have their own format.
And when I finalised the 'vector sprites', they could be suffixed through
the API themselves, either with a resolution suffix of
'xx
', or 'Vc
' or
something. Applications which used the API could find that they didn't
care what the type was and the correct file would be selected.
Disclaimer: By submitting comments through this form you are implicitly agreeing to allow its reproduction in the diary.