The Acorn Wimp is a very powerful and comprehensive piece of software available and accessible to all Archimedes users. It represents the state of the art in the excellent user interface which it creates. And more importantly it provides the means by which full co-operative multi-tasking is achieved on machines with RISC OS fitted.
If you are among those who write programs on the Archimedes, and have not yet come to grips with the Wimp, then there are many good reasons why you should. As well as enabling your programs to multi-task, the Wimp also greatly simplifies access to filing systems. If your program needs to operate on data files, you do not need to write any code to find or display files, or move around the directory structure of the ADFS or Econet: the Desktop filer provides all this, and allows you to drag data files onto an application icon to run them - and much more besides.
The Wimp presents the user with an easy-to-use, and intuitive interface. To the programmer it provides a very powerful structure within which to build his own code - which may be written in Basic, Assembler, or other high level languages such as C. The only real downside from the programmer's point of view is the complexity of the Wimp. But this is really quite unavoidable in view of the massive flexibility built into the system, as we will see in due course.
Because of this complexity, we will be treating the whole subject in a measured fashion, with the intention of spreading the introduction of new concepts throughout the series. To make this possible, we will gloss over a number of areas early in the series, returning to them at a later date to fill in the gaps.
Throughout the series we will be using Basic, and we will assume that you have RISC OS fitted in your machine (since the RISC OS Wimp is considerably more powerful than the Arthur Wimp). The best source of reference for the series will be the four-part RISC OS Programmer's Reference Manual. Part two of the Arthur Programmer's Reference Manual constitutes a reasonable second best, but inevitably lacks information on the considerable RISC OS extensions to the Wimp. Should you have access to neither of these volumes, you should nevertheless find sufficient information within this series to make considerable use of the Wimp in your own programs.
The acronym Wimp stands for Windows, Icons, Menus and Pointers. The software which handles this user interface in the Archimedes is a resident module called the Window Manager, often referred to as the Wimp. A typical window is shown in figure 1, and it is assumed that you are familiar with the effect of clicking the mouse when the pointer is over the various parts of the window. If not, switch on your machine, and find out!
The really excellent thing about the Acorn Wimp is that not only will it place windows on the screen exactly where you want them, but it will fully maintain them as well. For example, if the user drags a window to a new position on the screen, then the manager will handle this for you. Only if part of the window needs redrawing (as it would if it had previously been obscured by another window) will your program need to do anything, and in such cases the Wimp will tell your program exactly which parts of the window need updating. This means of course that a dialogue must be struck up between your program and the Wimp, and we will see how this works in due course.
Virtually all access to the Wimp is via so-called SWI calls, or their Basic equivalent, the SYS call. If you are unfamiliar with SYS calls, you are referred to the brief article in this issue: SYS Calls Explained. There are a staggering 52 Wimp calls documented in the RISC OS Programmer's Reference Manual, but we will start by concentrating on the use of just nine of these - see table 1.
Wimp_Initialise
Wimp_CreateWindow
Wimp_OpenWindow
Wimp_GetWindowState
Wimp_Poll
Wimp_RedrawWindow
Wimp_GetRectangle
Wimp_CloseDown
Wimp_ReportError
In very broad terms, a Wimp program will begin by making a call to Wimp_Initialise. This informs the Wimp of the existence of the new task (or program), and if the task has not been run from the Desktop, it will set up the mode, colour palette and pointer. At the same time, the Wimp issues the task with a so-called task handle. This is a number unique to that particular task, which may be used when referring to the task in future dialogues.
In order to open a window on the screen, the program must next make a call to Wimp_CreateWindow. In this call, the program provides a large block of data for the Wimp which precisely defines the window and the way in which it will behave. This block contains details of the exact size and position of the window, whether it has scroll bars, what its component colours are and so on.
Although it defines the window, this call does not cause it to be drawn on the screen. A second call, Wimp_OpenWindow, is used for this purpose. And even then, nothing will actually appear until a so-called Wimp Poll takes place. The Wimp_Poll SWI call is central to the whole operation of the Wimp. It is this call which is used to maintain the dialogue between each particular task and the Wimp, and it is by means of this call that the Wimp achieves multi-tasking.
In all Wimp programs there must be a central routine which makes repeated calls to Wimp_Poll. The Window Manager responds to these calls by returning a value, called the reason code, to the calling program (or task), and the task in turn responds to this. The reason code may indicate that the user has clicked on an icon in the task's window, or that he has typed at the keyboard, or whatever. In any case, it is up to the task to interpret the reason code, react accordingly, and then call Wimp_Poll again to find out what to do next.
Unbeknown to each task, the Wimp multi-tasks through this Wimp_Call. What happens is that the Wimp returns to each task in turn, so that in the time between a task calling Wimp_Poll, and getting back a reason code, the Wimp has serviced each of the other concurrent tasks in turn. This is all handled completely by the Wimp, and all that each task must do is to call Wimp_Poll in a central REPEAT loop, and to respond as quickly as possible to the reason code which the Wimp returns, and then call Wimp_Poll again, so passing control back to the Window Manager.
It should be stressed at this point that all Wimp programs must behave in this way. No special code over and above this is needed to accomplish multi-tasking. Whether or not a Wimp program multi-tasks depends on the way in which it is called. If it is run from Basic, then it behaves as a straightforward Basic application. If it is run from the Desktop, then it will multi-task with any other programs currently running. For specific details on multi-tasking you are referred to the two-part article "Multi-Tasking with RISC OS" in RISC User Volume 2, Issues 3 and 4.
To see how this all works in practice, we will take a look at the program in listing 1. This creates and maintains a single resizable window containing text and graphics. To try the program, type it in carefully, and save it away before running it. There are two ways to run it: it can be run just like any other Basic program by LOADing it into RAM, and typing RUN (or combining the operations using CHAIN), or alternatively you can double click on the program's icon from the Desktop. The advantage of the former approach is that when you quit the program by clicking on the "X" icon at the left of the title bar, your program will still be in RAM, from where it may be edited, and re-run.
If you run the program from the Desktop, you will see that it multi-tasks happily with any other task currently running, but with the disadvantage that when you leave the Desktop (either by selecting Exit, or using Ctrl-Shift-F12), the program will not be recoverable, and must be re-loaded from disc if you wish to edit it.
Incidentally, if you are running the program from the Desktop, you will probably not be able to start up any further tasks once the program is running (including clones of the program itself), because there is insufficient RAM. This is because the RISC OS Task Manager has allocated large quantities of free RAM to the task. You can stop this from happening by invoking the Task Manager Window. Click with the Menu button over the "A" icon at the right hand side of the icon bar at the base of the screen, and allocate just 16 or 32K to the "Next task" before running the program. We will deal with a special call for allocating RAM to each task in a future issue (but if you need to know now, see the article "Creating RISC OS Application Directories" in RISC User Volume 2 Issue 4 page 20).
Next month we will look in some detail at this program, and see how the various Wimp calls are made. In the mean time you may like to experiment a little. First of all check that the program behaves itself correctly, in a multi-tasking environment. Do all the icons produce the expected result when clicked? Can the window be dragged properly? And can you spot the inconsistency in the way in which the window is updated? Running more than one copy of the program may make this clearer.
If you want to experiment further, try altering the six parameters of FNcreate at line 220. The first two are the x and y co-ordinates of the bottom left hand corner of the visible part of the window. The second two are the width and height of the visible part of the window, and the last two are the x and y dimensions of the hidden part of the window i.e. the part of the window which is initially hidden, but which can be made to appear by clicking on the scroll bars or by resizing the window. More on all this next month.
10 REM >!RunImage
20 REM Program Simple Wimp Demo
30 REM Version A 0.12
40 REM Author Lee Calcraft
50 REM RISC User September 1989
60 REM Program Subject to Copyright
70 :
80 DIM block% &200
90 ON ERROR PROCerror:END
100 :
110 quit%=FALSE
120 REM-------------------------------
130 REM INITIALISE WIMP
140 REM-------------------------------
150 $block%="TASK"
160 SYS "Wimp_Initialise",200,!block%,"Test" TO version%,task%
170 REM-------------------------------
180 REM CREATE WINDOW
190 REM-------------------------------
200 REM x,y,width,height,extx%,exty%
210 REM extx% & exty% are hidden parts
220 whandle%=FNcreate(200,200,300,500,
200,200)
230 REM-------------------------------
240 REM OPEN WINDOW
250 REM-------------------------------
260 block%!0=whandle%
270 SYS "Wimp_GetWindowState",,block%
280 SYS "Wimp_OpenWindow",,block%
290 REM-------------------------------
300 REM WIMP POLL
310 REM-------------------------------
320 ON ERROR IF FNwimperror THEN END
330 REPEAT
340 PROCpoll
350 UNTIL quit%
360 $block%="TASK"
370 SYS "Wimp_CloseDown",task%,!block%
380 END
390 REM-------------------------------
400 :
410 DEFPROCpoll
420 SYS "Wimp_Poll",,block% TO reason%
430 CASE reason% OF
440 WHEN 1 :PROCredraw
450 WHEN 2 :!block%=whandle%:SYS "Wimp_OpenWindow",,block%
460 WHEN 3 :quit%=TRUE
470 WHEN 17,18:IF block%!16=0 THEN quit%=TRUE
480 ENDCASE
490 ENDPROC
500 :
510 DEFFNcreate(vwx%,vwy%,vww%,vwh%,extx%,exty%)
520 $block%=STRING$(88,CHR$0):REM Clr
530 REM Visible Work Area
540 block%!0=vwx% :REM x1
550 block%!4=vwy% :REM y1
560 block%!8=vwx%+vww% :REM x2
570 block%!12=vwy%+vwh% :REM y2
580 block%!24=-1:REM no winds above
590 block%!28=&FF00000F:REM wndow flg
600 REM Window Colours
610 block%?32=7 :REM Title fgnd
620 block%?33=2 :REM Title bcg
630 block%?34=7 :REM Work area colour
640 block%?35=1 :REM Work area bcg
650 block%?36=3 :REM Scroll bar bcg
660 block%?37=1 :REM Scroll bar fgnd
670 block%?38=12 :REM Title bar hlght
680 REM Work Area Extent
690 block%!40=0 :REM WAE x1
700 block%!44=-vwh%-exty% :REM WAE y1
710 block%!48=vww%+extx% :REM WAE x2
720 block%!52=0 :REM WAE y2
730 block%!56=&3D:REM Title icon flags
740 block%!60=3<<12:REM Work area flgs
750 $(block%+72)="Test Window"
760 SYS "Wimp_CreateWindow",,block% TO
handle%
770 =handle%
780 :
790 DEFPROCredraw
800 block%!0=whandle%
810 SYS "Wimp_RedrawWindow",,block% TO
more%
820 PROCgetorigin(block%,x0%,y0%)
830 WHILE more%
840 PROCdraw(x0%,y0%)
850 SYS "Wimp_GetRectangle",,block% TO more%
860 ENDWHILE
870 ENDPROC
880 :
890 DEFPROCgetorigin(block%,RETURN x0%,RETURN y0%)
900 x0%=block%!4-block%!20
910 y0%=block%!16-block%!24
920 ENDPROC
930 :
940 DEFPROCdraw(x0%,y0%)
950 SYS "Wimp_SetColour",11
960 MOVE x0%,y0%-40
970 PRINT TIME$
980 SYS "Wimp_SetColour",10
990 CIRCLE FILL x0%+100,y0%-400,50
1000 ENDPROC
1010 :
1020 DEFPROCclose
1030 $block%="TASK"
1040 SYS "Wimp_CloseDown",task%,!block%
1050 ENDPROC
1060 :
1070 DEFPROCerror
1080 ON ERROR OFF
1090 $block%="TASK"
1100 SYS"Wimp_CloseDown",task%,!block%
1110 PRINT REPORT$;" at line ";ERL
1120 ENDPROC
1130 :
1140 DEFFNwimperror
1150 !block%=ERR
1160 $(block%+4)=REPORT$+" at line "+STR$ERL+CHR$0
1170 SYS "Wimp_ReportError",block%,3,"Test Window" TO ,response%
1180 IF response%=2 THEN PROCclose:=TRUE ELSE =FALSE