Wimp.Desktop

New Calls

        Wimp_Initialise
        Wimp_CloseDown
        Service_WimpCloseDown
        Wimp_StartTask
        *Desktop
        Service_StartWimp
        Service_StartedWimp
        Wimp_Poll: reason code 18 (message) action 0 (global closedown)

Starting/stopping a task

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.

Starting the desktop

Either: *Desktop
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 Desktop, on finding that the service call has been claimed, will pass the value returned in R0 on to Wimp_StartTask, thereby invoking the *command in a new Wimp domain.

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:

After starting up the module, the Desktop will re-issue the service call, and will continue in this way until no-one claims the service, at which point it issues Service_StartedWimp (&4A) to say that it has finished, and exits. Any tasks that were started up during the sequence then continue running.

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.

Errors

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:

Closing down

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.