Wimp_Initialise Wimp_CloseDown Service_WimpCloseDown Wimp_StartTask
*Desktop Service_StartWimp Service_StartedWimp Wimp_Poll: reason code 18 (message) action 0 (global closedown)
Wimp_Initialise
Entry: if R1 = "TASK" (low-byte = "T", high-byte = "K"):
R0 = last known Wimp version number * 100 (at least 200)
R2 = pointer to short description of task (used by Switcher menu)
(this is a new-style Wimp task)
if R1 <> "TASK",
(this is an old-style Wimp task)
Exit: R0 = current Wimp version number * 100
if R1 = "TASK" on entry,
R1 = task handle on exit
Old-style Wimp programs are recognised by the Wimp by the way in which they call Wimp_Initialise, since they won't set R1 = "TASK" (unless they are extremely unlucky!).
When an old-style wimp application starts up, the Wimp will automatically open a large window with background colour 15, which covers all other windows, so that the task has the whole screen to itself. It will also prevent any other tasks from receiving any kind of event from Wimp_Poll while the old-style task is running.
When new tasks start up, the Wimp will set up the mode and pointer (if this is the first task), whereas it behaves in 'compatible mode' with old tasks, not doing anything except programming the pointer shape.
Wimp_CloseDown
Entry: if R1 = "TASK",
R0 = task handle of task to be closed down
If the task handle is not specified, it is assumed to be whichever task was last active (ie. the last task that Wimp_Poll returned to).
Note that the task handle should always be specified if Wimp_CloseDown is called in (eg) the 'Die' entry of a module, since the relevant task is probably not the one currently running.
When a live task is killed using Wimp_CloseDown, the following service call is issued by the Wimp:
Service_WimpCloseDown (&53)
Entry: R0 = 0 ==> Wimp_CloseDown was called
R0 > 0 ==> Wimp_Initialise was called in the same domain
R2 = task handle of task being closed down
Normally a task will close itself down when it has decided to finish, in which case the service call is somewhat superfluous, but there are two occasions where the task can be closed down 'automatically', as it were.
The first of these happens when OS_Exit is called by the task, and Wimp_CloseDown has not yet been called. This can happen if, for example, an error is generated which is not caught by the task's own error handler - in this case the Wimp reports the error and calls OS_Exit automatically. The service call will come round with R0=0 - in this case, the task receiving the service call should tidy itself up, and pass on the service (it should NOT call Wimp_CloseDown !!!). All registers must be preserved.
The second case occurs when Wimp_Initialise is called in the same task domain as a currently active task. This can occur, if, for example, the task allows the user to enter *commands, in which case it is likely that the user will try to start up another Wimp program. The Wimp will attempt to close down the first task before starting up the new one, and will send round the Service_WimpCloseDown with R0 > 0 (in fact R0=1 initially, but may be modified by the time the module receives it). If R0>0, the original task is allowed to return an error from the service call by pointing R0 at an error block (a good error message is "Wimp is currently active" (error number &103)). The service should not be claimed, so other modules can receive it, and R0 should be preserved unless an error is to be returned. If R0 > 1 on exit from the OS_ServiceCall, the Wimp will return the error to the task attempting to start up, which will prevent it from doing so. Note, however, that application space may well have been overwritten at this stage, so BASIC programs and the like cannot use this facility!
Note that modules should not actually claim this service (set R1=0), since it is possible that more than one module is interested in a particular task closing down.
Wimp_StartTask
Entry: R0 --> *command to execute
This command is used to start up a new Wimp task. It creates a new 'domain' for the task, and executes the *command in it. If and when the task calls Wimp_Initialise, and then Wimp_Poll, control will be returned to the 'parent' task (ie. the one which called Wimp_StartTask).
Note that Wimp_StartTask cannot be called except from within a new-style Wimp application.
Or: Wimp is the configured language, entered by the MOS automatically
The *Desktop command is decoded by the Desktop module, which also supports the DESKFS filing system, and allows the Desktop module to be entered as a language. The *Desktop command cancels the current EXEC file, if any, since the Desktop will exit immediately if an exec file is in operation (this is so that SHIFT-BREAK can be used to start up a boot file).
When the Desktop is entered (by either of the above methods), it attempts to 'wake up' any resident modules which would like to become Wimp tasks. It does this by passing round a service call Service_StartWimp (&49), which wimp application modules should respond to as follows:
The *command should be decoded by the module (by having the command in its command decoding table - see PRM 'Modules' chapter), and should cause the module to enter itself as follows:
SWI OS_Module, R0=2, R1-->module title, R2 = R0 on entry to *command
(R0 points to the command tail on entry to the *command).
Note that it is very important that the module starts itself up as an application, for the following reasons:
Example startup code:
Service LDR R12,[R12] ; get workspace pointer TEQ R1,#Service_StartWimp MOVNE PC,LR
Push "LR" LDR R14,mytaskhandle TEQ R14,#0 ; is module running? MOVEQ R14,#-1 STREQ R14,mytaskhandle ADREQ R0,mycommand MOVEQ R1,#0 ; if not, claim service Pull "PC"
mycommand DCB "foo",0 ALIGN
Mycommand_Code ; command table points here Push "LR" MOV R2,R0 ; R2 --> command tail ADR R1,ModuleTitle ; R1 --> module title MOV R0,#2 ; R0 = ModHandReason_Enter SWI XOS_Module Pull "PC"
Note that the module must actually enter itself in this way, rather than simply jumping to its code, since the MOS has to flatten the supervisor stack and so on, as the new module is a new application.
A problem arises if any module fails to initialise properly, since after reporting the error to the user, the module must abort, and the Wimp will then re-issue the Service_StartWimp call, which will be caught again by the module, and so on (ie. the user is stuck in an infinite loop).
It is better if any errors during initialisation are reported, followed by the rest of the modules starting up. To achieve this, the following procedure must be adopted:
To make it easier for the user to exit from the Wimp environment, the switcher module provides a menu entry that allows the user to close down all tasks. This causes the switcher to issue a broadcast to all tasks, asking them to close down, which should be responded to as follows:
Wimp_Poll
Exit: R0 = 18
R1 --> block (as supplied to Wimp_Poll)
+0 = 20 (size of block)
+4 = task handle of Switcher
+8 = reference number of message
+12 = 0
+16 = 0 (global close down)
If the task can exit immediately, it should do so (by calling Wimp_CloseDown followed by OS_Exit or Wimp_Poll).
If the task has some unsaved data (eg. the user has modified a file and not saved it), it should prompt the user (in the same way as it would if the user had attempted to exit from the task explicitly). Before it does this, however, it must abort the close down sequence by acknowledging the close down message as follows:
Wimp_SendMessage
Entry: R0 = 19 (acknowledge message)
R1 --> block
+ 12 = reference number of closedown message
Once the user has entered a dialogue with any task in this way, therefore, he must explicitly restart the closedown sequence if he still wishes to quit from the Wimp environment.