> net#arf:$.a500.RiscOS+.doc.SaveDesk


Author: Neil Raine
Status: Draft proposal, not agreed yet
History:
        20-Sep-89  0.01  First draft.
        20-Sep-89  0.02  TinyDirs section added.
        20-Sep-89  0.03  Desktop_PreSavingDesktop stuff deleted.
                         *SetMemorySize -next <n>k added
                         Comment about *Desktop_SetPalette added.
                         Comment about printer drivers saving choices added.
        20-Sep-89  0.04  /<Edit$Dir>.!Edit changed to /<Edit$Dir>
                         Comment about junking Filer=>Display=>Save added.
        20-Sep-89  0.05  Section about "shared resources" replaces "!System"
        21-Sep-89  0.06  Simplified according to WStoye's comments
        26-Sep-89  0.07  Added stuff about !Alarm
                         Added 'Outline' section
                         Added 'Work done in Desktop module' section
        29-Sep-89  0.08  Correct section about dbox
                         Enlarged section on Filer
         4-Oct-89  0.09  Message_SavingDesktop changed to Message_SaveDesktop
                         Example code segment for C application added
         6-Oct-89  0.10  Stuff about not acknowledging Message_SaveDesktop
        19-Oct-89  0.11  Stuff about desktop auto-saving removed
                         Aside about save dbox not being a menu removed
                         "Work done in the Desktop module" section removed
GStark  27-Oct-89  0.12  Added Service_WimpSaveDesktop (in resident modules
                         section)
        27-Oct-89  0.13  Corrected Service_WimpSaveDesktop
        31-Oct-89  0.14  Put auto-save icon into description of dbox
GStark  03-Jan-89  0.15  Changed Ram Disc and other slot size stuff to the new spec.

This document describes the Task Manager facility that allows a user to save
and restore the current state of his desktop, thus obviating the need for a
separate !SetDeskWorld utility.


Outline
-------

The Task Manager menu provides an option to save the current state of the
desktop world into a Desktop file, which can be used to restart the desktop
in its original state.

There will also be facilities to save the Desktop file as a !Boot file (on
ADFS) or !ArmBoot file (on NetFS), whereby the necessary configuration
commands to get the system to reboot via this file are automatically carried
out by the Task Manager.

In general the boot file will not return the desktop to precisely the state
it was in, because:

    (a) Applications which have not been specially written to deal with
        desktop saving will not be restarted.

    (b) Apart from Filer directory viewers, applications will not re-open
        all the windows that were open when the desktop was saved.  In
        particular, this means that editors will not re-open the files that
        were being edited.


Work done by Task Manager
-------------------------

Task Manager will have the following options:

        Save state to a given file, without exitting
        Exit to supervisor
        Shutdown machine

The menu therefore contains:

        New task        => (writeable buffer)
        Task display
        *Commands (f12)
        Desktop boot    => (boot dbox)
        Exit
        Shutdown

Note that the menu option says "Desktop boot" rather than "Save desktop" in
order not to raise the user's expectations too high, since it will not in
general be possible to return to precisely the same state as the desktop was
in.

The boot file save dbox would look like this:

        <file icon>

        [ !Boot ]  [OK]

        [ ] Auto boot
        [ ] Auto save

If auto boot is enabled, then the effect of SHIFT being pressed on reset is
reversed: ie. if it is not pressed, the boot file will be executed, and if
it is pressed, the boot file will not be executed.  The icon is initially
set up to reflect the current state of the auto-boot CMOS RAM bit.

The auto save icon is always turned off by default - if it is enabled when
the file is saved, the file will be marked as an auto-save file, so that
when the user selects Exit or Shutdown from the iconbar menu, the desktop
state will be automatically saved in that file.

The filename is initialised to "!Boot" or "!ArmBoot" when the Task Manager
starts up, depending on whether adfs or net is the configured filing system. 
The user can change this if he wishes, and then click on OK or drag the
file into a directory viewer.

        net:
            If directory name is net#<fsname>:&
                *opt 4,2 executed on the appropriate fileserver
                *configure filesystem net
                *configure fs <fsname>
                *configure boot/noboot

        other:
            If directory name is <fs>::<discname>.$
                *opt 4,2 executed on the appropriate disc
                *configure filesystem <fs>
                *configure boot/noboot
            If <fs> is adfs
                *configure drive <drive containing appropriate disc>

Filing systems other than the network are assumed to behave like adfs, ie.
the boot filename is "!Boot" and it must be created in "$".

    Aside:  It was felt that it would be too much of a shock for the user if
            an error message was returned if the file was not saved in the
            root directory, so instead it just doesn't do the filesystem
            configuration etc.


The save protocol
-----------------

