C The Wimp (part 4 - Boxing Clever)

Last time, I was saying that the use of a library (.h) file would, in the long term, save lots of time in that the common parts of any application can be accessed without the need to constantly type the code back in.

The constant typing, whilst it does make you more familiar with the form of the structures and unions, also has the downside that you may rush and make a mistake which will break (i.e. render useless or, at least, partially inoperative) your program.

If you haven't already purchased, from RISCOS Ltd, the excellent PRM CD and haven't obtained the StrongHelp manuals, you will soon run into trouble. In fact, after this tutorial, I'd say you won't be able to get much further without them.

OK, on to the library. I'll deal with the Wimp_Poll block here.

Recap

_swi(Wimp_Poll,_INR(0,1)|_OUTR(0,1),mask,block,&reason code,&block);

where mask is what reason codes we want to see, and block is the 256-byte block. &block contains the returned value from the call.

Given that there are 17 reason codes for the WIMP itself (excluding 14-16) and with the exception of reasons 0 & 3-5 (no reason), the return values all have multiple components (such as Mouse Click which has six return values). The upshot of this is that the returned block will need interpreting. While this may not be overly difficult, it would be tedious to have to constantly work out the offset (position from the start of the returned value).

How to create such a library

It can be done one of two ways - have all the reason code return values in one mammoth structure or (as I will and do) create a number of small structures and include them all in the main structure.

Let's take an example - reason code 6 - mouse click. The call from the poll returns:


  offset   meaning
  0        Mouse x position
  4        Mouse y position
  8        Buttons
  12       Window handle
  16       Icon handle
  20       Button state prior to click

This can be simply translated into a structure thus:

typedef struct mousey {
                      int mouse_x;
                      int mouse_y;
                      int buttons;
                      int window_handle;
                      int ic;
                      int pre_button;
                      } mousey;

Similar mini-structures can also be built up for the other reason codes and, being a structure, there is no reason that if you had, say, defined:

typedef struct win_han {
                        int wh;
                       } win_han;

that this couldn't be included in the mousey structure as:

typedef struct mousey {
                      int mouse_x;
                      int mouse_y;
                      int buttons;
                      win_han window_handle;
                      int ic;
                      int pre_button;
                      } mousey;

When all of these mini structures have been completed, they can be wrapped up into one large structure. Remember though that the WIMP can return messages other than the ones already outlined, so you must ensure this is catered for. Doing this is simple.

typedef struct wimp_block {
                          union {
                                 *bits*
                                } poll;
                          char memory[256];
                          } wimp_block;

in other words, it's either the union or the memory block. (The full version of this is given on both the Acorn Education website or this month's Archive disc.)

SWI or SWIX?

An area I've not yet covered is whether the _swi or _swix form should be used - indeed, what the difference actually is!

Whenever making a system call, RISC OS will return either a zero for a successful call or non-zero for a failed call. If the x form of the call is made, this returned value can be tested. If you don't use the x call, an error may be generated which can vary from helpful (such as illegal window call) to complete gibberish (abort on data fetch at &0322311ac).

Testing for the returned value is a good idea and simple to perform.

if ((_swix(somecall,params))!=0) error_message("swi failed");

While not incorrect, the above line is an example of pseudo-code.

Pseudo-code?

When developing a program of any sort of complexity, unless you know what you are doing, pseudo code is probably one of the most useful methods of learning.

For instance, say you want to write a comparison routine. First off, you would set yourself an aim - in this case to compare two numbers and see if they're the same and, if they are, whether they are divisible by 4 with the answer being an integer.

Next, you write the pseudo code:

is no1 == no2 ?
if no, exit totally
if yes
does no2 divide by 4 & no remainder?
if no, exit with message "are ="
message "are = and /4 cleanly"
exit totally

This is a vague language which follows the structures of a number of computer languages.

It is only a small step to convert this into C.

if (no1!=no2)
{
 printf("not equal\n";
return -1;
}
else
{
 if (no2%4==0)
 printf("are = and /4
 cleanly\n") ;
 else
 printf("are = and not /4
 cleanly\n");
}

(OK, the above is nothing amazing; it's really just to demonstrate a point!)

A second structure which you will need is one for the error handling. The WIMP provides us with a useful (if slightly outdated) error box.

For now, our code to handle the error box is deliberately simple and is this:

void report_error(const int error_number,const char *error_message)
{
 error_block error;
 error.value=error_number;
 sprintf(error.text,"%.251s",error_message);
 _swix(Wimp_ReportError,_INR(0,2),err_block,1,task_name);
}

The task_name is predefined at the start of the code.

That's all I wish to cover for this time. Next time, let's get going on some code.


Source: Archive Magazine 14.7
Publication: Archive Magazine
Contributor: Paul Johnson