Wimp.Messages

New Calls

        Wimp_SendMessage
        Wimp_Poll:  reason codes 17, 18, 19
        Wimp_TransferBlock

SWI Wimp_SendMessage

Entry: R0 = reason code to be returned to receiving task

          R1 --> block containing message
          R2 = task handle of task to receive message
       or R2 = window handle (message is sent to owner of window/icon)
          R3 = icon handle   (required if R2 = iconbar window handle (-2))
       or R2 = 0             (message is broadcast to all tasks in turn)

Exit: R2 = task handle of receiver (unless R2=0 on entry)

          the message is queued
          the block is updated if R0 was 17 or 18 on entry

The messages are queued on a First-In-First-Out basis, and are delivered when Wimp_Poll is next called. Note that a message will only be delivered if the receiving task is still active, and has not masked out the relevant reason code (R0 on entry to Wimp_Poll = mask). Messages sent to a window/icon rather than a task are also tagged so that if the window or icon is deleted then the message is not delivered.

Note that pending messages take priority over any other kind of action which might return a reason code from Wimp_Poll.

Wimp_Poll reason codes

        Code    Meaning                         Block size (bytes)
        0       Null                            0
        1       Redraw_Window                   4
        2       Open_Window                     32
        3       Close_Window                    4
        4       Pointer_Leaving_Window          4
        5       Pointer_Entering_Window         4
        6       Mouse_Click                     24
        7       User_DragBox                    16
        8       Key_Pressed                     28
        9       Menu_Selection                  variable
        10      Scroll_Window                   40
        11      Lose_Caret                      24
        12      Gain_Caret                      24
        13..16  Reserved
        17      User_Message                    variable
        18      User_Message_Recorded           variable
        19      User_Message_Acknowledge        variable

Wimp_SendMessage with R0 = 17, 18, 19 (User_Message)

In addition to sending 'ordinary' reason codes to other tasks, such as Open_Window_Request or Mouse_Click, Wimp_SendMessage can be used to send message blocks, using the new reason codes 17, 18 and 19.

The format of the block on entry to Wimp_SendMessage in these cases is as follows: Entry:
+0 size of block ( 20<=size<=256, size MOD 4 = 0)
+4 not used
+8 not used
+12 your_ref (0 if not replying to a previous message)
+16 message action (unique)

        +20..   message data (format depends on message action)
Exit:
+4 task handle of sender (ie. this task)
        +8      my_ref (reference number of message (unique non-zero word))

The two fields on exit are filled in by Wimp_SendMessage, and will also be included in the block received at the other end.

The three different reason codes (17, 18, 19) have the following meanings when given to Wimp_SendMessage:

17 User_Message

The message is sent by the Wimp to the relevant task.

If the message is not delivered (eg. if the task is dead, or it just ignores it), then nothing happens.

18 User_Message_Recorded

The message is sent by the Wimp to the relevant task.

If the message is not acknowledged by the receiving task, then the Wimp will return the message to the original sender, with the reason code changed to 19. To acknowledge a message, the receiving task must send another message with its 'your_ref' field set to the 'my_ref' field of the original message, before it calls Wimp_Poll again.

19 User_Message_Acknowledge

The message identified by the your_ref field is acknowledged.

In order to acknowledge a message (ie. to prevent it from being returned to the sender), the receiving task can either send another message or send a User_Message_Acknowledge, which will acknowledge the message without actually sending one in reply. In either case, the my_ref field of the original message should be copied into the your_ref field of the new message, in order to acknowledge it.

If the original message was a broadcast, acknowledging it will prevent it from being passed to any further tasks.

Note that sending a message type 19 with your_ref=0 and R2/R3 = window/icon handle is one way to discover the handle of the task owning a window/icon (on exit from Wimp_SendMessage R2=task handle) without actually sending a message.

Wimp_Poll reason codes 17, 18, 19

Note that when receiving messages, a task should not distinguish between message types 17 and 18 in terms of their function - it is the 'message action' field which uniquely determines the purpose of a message.

Wimp_Poll reason code 19 means that a type 18 message you sent has been returned to you, since it was not acknowledged (see above).

Message Actions

It is envisaged that, in addition to the 'system' message actions (see below), various families of applications may wish to send messages to each other. To ensure that message actions do not clash, it has been decided that the message numbers will be allocated in parallel with SWI chunk numbers. Thus, if you have already been allocated a SWI chunk, you can use message actions in that range for private purposes. If you have not been allocated any SWI chunks, and you need one, you should apply to Acorn to get it!