Once the file to be saved is known, the save protocol can start:

  * The Task Manager first opens the output file and makes a note of the
    handle.

  * The Task Manager then inserts a comment saying when the file was created,
    so that when the user refers to the file (s)he will know how recent it is.

  * The Task Manager then inserts four *commands:
        1) WimpSlot -next <wimp slot 'next' size>K
        2) ChangeDynamicArea -FontSize <font area size>K
        3) ChangeDynamicArea -SpriteSize <system sprite area size>K
        4) ChangeDynamicArea -RamFsSize <RAM disc size>K

    These set the sizes of the 'Next' slot, the font and sprite area sizes, and
    the RAM disc size, as would be expected. It is not sensible to set the RMA
    size or the system stack in this way, as they are much more system-dependent
    than those described above. The screen size cannot be set as it is always
    reset to the size of the current screen mode by the Task Manager.

    If there is not enough memory free to be allocated for a particular slot then,
    instead of giving errors, the largest amount of memory which is free
    will be allocated to the slot.

  * If the user enabled 'auto-save' in the dbox, the Task Manager inserts
    the following line at the top of the output file:

        *Set SaveDesk$File <Desktop$File>

    What this does is to ensure that when the file is used to restart the
    desktop, the environment variable SaveDesk$File is set up to remember
    the name of the file.  This works because the Desktop module has also
    been extended to set up Desktop$File to the name of the file passed to
    it.

    When the user selects 'Exit' or 'Shutdown' from the task manager's menu,
    it looks to see if the variable SaveDesk$File is set up - if it is, it
    automatically saves the desktop state in this file before exitting.

  * Rather than using broadcast messages, the Task Manager talks to all the
    other tasks by using its list of task handles and names.  This ensures
    that the tasks are asked to restart in the same order as they were
    originally started (which is not true for broadcasts).

  * For each task in its list, the task manager sends a message called
    Message_SaveDesktop:

        +16 Message_SaveDesktop (10)
        +20 (word) file handle of desktop file being written
        +24 flag word:
            bits 0..31  reserved (ignore them)

    Note that this is a RISC OS rather than a C file handle, so fprintf()
    cannot be used.  The RISC OS SWIs OS_BPut or OS_GBPB should be used
    instead.

  * If the task understands the message, it then writes data directly
    into the desktop file, using the file handle supplied.

    The data is a sequence of *commands suitable for inclusion in a Desktop
    file, each terminated by a linefeed character (&0A).  When the file is
    run to start the desktop, each command will be executed as a separate
    Wimp task.

    A typical example for a C application follows:

        #include <os.h>
        #include <swis.h>

        os_error *save_desktop(int handle)
        {
          char *ptr;

          for (ptr=getenv ("Edit$Dir"); *ptr; ptr++) {
            os_error *error = os_swi2(OS_BPut, *ptr, handle);
            if (error) return error;
          }

          return os_swi2(OS_BPut, 10, handle);    /* line terminator */
        }

  * If the message is NOT acknowledged, the task manager goes on to the
    next one in the list.  This means that:

        (a) Tasks which don't understand desktop saving will not be saved in
            the desktop file, and the documentation should make it clear
            that this will happen with old applications.

        (b) If an application gets an error while writing to the file, it
            should acknowledge the message and report the error.  The Task
            Manager will detect that the message has been acknowledged, and
            will abort the save operation and remove the file.

  * When all the tasks have been asked for their restart commands, the file
    is closed, and if the output was a boot file, *Opt 4,2 is executed for
    the appropriate disc drive / user id.

  * If this was an auto-save operation, the exit / shutdown sequence will
    start from there, with the PreQuit broadcast followed by the Quit
    broadcast.


Work done by applications
-------------------------

Normal applications:

    The typical restart command for an application is a GSTrans-ed form of
    something like:

        /<Edit$Dir>

    Note that since several copies of !Edit can be loaded at once, this
    GSTrans-ing operation should be done as soon as the application is
    loaded (and the result stored in a buffer), in case the value of
    Edit$Dir changes subsequently.