The following message actions have been defined so far:

             0  Message_Quit
             1  Message_DataSave
             2  Message_DataSaveAck
             3  Message_DataLoad
             4  Message_DataLoadAck
             5  Message_DataOpen
             6  Message_RAMFetch
             7  Message_RAMTransmit
             8  Message_PreQuit
             9  Message_PaletteChange
          &400  Message_FilerOpenDir
          &401  Message_FilerCloseDir
        &40040  Message_Notify
        &400C0  Message_MenuWarning
        &400C1  Message_ModeChange
        &400C2  Message_TaskInitialise
        &400C3  Message_TaskCloseDown
        &400C4  Message_SlotSize
        &400C5  Message_SetSlot
        &400C6  Message_TaskNameRq
        &400C7  Message_TaskNameIs

0 Quit (broadcast)

R0 = 17/18
R1!0 = size of data

   R1!12= 0                     ; your ref.
   R1!16= 0                     ; action

On receipt of this message, a running Wimp task should tidy up and close down, by calling Wimp_CloseDown and OS_Exit. At this stage, the task should not refuse to close down - if the task has any unsaved data, it should object when it receives the PreQuit message (8), which is always issued prior to the Quit message (see below).

1..7 Data transfer protocol

These messages are detailed in a separate section below.

8 PreQuit (broadcast)

R0 = 17/18
R1!0 = size of data

   R1!12= 0                     ; your ref.
   R1!16= 8                     ; action

On receipt of this message, a running Wimp task should check to see if any data would be lost if it were to close down (ie. if any files have been modified but not saved). If not, the message should be ignored, and the sender of the PreQuit message will follow it up with a Quit message, causing the task to close down.

If the task has unsaved data, it should acknowledge the PreQuit message (SWI Wimp_SendMessage with R0=19, R1->original block, R1!8 copied into R1!12), and bring up a suitable dialogue box so that the user can specify whether to save or discard the files.

If the user subsequently decides to discard the files, the application should restart the closedown sequence by sending a CTRL-SHIFT-f12 keypress event to the sender of the PreQuit message, as follows:

        SYS "Wimp_GetCaretPosition",,R1     :REM fill up first 5 words
        R1!24 = &1FC                        :REM CTRL-SHIFT-f12
        SYS "Wimp_SendMessage",17,R1,prequittask%

(prequittask% is the task handle of the sender of the PreQuit message, which can be read from the original message block).