Resident modules:

    Resident module tasks do not require a restart command of that form,
    since they are automatically started when the desktop is entered (by
    means of the Service_StartWimp protocol).  However, if the modules are
    not stored in the ROM, they will probably be loaded by means of some
    form of *RMEnsure command in a !foo application, so the !foo application
    should be re-run instead.

    There is a service call provided, though, for modules which need to save
    some state to the file, e.g. ColourTrans saves its calibration. This is
    as below:

    Service_WimpSaveDesktop (&5C)
    In  R0 = flag word (as in Message_SaveDesktop)
        R1 = &5C (reason code)
        R2 = file handle of file to write *commands to
    Out R0 -> Error, if necessary, else preserved
        R1 = 0 for error (i.e. claim), else preserved
        all other registers preserved

    When a module receives this service code it should write out any *
    commands, to the specified file handle, which should be performed by a
    Desktop Boot file on entry to the Desktop.

    If an error occurs (Disc full, Can't extend, or even a module specific
    error like 'Can't save desktop now because...' then the service should
    be claimed, and R0 should point to the error block.

    This service call is performed before the task manager issues the Wimp
    broadcast message Message_SaveDesktop.

NetFiler:

    Network logons must be regenerated, so that Filer windows referring to
    network directories can be re-opened.  The NetFiler module must keep
    track of which username is in use on each fileserver, so that it knows
    the required username to put in the *command.  These commands would not
    include the password - if the user id required a password, the Wimp's
    command window would appear with the *Logon command in the title and the
    prompt 'Password:' in the window.  The current NetFiler would have to be
    changed so that the window title displayed the fileserver and username,
    so that the user knew which password to enter!

Filer:

    As long as the appropriate logons are executed, the current state of the
    filer display can be saved by using the Filer's ability to generate
    *Filer_OpenDir commands for the directories currently open (already used
    in the Filer's Display => Save option).

    The Filer must remember the full pathnames of any applications it sees
    (eliminating duplicates), and issue a "Filer_Boot" command for each
    application that contained a !Boot file (since these can set up aliases
    and load in icons for data filetypes).

    The Filer must issue a Message_FileStarted broadcast after it has
    started all its children, which allows the TaskManager to 'renumber' the
    Filer in its list, so that its desktop saving will be done AFTER that of
    the individual filing systems.  This is important so that the NetFiler
    can issue its logon commands before any net directories are opened.

Shared resources:

    Environment variables pointing to shared resources are set up when the
    !Boot file of the relevant shared resource directory is run.  This is
    therefore dealt with by the Filer.

PaletteUtil:

    The Palette Utility is capable of saving the current palette in a file,
    but this would not be suitable for saving its current state into the
    saved desktop file.  It would have to accept a new *command of the form:

        *Desktop_SetPalette RRGGBB RRGGBB RRGGBB etc. (times 20)

    where 'RRGGBB' is a sequence of 6 hex digits defining colour (0..15,
    then the border colour and then the 3 mouse colours).

    (The maximum length of a line in a Desktop file is 256 characters, and
    at 158 characters, this line is OK).

Printer drivers:

    Similarly the printer drivers can set their current state from the
    'PrData' file stored within themselves, but strictly speaking ought to
    save their state as a set of textual parameters on the command line,
    which could be re-asserted when the command was executed.  The problem
    with simply saving the current state into the PrData file is that two
    different desktop save files with different printer setups would produce
    the same result if there was only one printer application, since both
    would cause the same PrData file to be loaded.  However, it may be
    impractical to duplicate all the functionality of the modifiable parts
    of the PrData file as *commands.

    If the state must be saved in the PrData file, then at least the printer
    drivers should behave like !Edit in that if you try to exit while you
    have unsaved choices, a dialogue box is presented.

!Alarm:

    Applications such as !Alarm that live in DeskFS: cannot easily save data
    into their application directory (unless the user copies the directory
    onto a disc and runs it from there).

    With the advent of desktop saving, it is probably better for
    applications like !Alarm to save small bits of configuration status in
    an environment variable, and then to output an appropriate *Set command
    when the desktop save occurs.

    The ROM version of !Alarm will detect which filing system it was run
    from, and grey out the "Alarm=>Set" option if it detects that it has
    been run from DeskFS.  It can do this as follows:

        handle% = OPENIN"Alarm:!Alarm"               :REM open alarm file
        SYS "OS_FSControl",21,handle% TO ,,fsword%   :REM read FS info word
        CLOSE #handle%
        IF (fsword% AND &FF)=21 THEN <grey out "set alarm">

    !Alarm should use an environment variable to store the user format
    time string, eg.

        *Set Alarm$DateFormat %w3 %zdy %m3 %z12:%mi %pm

    Another environment variable is also required:

        *Set Alarm$DateType Analogue
        *Set Alarm$DateType HoursMins
        *Set Alarm$DateType HoursMinsSecs

    since Alarm$DateFormat is still used for the user date string even if
    (eg) analogue is initially selected.

    In this way all the data concerning the display options is held in the
    desktop save file, rather than the application itself.  CMOS RAM is not
    used, since (a) there is not enough to store the user format string, and
    (b) if the user format string is in a variable, then so should the
    display type be.

    However, the alarms are stored in the application directory, but are not
    available if !Alarm is run from DeskFS.


ADFSFiler:

    It is not necessary to 'log on' to discs - the user will automatically
    be prompted to insert the appropriate discs as required.

TinyDirs:

    The TinyDirs module must return a *AddTinyDir command for each
    directory currently held on the iconbar, in left-to-right order.  When
    re-executed, these commands would cause each new directory to be placed
    to the right of the previous one.