The Task Manager module provides a global 'Exit' option, which it executes on receipt of a CTRL-SHIFT-f12 as follows:

  1. SWI Wimp_SendMessage,17,prequitblk,0
  2. prequitref = prequitblk!8 ; remember myref field
  3. On receipt of Wimp_Poll (19),
    if message!8 = prequitref then: SWI Wimp_SendMessage,18,quitblk,0 quitref = quitblk!8 ; remember myref field
  4. On receipt of Wimp_Poll (17/18),
    if message action = Quit then if message block!8 <> quitref then <quit>
  5. On receipt of Wimp_Poll (19),
    if message action = Quit then if message block!8 = quitref then <quit> The Task Manager issues the PreQuit broadcast first - if this is not acknowledged by any task, it proceeds to issue the Quit broadcast. This means that if any task objects to being closed down, it does so before any of the other tasks is closed down. It also means that if any task contains unsaved data, the task will not be closed down, and the user must re-select the quit option after responding to the task's save/discard confirmation sequence.

    After sending the Quit broadcast, the Task Manager does not quit itself until it receives its own message back to confirm that all other tasks have been closed down successfully. However, if it receives the message from another task, it should close down immediately.

    Note that the Task Manager responds to CTRL-SHIFT-f12 being pressed by using a 'grabkeys' window (bit 12 of window flags set) to respond to the user pressing the key. Note that due to the above protocol, any form of closedown sequence (such as one that is required in order to boot a new operating system) must respond to the CTRL-SHIFT-f12 keypress message, even if it is never passed user keystrokes (indeed, it should not respond to the actual user keystrokes, since the Task Manager is supposed to deal with that).

    9 Message_PaletteChange (broadcast)

    R0 = 17/18
    R1!0 = size of data

       R1!12= 0                     ; your ref.
       R1!16= 9                     ; action
    

    This message should not be acknowledged by any task.

    The palette utility issues this broadcast whenever the user finishes dragging any of the RGB bars in the palette window, or loads a new palette file.

    On receipt of the PaletteChange message, a task which needs to alter any internal tables or colour mappings when a palette change occurs should do so, and call Wimp_ForceRedraw if necessary to ensure that the relevant changes are reflected on the screen.

    Note that since the palette utility will automatically invalidate the whole screen if any of the Wimp's colours change their logical mapping, most tasks do not need to take any notice of this message. See Wimp.Colours for further details of the Wimp colour mappings.

    This message is not issued when the mode changes, so Message_ModeChange (&400C1) should also be trapped by tasks needing to act on colour mappings.

    NetFiler messages

    The netfiler uses messages in the NetFS module SWI range (&40040-&4007F).

    &40040 Message_Notify (broadcast)

    R0 = 17/18
    R1!0 = size of data
    R1!12= 0
    R1!16= &40040
    R1?20= station number } of sending station R1?21= network number }
    R1?22..R1?26 = 5-byte real time when message was received

       R1?27..      = message (0-terminated)
    

    The NetFiler offers this broadcast around to make it easy for another application to pick up the message and display it in some nice way for the user. If the message is not acknowledged, the NetFiler will simply call Wimp_ReportError with the message in the error box, and the string 'Message from station xxx.xxx' in the title bar.

    Wimp messages

    The Wimp-specific messages are allocated in the range &400C0-&400FF (in its SWI range).

    &400C0 Message_MenuWarning

    R0 = 17/18
    R1!0 = size of data
    R1!12= 0
    R1!16= &400C0
    R1!20= address of submenu data
    R1!24= x-coordinate of top-left of menu R1!28= y-coordinate of top-left of menu R1!32= list of menu selection numbers, terminated by -1

    This message will only be delivered by the Wimp if bit 3 of the menu flags of a menu item is set, and the submenu pointer is not null. If this is true, and the user moves the mouse pointer over the right-arrow icon of the menu entry, then instead of directly opening the relevant submenu, the Wimp will generate this message. After processing the information contained in the message block (and possibly amending the submenu data) the application should respond by calling Wimp_CreateSubMenu with the parameters in the message block at offsets 20, 24 and 28 (ie. the menu data pointer and x,y coordinates). Note that the submenu could be a dialogue window handle.

    The list of menu selection numbers indicates the current state of the menu tree, and is the same as that returned by Wimp_Poll (Menu_Select). This information, together with the application's record of which menu tree it last created, is sufficient to determine whereabouts in the menu tree the Wimp currently is.

    &400C1 Message_ModeChange (broadcast)

    R0 = 17/18
    R1!0 = size of data (20)
    R1!12= 0
    R1!16= &400C1

    On receiving this message, a task which needs to make adjustments on a mode change shuld do so. Note that the mode number is not supplied in the message

    After sending the Message_ModeChange, the Wimp sends an Open_Window_Request for each window that was open at the time the Wimp_SetMode occurred. This is designed so that if the screen width is reduced (eg. if going from mode 16 to mode 12), the windows will be 'scrunched' into the visible portion of the screen. The mode change also causes the entire screen area to be marked invalid, so all windows will be redrawn.

    There is a problem, however: if a task wishes to modify a window after the mode change in a way which requires it to be deleted and re-created, the window handle will change. Unfortunately problems will result if this is done on receipt of the Message_ModeChange, since the Wimp will subsequently return an Open_Window_Request for the OLD window handle, not the new one.

    The solution is that if you need to change the window handle in this way, you should not do it until you receive the Open_Window_Request for the relevant window - in other words, on the Message_ModeChange you should mark the window 'dirty' (in some internal data structure), and on Open_Window_Request check the 'dirty' flag and do the deletion/recreation stuff if required.

    &400C2 Message_TaskInitialise (broadcast)

    R0 = 17/18
    R1!0 = size of block (including header) R1!4 = task handle of new task
    R1!12= 0
    R1!16= &400C2
    R1!20= CAO pointer of task
    R1!24= amount of application memory used by task R1+28..= <task name, as pointed to by R2 on entry to Wimp_Initialise>

    Issued by the Wimp when a task calls Wimp_Initialise. This message is picked up by the Task Manager module, and enables it to maintain a list of running tasks. Note that the Task Manager will only notice tasks which start up after it, so it should be the first desktop module in the module list.

    &400C3 Message_TaskCloseDown (broadcast)

    R0 = 17/18
    R1!0 = size of block (20)
    R1!4 = task handle of dying task
    R1!12= 0
    R1!16= &400C3

    Issued by the Wimp when a task calls Wimp_CloseDown (if a task calls OS_Exit prematurely, the Wimp will call Wimp_CloseDown for it). The Task Manager module is again the main client of this message.

    &400C4 Message_SlotSize (broadcast)

    R0 = 17/18
    R1!0 = size of block (28)
    R1!4 = task handle of task owning current slot R1!12= 0
    R1!16= &400C4
    R1!20= new current slot size
    R1!24= new next slot size

    This message is broadcast by the Wimp whenever Wimp_SlotSize is used to alter the amount of memory owned by a task. It is normally picked up by the Task Manager module to allow it to maintain its display of memory allocation.

    This message should not be acknowledged, since that would stop any other utilities from picking it up.

    &400C5 Message_SetSlot

    R0 = 17/18
    R1!0 = size of block (28)
    R1!12= 0
    R1!16= &400C5
    R1!20= new current slot size
    R1!24= task handle of task whose slot should be changed

    This message is sent to a task by the Task Manager when the user drags the task's slot, if the task has initially told the Task Manager that it can deal with dynamic drags by acknowledging a message of this form when it started up. On receipt of this message, the task should (if R1!20 >= 0) call Wimp_SlotSize to alter its slot size to the appropriate value. See Wimp.Switcher for further details.

    &400C6 Message_TaskNameRq

    R0 = 17/18
    R1!0 = size of block (24)
    R1!12= 0
    R1!16= &400C6
    R1!20= task handle of task being asked about

    If a task wishes to find out the name of a task given its handle, it should broadcast this message. If the Task Manager is running, and it recognises the task handle, it will reply with the following message:

    &400C7 Message_TaskNameIs

    R0 = 17/18
    R1!0 = size of block
    R1!12= myref of previous message
    R1!16= &400C7
    R1!20= task handle of task being asked about R1!24= task's slot size
    R1+28..= <task name, as pointed to by R2 on entry to Wimp_Initialise>

                (0-terminated)
    

    This message pair is used by the !Help application so that it can provide extra help about the ROM modules (which have defined names).

    Data Transfer Protocol

    1 Message_DataSave

       R0     17 (usually)
    
    R1!0 size
         !12  0
         !16  1 ; DataSave
         !20  destination window handle             ;
         !24  destination window icon               ; copied from
         !28  destination x coord (screen coords)   ; Wimp_GetPointerInfo
         !32  destination y coord (screen coords)   ;
         !36  estimated size of data, in bytes
         !40  file type of data
         !44  proposed leaf-name of file, 0-terminated
    

    2 Message_DataSaveAck (save data to file)

       R0     17 (usually)
    
    R1!0 size
         !12  my_ref field of DataSave message
         !16  2 ; save data to here
         !20  destination window handle             ;
         !24  destination window icon               ; preserved from
         !28  destination x coord (screen coords)   ; Message_DataSave
         !32  destination y coord (screen coords)   ;
         !36  estimated size of data, in bytes      ; -1 if file is 'unsafe'
         !40  file type of data
         !44  full-name of file, 0-terminated
    

    Where this message is used as part of the scrap transfer protocol (see below), the 'estimated size' field is set to -1 by the sender, to tell the receiver that his file will NOT be 'safe' after it has been saved to the destination. Typically a file called <Wimp$Scrap> will be saved, and it is not considered a good idea to put '<Wimp$Scrap>' in the title bar of the document that has just been saved, or to mark it unmodified, since the scrap file will be deleted after the sender gets back a DataLoad (see below).

    3 Message_DataLoad (drag file from Filer / I have saved data to a file)

       R0     18 (usually)
    
    R1!0 size
         !12  my_ref field of DataSaveAck message (or 0 if from Filer)
         !16  3 ; load data from here
         !20  destination window handle             ;
         !24  destination icon handle               ; copied from
         !28  destination x coord (screen coords)   ; Wimp_GetPointerInfo
         !32  destination y coord (screen coords)   ;
         !36  estimated size of data, in bytes
         !40  file type
         !44  full path-name of file, zero-terminated
    

    The filer sends this message when a file has been dragged into a window belonging to another application. The application is then free to copy or insert the file, if it so desires.

    If the application can load files of the relevant type, and the file is loaded successfully, it should reply as follows:

    4 Message_DataLoadAck

       R0     17 (usually)
    
    R1!0 size
         !12  my_ref field of DataLoad message
         !16  4 ; DataLoadAck
         !20  destination window handle             ;
         !24  destination icon handle               ; copied from
         !28  destination x coord (screen coords)   ; Wimp_GetPointerInfo
         !32  destination y coord (screen coords)   ;
         !36  estimated size of data, in bytes
         !40  file type
         !44  full path-name of file, zero-terminated
    

    5 Message_DataOpen (broadcast for double-clicked file)

       R0     18 (usually)
    
    R1!0 size
         !12  0
         !16  5                 ; destination info request
         !20  window handle of directory viewer
         !24  unused
         !28  x-offset of icon being opened within viewer
         !32  y                 ; allows for 'zoom' box if implemented
         !36  estimated size of data, in bytes
         !40  file type
         !44  full path-name of file, 0-terminated.
    

    DataLoadAck is returned by the application which loads the file.

    6 Message_RAMFetch (transfer data to buffer in my workspace)

       R0     18 (error message if not acknowledged)
    
    R1!0 size
         !12  my_ref field of DataSave message
         !16  6 ; RAM fetch.
         !20  buffer address
         !24  buffer size (bytes)
    

    7 Message_RAMTransmit (I have put some data in a buffer in your workspace)

       R0     18 (error message if not acknowledged)
    
    R1!0 size
         !12  my_ref field of RAMFetch message
         !16  7 ; RAM transmit.
         !20  buffer address             ; copy of value sent in RAM fetch
         !24  number of bytes written to buffer
              (if buffer not full, send another RAMFetch)
    

    To write the data into the receiver's buffer, use the following call:

    Wimp_TransferBlock
    Entry: R0 = task handle of source
    R1 --> source buffer
    R2 = task handle of destination
    R3 --> destination buffer
    R4 = buffer length
    buffer addresses and length are byte-aligned (not nec. word-aligned)
    if the buffer addresses are within application space,
    they are validated to ensure they are within the correct task
    Errors: "Invalid task handle"

            "Wimp transfer out of range"
    

    Application code for direct file transfer

    NOTE: In all cases where an unknown message action is received by an
           application, it MUST ignore the message completely.
    

    Save file:

    1. transmit DataSave message
    2. if DataSaveAck returned, save file and send DataLoad Unless receiver is the Filer, the DataSaveAck would refer to "<Wimp$Scrap>", and the estimated size field would be set to -1, indicating that the file is not 'safe'.
                         Errors encountered during file saving are reported by the
                         sender, and DataLoad is not sent.
      
              3.      if RAMFetch returned, send RAMTransmit and loop until done
      
      NOTE: all messages in this protocol apart from the DataSave should quote the
      other side's my_ref field in their your_ref fields, to ensure that the
             messages are acknowledged correctly.
      
      Receiver:
      1. DataSave received
      2. If data can be loaded from RAM, send back a RAMFetch (look at approx data size in DataSave message, but do not rely on its absolute accuracy, ie. be prepared for MORE data than that to be sent)
                        If RAMFetch not acknowledged, load from a file (step 3)
        
                           if RAMTransmit received,
                              finished if buffer NOT filled,
                              else send another RAMFetch and loop.
                              if any RAMFetch other than the 1st is not acknowledged,
                                 report error
                              - no need to check your_ref field if RAMFetch (18) used,
                                since the RAMFetch will not be acknowledged
                              if pipe break received, shut up quietly
        
                3.      If data must be in a file, return DataSaveAck "<Wimp$Scrap>",
                        setting the 'estimated size' field to -1.  If the environment
                        variable Wimp$Scrap does not exist, the error message
                        "<Wimp$Scrap> not defined" should be generated.
        
                        If DataLoad received, load file, delete and return DataLoadAck
                           Note that the your_ref field of the DataLoad tells the
                           receiver whether the file is the scrap file.
        

        Minimal functionality is for the sender to only cope with DataSaveAck, and for the receiver to only cope with file-based i/o. If the receiver wishes to engage in RAMFetch operations, it should be prepared for the sender to be ignorant of that protocol - ie. it should be prepared to revert to the scrap file mechanism.

        Ramifications

        The main change to the spec is that all applications must be prepared to recognise DataSave, and return at least a DataSaveAck to <Wimp$Scrap>, followed by acting on DataLoad (which they do anyway), and deleting the file after loading it, if the your_ref field of the DataLoad refers to their DataSaveAck message.

        Another change is that when files are saved onto the Filer, this action is followed by a DataLoad message being sent. Therefore the Filer must respond to the DataLoad message with a DataLoadAck (if the DataLoad your_ref field is correct).

        It might have been possible to shift the onus onto the saver of the data, by sending a DataLoad message to the unsuspecting receiver. However, this would entail the creation and deletion of a scrap file whenever the data is dragged onto the desktop background!