Configure Plug-ins

Introduction

Configure is the desktop application through which the user alters the configuration of the machine: the choices that are stored in CMOS RAM, the files within the Choices boot structure, and the settings of other components of the system. Each area of configuration is presented in its own window, and each of those windows is provided by a separate plug-in application. Configure itself provides the main window from which the plug-ins are opened, decides whether the machine is in a state where its configuration may be changed, and manages the closing of plug-ins.

This chapter describes the interface between Configure and its plug-ins. It is intended for those who write a plug-in for a piece of hardware or software, for those who write a group of related plug-ins which are presented together, and for those who write installation tools which add resources to the boot structure. It defines the user interface that a plug-in must present, the resources that a plug-in supplies, the way in which a plug-in is started and positioned, the Wimp messages exchanged with the plug-in, and the commands which are provided by the Installer module.

The content of the individual configuration windows (the choice of options on the Mouse window, for example) belongs to the plug-ins which provide them and is not described here. The use of the Toolbox to build a plug-in's window is likewise outside the scope of this chapter.

Overview

Structure

A configuration system is made up of the following parts:

  • The root (or controlling) application, which displays the main window containing one icon for each top-level plug-in.
  • Plug-ins, which are applications whose directories are placed within a configuration directory. Each plug-in opens a single window, which is used to alter one aspect of the configuration.
  • Group plug-ins, which are plug-ins whose window shows a further collection of plug-ins, in the same way that the main window does. The members of a group are second-level plug-ins. Groups may be nested to further levels. A generic shell application, CPIShell, provides the behaviour of a group, so that a group need consist only of the shell, a messages file and a directory of children.
  • The Installer module, which merges files and entries into the boot structure, keeping backups and logs of what it has done. It is used by the windows which install new resources.

Plug-ins are separate tasks. They communicate with the root application (or with the group which controls them) through a small number of Wimp messages, described in Wimp Messages. A plug-in which does not know about the protocol can still be used, but will not position its window consistently and cannot object to being closed; see Protocol-ignorant applications.

Purpose of plug-ins

Separating the configuration windows into individual applications allows parts of Configure to be added or removed without altering the rest. Third-party hardware, such as a SCSI interface, can supply its own configuration window which appears alongside the standard ones, and each plug-in can be maintained, upgraded and distributed by its own author. A system administrator may remove the plug-ins for areas which users must not alter (the network configuration, for example) without preventing them from changing others, such as the mouse speed.

Groups of plug-ins

Where there are many related configuration windows, they are collected under a single icon in the main window. Opening that icon opens a window which presents the members of the group as icons, in the manner of the main window. The group is the controlling plug-in for its members: it broadcasts the quit messages for them, and it passes on to them the class that identifies the group (see Plug-in classes).

The members of a group may be hidden or faded according to the configuration of the machine, or the version of the operating system, so that the same group can be shared between several versions of the system. The conditions are described in Group shell.

Locking

The root application is responsible for deciding whether the machine is in a state in which it may be configured. That decision depends upon whether the machine was booted locally or remotely, the access permissions of Choices$Write, and the state of FSLock. When configuration is not possible, the icons of the main window are faded, and the plug-ins cannot be started from it. The details are in Locking and failed writes.

Protocol-ignorant applications

An existing configuration application which does not implement the protocol can be included as a plug-in. In that case the root application takes the name of the application, without the leading !, as the text of its icon; the name of the application, including the !, as the name of its sprite; and a generic string as its help text. These defaults are a fallback only. An application which is written to be used as a plug-in must supply its own text, sprite and help, as described in Plug-in resources.

The only message which such an application must handle is Message_Quit. Without the remainder of the protocol the window of the application will not be positioned beside the icon that opened it, and the application will not be reopened at the front of the window stack when its icon is clicked a second time.

User Interface

General principles

Every configuration window is a dialogue box presented in the standard RISC OS style. All gadgets must comply with the Style Guide. Each window has separate action buttons at the bottom, rather than instant-effect gadgets and a close icon. Because a window has a Cancel button, it has no close icon.

The windows normally provide the following action buttons. Where a Default button is present it restores the factory defaults for the system, which may differ from the defaults of the same components when they are soft-loaded on an earlier system.

ButtonClickAction
SetSelectConfigures the current selections and closes the window.
SetAdjustConfigures the current selections, and leaves the window open.
CancelSelectCloses the window without configuring the selections. The next time that the window is opened it will show the configured values.
CancelAdjustResets the selections to the configured values; that is, to the values when the window was opened or last Adjust-clicked on Set, whichever is more recent.
DefaultAdjustResets the selections to the factory defaults without configuring them.
DefaultSelectAs for Adjust. Selecting the defaults and then closing the window would only duplicate Cancel, so the button does not close the window.

A window may also provide a Try button, for settings whose effect can be sampled (the system beep, or a screen saver), so that the user can test them without configuring them.

A window which is opened gains the input focus, so that Return and Escape can be acted upon. If the window has no writable icons it must place an invisible caret. The Set button, or its equivalent, must always be a default action button (with the 3D border of a cream well), to show that it is the action taken on Return.

When the user clicks on the icon of a plug-in whose window is already open, the window is reopened at the front of the window stack in the same position, without changing any of its selections. The root application does this by sending Message_OpenConfigWindow. A click with Adjust does not close the main window.

Where a plug-in is used within a group, the group's Cancel closes all of the open windows of its members, and its Set does the same after telling them to save any data which they have modified. Unless Adjust was used, the group's own window then closes as well. A member whose data has been modified, and which has not been told to set it, asks the user whether to discard, cancel or set it; see Quit protocol.

Interactive help

Interactive help text is standardised across plug-ins. Only one help message can be given to each gadget (which may consist of several icons and, for a string set, a menu), and gadgets provide no help while they are faded. In the table below, *** is replaced by text appropriate to the circumstances, and |M is the sequence which makes the Help application insert a line break. Wherever possible, the help text of a gadget takes one of these forms:

GadgetHelp text
Plug-in activation icon (main window)Click SELECT to open the *** configuration window.
Plug-in work areaThis window allows you to configure various aspects of the ***.
Preceding labelsThis is the ***.
Numeric range (writable)You can adjust the *** using either the keyboard or the arrows.
Numeric range (display)You can adjust the *** using the arrows.
Writable iconsYou can enter the *** here.
String setsYou can choose a *** from the menu.
SlidersYou can adjust the *** using the slider.
Following labelsThe *** is measured in ***. The non-abbreviated name of the unit is used, followed by any necessary explanation of the unit, in brackets if that is brief.
Option buttonsThis indicates if ***.|MClick SELECT to select or deselect this option.
Radio buttonsThis indicates if ***.|MClick SELECT to select this alternative.
Drop zonesYou can drop a *** here.
Try action buttonsClick SELECT to sample the selected ***.
Default action buttonsClick SELECT to reset the selections to the factory defaults.
Cancel action buttonsClick SELECT to close this window without configuring the selections.|MClick ADJUST to reset the selections to the configured settings.
Set action buttonsClick SELECT to configure the selections and close this window.|MClick ADJUST to configure the selections without closing this window.

Main window

The main window contains one icon for each plug-in, sorted alphabetically by the descriptive text of the plug-in. The window initially has room for up to five columns and four rows of icons; if there are more, the work area extends beyond the visible area. The window can be resized in the manner of a directory display. The text, sprite and help of each icon come from the plug-in, as described in Plug-in resources.

The menu of the main window has no Quit item. It contains:

  • Info, which leads to a submenu offering an information box for the application and for each top-level plug-in.
  • Save CMOS, which saves the contents of the CMOS RAM to <Choices$Write>.CMOS.
  • Load CMOS, which restores the CMOS RAM from that file.
  • Help..., which starts interactive help.
  • Default CMOS, which loads the CMOS RAM from Choices:ResetCMOS.

The three CMOS items are faded when the reading or writing of the files they use is not possible, for example because FSLock is active. When Choices$Write is on a locked filing system, or when the machine has been booted remotely and Choices$Write is not publicly writable, every icon in the work area is faded. If FSLock is active, the icon of the Lock plug-in is not faded, so that the user can unlock the machine.

The help text for the work area of the main window changes with the state of the machine.

ItemHelp text
Work areaConfigure allows you to control various preferences of operation and startup.|MClick SELECT on the icons to open the individual configuration windows.
Work area (disc locked)Configure allows you to control various preferences of operation and startup.|MThe icons are faded because the hard disc is locked.|MClick SELECT on the Lock icon if you wish to unlock the hard disc.
Work area (no permission)Configure allows you to control various preferences of operation and startup.|MThe icons are faded because you do not have permission to save your choices on the remote machine.
InfoMove the pointer right to view information about the configuration system.
Save CMOSClick SELECT to save all the CMOS RAM as a file, from where you can restore it later.
Save CMOS (locked)You cannot save the CMOS RAM while FSLock is active.
Load CMOSClick SELECT to load all the CMOS RAM from your saved CMOS file.
Load CMOS (no file)You do not have a CMOS RAM file to load from.
Load CMOS (locked)You cannot load the CMOS RAM while FSLock is active.
Help...Click SELECT to load interactive help, for guidance on the use of Configure.
Default CMOSClick SELECT to restore all the CMOS RAM to the factory default settings.

Installation windows

Three windows install resources into the boot structure, and share both their user interface and the Installer module that does the work:

  • System, which merges a !System directory into System$Dir.
  • Fonts (the Install fonts... button of the Fonts window), which merges a !Fonts directory into the font directory.
  • Boot (the Install button of the Boot window), which merges a !Boot directory into Boot$Dir.

The Fonts and Boot windows are second-level plug-ins, opened by their parent through its group. The window of each is dragged to by a directory display; the dropped directory must be named and structured in the same way as the one it is to be merged into. The merge is described in terms of the objects and operations defined in Installer module.

The window has three states. In the initial state it asks for a directory to be dropped on it; it returns to this state whenever Cancel is clicked with Adjust. When a suitably named directory is dropped (even after a preview has been calculated), the window shows the name of the source and offers Quick merge, which starts the merge at once, and Preview. The preview examines all of the files concerned, determines the necessary operations, and presents them as a list of option buttons. The user may deselect any operation which they do not wish to perform; All and None select and deselect every operation. If an error occurs during the merge the user may cancel or continue; the window stays in the preview state, with the operations that completed successfully deselected.

The operations offered are the addition, update or removal of each file, as determined from the state of the destination before and after the operation. A font face is treated as a single item, so that the operations are of the form Update face Homerton.Medium. Paths are shown relative to the destination directory. The System and Boot windows also offer a Synchronise !System operation, generated whenever the contents of System$Dir are altered, which runs *Install_CheckSystem.

Directories of load and execution address &DEADDEAD (known as corpses) are requests for the object at the equivalent position of the destination to be removed. An empty directory is created at the destination with *CDir.

WindowDestinationDifferences
SystemSystem$DirLooks for modules, corpses, empty directories and miscellaneous files. The search starts from any subdirectory, whether or not it is an application, except Backup. Backups and the log are kept in the Backup and Log objects of System$Dir. Synchronises !System at the end.
FontsThe third-last directory on Font$PathLooks for fonts and corpses. The search starts from any subdirectory excluding applications. Backups and the log are kept in the Backup and Log objects of Boot$Dir. Runs *FontInstall at the end.
BootBoot$DirLooks for any file or font, together with corpses and empty directories. The search starts from the source directory itself, excluding Backup and Log. Backups and the log are kept in Boot$Dir, unless the destination is within System$Dir, when the System locations are used. Synchronises !System only if the contents of System$Dir were changed. The Boot.PreDesktop and Boot.Desktop files in Choices$Write are merged with *Install_Merge rather than updated.

The interactive help for the merge windows follows the standard forms. For the System window:

GadgetHelp text
MergeClick SELECT to close the dialogue box and start the merging process.|MClick ADJUST to do the same, but keep the dialogue box open.
CancelClick SELECT to cancel this dialogue box.|MClick ADJUST to forget about the !System directory that has been dropped on to this window.
AgendaClick SELECT to view a list of all the operations that will be performed during the merge.
AllClick SELECT to select all the operations.
NoneClick SELECT to deselect all the operations.
Pane iconsThis is one of the operations that will be performed as part of the merge process.|MClick SELECT to disable or re-enable the operation.

Lists of boot items

Plug-ins which edit an ordered list of files, such as the items to be run or booted at startup, present the list in a scrolling pane. The list contains leafnames; a directory refers to the objects within it, to which the action is applied in turn. The list accepts files, applications and directories dropped on to it, drags within it (with autoscrolling) to change the order, and the Remove, Select all and Clear selection buttons. Entries in the file which were not written by the plug-in are shown faded; they cannot be selected or edited, and new items cannot be placed before or between the faded entries which come first, or after the faded entries which come last. Items which can be edited are shown with fully canonicalised names, and are stored relative to Boot: or Boot:^ where that is possible. The entries are written to the boot files with *Install_Merge; see Merging obeyfiles.

GadgetHelp text
Remove selectionClick SELECT to remove all the selected files, applications and directories from this window.
Select allClick SELECT to select all the files, applications and directories.
Clear selectionClick SELECT to deselect all the selected files, applications and directories.
Pane work areaDrag files, applications and directories to this window to add them to the list.
Un-faded items in paneDrag this around within the window to change its position within the sequence.|MDrag other files, applications and directories to this window to add them to the list.

Technical Details

Plug-in resources

A plug-in is an application directory located within a configuration directory. For the root application this is BootResources:Configure; for a group it is the directory given by the -dir option of the shell (see *CPIShell). The root application scans its directory when it starts. The information about each plug-in is read from the Messages file in the plug-in's application directory, using the following tokens.

TokenMeaning
_ConfigTextThe brief text of the icon in the window of the controlling application, and the key by which the icons are sorted. Defaults to the name of the application without the leading !.
_ConfigHelpThe interactive help text of the icon. It should follow the form given in Interactive help. A generic string is used if the token is absent.
_ConfigSpriteThe name of the sprite for the icon. The sprite is taken from the Wimp sprite pool. Defaults to the name of the application including the !.

To make the sprite available, the controlling application runs *IconSprites on the file CoSprite within the plug-in (or CoSprite22 and so on, following the usual conventions for sprite files). To avoid clashes with other sprites in the pool, the names of sprites within these files begin with the three characters co_.

A plug-in will normally also have a !Sprites (or !Sprites22 and so on) file and, optionally, a !Boot file, for the case where it is used as a stand-alone application. Plug-ins are not normally booted by the Filer unless a directory display is opened for the configuration directory, which saves time and space in the sprite pool. The sprite for the application in !Sprites should differ from that in CoSprite, as the latter is not constrained to 68×68 OS units. If no better sprite is available the !configure sprite can be used.

A plug-in which is a group controlled by CPIShell may also use the tokens described in Group shell.

Starting a plug-in

The controlling application starts a plug-in with Wimp_StartTask, passing the command line described by *ConfigurePlugIn. The -openat option gives the preferred position of the top-left corner of the window, in decimal OS units, relative to the screen; a typical command ends !InetSetup -openat 120 844. A plug-in which is started without that option (for example, because its application was double-clicked in a directory display) must centre its window on the screen. A plug-in which was started without -openat must also ignore Message_PlugInQuit, as it will not subsequently receive a Message_Quit.

When the user clicks on the icon of a plug-in which is still running, the controlling application sends it Message_OpenConfigWindow instead of starting it again. The plug-in must reopen its window at the front of the window stack, in the same position, and must make no other change, equivalent to an Adjust-click on Cancel that leaves its state alone.

A plug-in is launched on behalf of a group with -class naming the plug-in class of the group that controls it; see Plug-in classes.

Opening a particular plug-in directly, rather than the group as a whole, is done by starting the group's shell with -openwith. If the shell is already running, the same information is passed to it in Message_OpenConfigWindow, as described there.

Plug-in classes

Each plug-in system is identified by a plug-in system descriptor, a 32-bit number. The descriptor identifies the group of plug-ins to which the messages in Quit protocol apply, so that a message intended for the plug-ins of one group is ignored by the plug-ins of another.

A plug-in has a class, the descriptor of the group of which it is a member, which it receives with the -class option. A group, in addition, has a control class, the descriptor of the plug-ins which it controls, which it receives with the -control option. The group sends the control class in the messages that it broadcasts for its members, and passes it to each of them as their class. The root application is the controller of the main plug-in system, and uses the descriptor &50DBF as its control class.

Descriptors are allocated within the same chunk of numbers as the Wimp messages of the protocol, which starts at &50D80. The values in use are:

DescriptorPlug-in system
&50DBFThe main Configure plug-in system (the root application)
&50DBEBoot configuration
&50DBDFonts configuration, and the font merge dialogue
&50DBCNetwork configuration
&50DBBSound configuration
&50DBADisc configuration
&50DB9Display configuration
&50DB7Extension configuration
&50DB5Window configuration
&50DB4User configuration
&50DB3Input configuration

Other values may be used for new groups, but must be kept within the range of numbers allocated for Configure. The same descriptor field is used in the messages so that the quit messages may be used by tasks which are not plug-ins of Configure: a task which does not recognise the descriptor must ignore the message.

Locking and failed writes

Only the root application tests whether the machine is in a state which allows its configuration to be changed. A plug-in does not repeat that test. Since plug-ins are normally reached only through the root application, which will not start them if the machine cannot be configured, this is sufficient.

A plug-in can also be started directly, by double-clicking its application. For that case a plug-in must not report an error if it fails to write to disc or to CMOS RAM. It must, however, still apply the settings for the current session. This allows a knowledgeable user to alter the operation of a locked machine, for example the mouse speed or the filename width of the Filer, when no other interface is available.

The Lock plug-in cooperates with the root application to change the state of FSLock, using the messages described in Lock protocol.

Quit protocol

The root application must close its plug-ins when its main window is closed, or when FSLock is activated. A plug-in whose selections would be difficult or time-consuming to repeat, such as an editor for the boot sequence, should be able to object. The existing Message_PreQuit mechanism cannot be used to warn these plug-ins, because it can only close a single task or the entire desktop and cannot restart the closing process if the user decides to proceed. The quit protocol is used instead, and is also used between a group and its members.

The sequence is as follows.

  1. The controller receives a request to close its window, a Message_PlugInQuitContinue from a plug-in that has finished its confirmation, or (for the root application) a Message_FSLockStateChangeRequest for lock status 2. It broadcasts Message_PlugInQuit, using event type 18 (recorded delivery), with its control class in the plug-in system descriptor.
  2. A plug-in which has the same class, has modified data and has not yet been told to proceed, claims the message so that it is not returned to the sender, and asks the user whether to discard, cancel or set the data. This may take several calls to Wimp_Poll.
  3. If the user chooses to discard or to set, the plug-in sends Message_PlugInQuitContinue to the task which sent Message_PlugInQuit, and will no longer object. The controller then repeats step 1, so that other plug-ins have their turn.
  4. If the user chooses to cancel, the plug-in broadcasts Message_PlugInQuitAbort. Every plug-in which receives the message with a matching descriptor sets its objection state ready for the next time. The quit process stops.
  5. If no plug-in claims the message, the Wimp returns it to the controller. The controller then sends Message_Quit to each of its plug-ins individually. The Lock plug-in is not sent the message when the closure was the result of locking.

When the closure was caused by a group, rather than the root application, the process is the same, except that the group sends Message_PlugInQuit with a flags word, which says whether the user clicked Set or Cancel. A plug-in told that Set was clicked can assume that the user wants its data set, and so does not need to display the dialogue box asking whether to discard, cancel or set it. A group which has been asked to close, and which has members that object, is responsible for itself objecting in the same manner, and for forwarding the quit to its members once they have no further objection.

A plug-in which wishes to be able to object must, in addition to handling Message_PreQuit in the usual way, behave as shown in Handling the quit protocol.

When a plug-in is closed with Message_PreQuit and flag bit 0 is set (a closure of the single task, for example from the Task Manager), a group which has members still open claims the message and tells its members to quit as if Cancel had been clicked. The group's own closure is then the result of the Message_Quit which follows. A closure of the entire desktop is not intercepted.

Lock protocol

The Lock plug-in and the root application have a private protocol, used to change the state of FSLock; other tasks must ignore these messages. The Lock plug-in broadcasts Message_FSLockStateChangeRequest with the new lock status (0, 1 or 2). If the new status is 2, the root application quits all of the other plug-ins, using the quit protocol, and fades their icons in the main window. If none of them objects, the root application broadcasts Message_FSLockStateChangeConfirm to the Lock plug-in, which then applies the new status. The confirmation is never sent if one of the plug-ins objected to being closed. The Lock plug-in announces the completed change to every instance of itself with Message_FSLockStateChanged, so that their windows can be updated.

The status values are 0 (permanently unlocked), 1 (temporarily unlocked) and 2 (locked).

Handling the quit protocol

A plug-in which can object to being quit maintains two flags: a complain flag, which is set when the plug-in is initialised, and a modified flag, which is set when its selections differ from the configured values. It responds to the messages as follows.

      When Message_PlugInQuit is received with a descriptor equal to our class:
  If complain and modified are both set:
    Acknowledge the message, so that it is not returned to the sender
    Ask the user whether to Discard, Cancel or Set the data
    If Discard or Set was chosen:
      Clear complain
      Send Message_PlugInQuitContinue to the sender of Message_PlugInQuit
    Otherwise (Cancel was chosen):
      Broadcast Message_PlugInQuitAbort

When Message_PlugInQuitAbort is received with a descriptor equal to our class:
  Set complain, ready for the next time

The message is acknowledged by sending it back to the task which sent it as a Wimp user message acknowledgement (event type 19), with the your_ref field set to the my_ref of the message. A plug-in which is told that the user clicked Set, in the flags word, sets its data without displaying the dialogue box, and objects only if it cannot do so; it reports that error itself. If the plug-in was started without -openat it ignores the message.

Group shell

CPIShell is the application which implements a group of plug-ins. A group consists of the shell and a directory containing the application directories of its members. The shell displays the members in a window in the manner of the main window, starts them in the way that the root application does and takes part in the quit protocol on their behalf. It is started with the command line described in *CPIShell.

The messages file of the application which uses the shell (the directory named by -msgdir) may supply the following tokens.

TokenMeaning
_ConfigWindowTitleThe title of the window of the group.
_ConfigSetMessageA message which is displayed when the Set button is clicked. It may be used to give a warning about the details that have been configured.

In addition to the tokens in Plug-in resources, the messages file of a member may supply the following tokens.

TokenMeaning
_FadeIfVariableThe plug-in is faded depending on the state of a system variable. The value is a name preceded by + (fade if the variable is set) or - (fade if the variable is not set).
_FadeIfModuleAs for _FadeIfVariable, but the plug-in is faded depending on whether a module is present (+) or absent (-).
_FadeIfPoduleAs for _FadeIfVariable, but the value is the product type of a podule, and the plug-in is faded if the podule is present (+) or absent (-).
_FadeIfFileAs for _FadeIfVariable, but the plug-in is faded depending on whether a file is present (+) or absent (-).
_ConfigHelpFadedThe help message of the icon of a plug-in which has been faded.
_ConfigHiddenIf the token is present, with any value, the plug-in is not included in the list. A hidden plug-in is not shown at all, unlike a faded plug-in. It is only useful to hide configuration which would otherwise conflict with a later version of the operating system.
_ConfigMaxOSVersionA three-digit version of the operating system. If the version given by Boot$OSVersion exceeds this value, the plug-in is hidden. The final digit of the system variable is always zero, so a component which applies to RISC OS 4.00 only has the value 400.
_ConfigOSVersionThe three-digit operating system version to which a plug-in applies. It determines the directory into which the plug-in is installed; see Installing a plug-in.

The values of _FadeIfVariable and _FadeIfModule may combine several conditions with the conjunctions & (logical AND) and | (logical OR). The conjunctions must be separated from the conditions by spaces, and cannot be nested. For example,

_FadeIfModule:-SCSI & -SCSIFS

fades the plug-in if neither the SCSI module nor the SCSIFS module is present.

Installing a plug-in

A new plug-in can be added to a group by dragging its application directory to the window of the group. An application is accepted as a plug-in only if its messages file contains a _ConfigSprite token. If it does not, the user is told that the application cannot be installed, or is warned that installation may have undefined results.

The destination within the configuration structure depends upon the _ConfigOSVersion token in the messages file of the plug-in. If the token is absent the plug-in is installed into the RO400Hook directory, for compatibility with earlier versions of the operating system. Most commonly the value is 420 or 400.

Installer module

The Installer module provides the operations used to install files into the boot structure, through a number of star commands, so that they can be used in an Obey file as an installation script. The module ensures that backups and logs are kept for every change, that modules are compared correctly, that the font messages files are updated, and that the version directories of !System are maintained.

The module recognises the following kinds of object. It installs one object at a time; it does not install an entire directory in a single command.

ObjectMeaning
FontA compound object, consisting of all the files (of any file type) in one directory, one of which has a name beginning IntMet. The font is referred to by the directory, for example Resources:$.Fonts.Homerton.Medium.
ModuleA file of type &FFA.
ObeyfileA file of type &FEB (Obey), &FD7 (TaskObey) or &FEA (Desktop).
DatafileAny other file, typed or untyped.

Backups and logs. The commands which replace or remove a file first copy it to a backup directory, and then append a record of the operation to a log file. Both are held below the directory selected with *Install_LogDir: the log file is called Log, and a file which has the path path relative to the log directory is backed up at path relative to its Backup directory. The log directory must therefore be higher in the hierarchy than any file to be installed, or the file cannot be backed up. When no log directory is defined the log data is written to the screen. For a module, the version number multiplied by 100 is appended to the name of the file in the backup directory, and the version is given in the log.

Newness. *Install_Update replaces a file only if the source is newer than the destination. If both files are modules, the version numbers are compared, and if they are equal, the datestamps of the files. Otherwise the datestamps of the files are compared, with the following special cases: an untyped file has the datestamp of the beginning of time; a font has the most recent datestamp of the files in its directory (not recursively); a directory has the most recent datestamp of the files within it (recursively); and where there is nothing at the destination, but it is located below a file rather than a directory, the datestamp of that file is used.

When fonts are installed or removed, the messages files in the first !Fonts directory above the destination are updated. For each new font family a default face is selected, in order of preference: none (regular), Medium, Book, Light, Demi, Bold, Heavy and Black, followed by the Oblique and then the Italic versions of the same.

When files in the Encodings directory of a fonts directory are changed the messages files are not updated, as the module cannot know that the files are within a fonts directory. To rebuild them, the caller should wipe !Fonts.Messages# and then install a font, which causes a new messages file for the current territory to be built, including the encodings. Aliases in the messages file of a source font are not copied to the destination file. When a complete !Fonts directory is removed, the backup copies of the messages files may be incomplete, because the file is updated as each font is removed. A font face which has been removed as a font directory is no longer recognised as a font by a later request to remove it, which then removes the hierarchy below it as well.

Obeyfile entries. An obeyfile which can be merged is made up of entries, each of which has the form:

      |Start company application version section
...assorted * commands...
|End

Only the first word of the section name is significant. The company, application and section are matched without regard to case. A non-empty entry must always have a version number of at least 0.01. The comment |Variable, within an entry, causes an existing entry of the same version to be overwritten.

Merging obeyfiles

*Install_Merge combines the entries of a base obeyfile and a changes obeyfile into a destination file. The entries of the changes file are merged into the base file one by one:

  1. The base file is scanned for the first entry with the same section. If there is none, the first applicable rule is used to decide where the new section is placed. If no rule applies, the default rule *>* is used.
  2. The consecutive entries with that section are scanned for the first with the same company, and if none is found the rules are used in the same way.
  3. The consecutive entries with that section and company are scanned for one with the same application. If none is found, the rules are used again. If there is one, the version numbers are compared: if the new entry has a matching or earlier version, the entry of the base file is kept, and otherwise the entry from the changes file is used.

The changes file may contain positioning rules. A rule is a one-line entry beginning with |Section, |Company or |App, with the form

|[Section|Company|App] rule [rule [rule ...]]

where each rule is either specifier>specifier, meaning that the item on the left is created after the item on the right, or specifier<specifier, meaning that it is created before it. There must be no spaces within a rule. A specifier is a single word naming a section, company or application, without regard to case, or *. On the left, * means any specifier, and on the right it means all of them. The rules are applied from the first appropriate line of the file to the last, and from left to right within each line.

*Install_DeMerge performs the reverse operation, removing entries from the base file.

Wimp Messages

The messages of the protocol have numbers in the chunk starting at &50D80. In every message the plug-in system descriptor is a number identifying the plug-in system for which the message is intended; see Plug-in classes. A task which receives a message and does not recognise the descriptor must ignore the message.

Message_PlugInQuit&50D80
Warn the plug-ins of a system that they are about to be quit
OffsetSizeNameContents
04size24, or more to indicate that further data is present
124your_ref0
164action&50D80
204descriptorplug-in system descriptor of the plug-ins which are to be quit
244flagsflags (present if the message size is more than 24; the message is sent in a form which does not include the flags if the sender does not distinguish Set from Cancel)
Bit(s)NameMeaning
0SetClear:the user clicked Cancel, or the quit was not initiated by a click
Set:the user clicked Set
1-31Reserved, must be zero
Message must be broadcast (destination 0)

Message must be sent recorded delivery (reason code 18)

This message is broadcast by the controlling application of a plug-in system (the root application, or a group of plug-ins) to tell its plug-ins that they are about to be quit, unless one of them objects. It is sent as recorded delivery, using event type 18, so that if no task claims it the Wimp returns it to the sender. The sender then closes its plug-ins using Message_Quit.

A plug-in which does not recognise the descriptor must ignore the message. A plug-in which was started without the -openat option must ignore it, as it will not receive a following Message_Quit.

The behaviour expected of a plug-in is described in Quit protocol and in Handling the quit protocol.

Message_PlugInQuitContinue&50D81
Resume the quitting process after a plug-in has no further objection
OffsetSizeNameContents
04size24
124your_ref0
164action&50D81
204descriptorplug-in system descriptor of the plug-in which sends the message
Message must be sent directly to task

Message may only be sent normally (reason code 17)

This message is sent by a plug-in, directly to the task which broadcast Message_PlugInQuit, to tell it to resume the quitting process. The plug-in sends it when it has halted the process in order to ask the user for confirmation, and the user has chosen to discard or set the data.

The plug-in must fill in the descriptor correctly. If it does not, the controlling application will ignore the message, or may take the wrong subsequent action.

Message_PlugInQuitAbort&50D82
Tell plug-ins that the quitting process has been aborted
OffsetSizeNameContents
04size24
124your_ref0
164action&50D82
204descriptorplug-in system descriptor of the plug-in which sends the message
Message must be broadcast (destination 0)

Message may only be sent normally (reason code 17)

This message is broadcast by a plug-in when the user has decided to cancel the quitting process. It allows the other plug-ins to know that the process has been aborted, so that they reset their internal complain flag, and can object again to a later request to quit. A plug-in which receives it resets the flag if the descriptor is its own class, or if it controls the group with that descriptor. A task which does not recognise the descriptor must ignore the message.

The controlling application broadcasts the message with its own descriptor before it starts a new quit process, in case the last one has not finished.

Message_OpenConfigWindow&50D83
Reopen the window of a plug-in at the front of the window stack
OffsetSizeNameContents
04size20 for a plain request, or at least 24 with a component name
124your_ref0
164action&50D83
204descriptorplug-in system descriptor (only present if the size is more than 24)
240componentzero-terminated string naming a component to open, optionally followed by a space and parameters (only present if the size is more than 24)
Message must be sent directly to task

Message may only be sent normally (reason code 17)

This message is sent by the controlling application when the user clicks on the icon of a plug-in whose task is still running. The plug-in must reopen its window at the front of the window stack, in the same x and y position, and must not make any other change to the window or its selections.

The message may be sent to a group of plug-ins with a component name, when a request is made to open a particular member (see the -openwith option of *CPIShell). If the message is larger than 24 bytes, the descriptor must be that of the group, and is followed at offset 24 by a name of the form plugin or plugin.component, which is the name of the member to open and, if given, the member of that member. Any parameters for the member follow the name, separated by a space. The message must be padded to a multiple of four bytes, and the whole message must fit within the 256 bytes of a Wimp message. If the descriptor does not match, the component is ignored and the window is reopened as for the plain form.

Message_FSLockStateChangeRequest&50D84
The Lock plug-in requests a change of FSLock state
OffsetSizeNameContents
04size24
124your_ref0
164action&50D84
204statusnew lock status: 0, 1 or 2
Message must be broadcast (destination 0)

Message may only be sent normally (reason code 17)

This message is broadcast by the Lock plug-in for the attention of the root application. Other tasks must ignore it. If the new status is 2, the root application quits all the other plug-ins, using Message_PlugInQuit, and fades their icons in the main window. The plug-ins may object using the quit protocol.

Message_FSLockStateChangeConfirm&50D85
The root application confirms the change of FSLock state
OffsetSizeNameContents
04size20
124your_ref0
164action&50D85
Message must be broadcast (destination 0)

Message may only be sent normally (reason code 17)

This message is broadcast by the root application, for the Lock plug-in, to confirm that the change of state may be made. It is not sent if one of the other plug-ins objected to being closed.

Message_FSLockStateChanged&50D86
The FSLock state has been changed
OffsetSizeNameContents
04size20
124your_ref0
164action&50D86
Message must be broadcast (destination 0)

Message may only be sent normally (reason code 17)

This message is broadcast by the Lock plug-in to announce that the state of FSLock has been changed. It allows several instances of the Lock plug-in to update their windows at the same time.

Commands

The first two commands are the command lines with which the applications of the plug-in system are run. They are not star commands; they are given to Wimp_StartTask or the Run command, in the form <directory>.!Run options. The remainder are star commands provided by the Installer module.

*ConfigurePlugIn
Run a configuration plug-in application
*ConfigurePlugIn!Run -openat x y -class class -openwith component
-openat <x y>-Position of the top-left corner of the window, in decimal OS units.
-class <class>-The plug-in system descriptor of the group of which the plug-in is a member, in hexadecimal.
-openwith <component>-Name of a component to open when the plug-in is a group. The parameters for that component may follow, separated by a space.

The controlling application runs a plug-in in this way. A plug-in which does not receive -openat must centre its window on the screen, and must not respond to Message_PlugInQuit. The positions are measured from the origin of the screen. A plug-in which does not receive -class has no class, and ignores the messages of the quit protocol.

*CPIShell
Run a group of configuration plug-ins
*CPIShell!Run -dir directory -msgdir messages directory -openat x y -control control class -class our class -openwith component -openwithparams parameters
-dir <directory>-Directory in which to search for the plug-ins to display.
-msgdir <messages directory>-Directory containing the messages file for this group; see Group shell.
-openat <x y>-Position of the top-left corner of the window; see *ConfigurePlugIn.
-control <control class>-The plug-in system descriptor of the plug-ins which the group controls, in hexadecimal. This is the descriptor sent in the quit messages for the members, and is passed to them as their class. Defaults to &50DBF.
-class <our class>-The plug-in system descriptor of the group of which this group is a member, in hexadecimal.
-openwith <component>-Open with a particular component displayed. The name is that of the application directory of the member, optionally followed by a dot and the name of one of its own members, for example ScrnSetup.SvrSetup to open the screen saver plug-in.
-openwithparams <parameters>-Parameters to use when opening the component named by -openwith; for example -from ADFS::$.Some.Path.!Boot to give the Boot installation plug-in a source directory.
-root -Run as the root application, using the configuration directory BootResources:Configure.

The shell presents the plug-ins found in the directory as a window of icons, which can be opened in the same way as those of the root application. Only one instance of the root application may run at any time. If the root application is already running when a second is started, the second sends Message_OpenConfigWindow to the first, with the component given by -openwith and its parameters, and then exits.

Run <ConfigPluginShell$Dir>.!Run -dir <Boot$Dir>.Resources.Configure.!BootSetup -msgdir <Boot$Dir>.Resources.Configure.!BootSetup -openat 120 844 -control 50DBE -class 50DBF Run <ConfigPluginShell$Dir>.!Run -root -openwith BootSetup.BootMerge -openwithparams "-from ADFS::$.Some.Path.!Boot"
*Install_LogDir
Set the directory for the log file and backups
*Install_LogDir*Install_LogDir directory
<directory>-The new log directory.

Defines the directory into which the Installer module writes the log file, called Log, and builds the backup tree. Backed-up files have the same path relative to directory.Backup as they had relative to directory. The directory must therefore be higher up the hierarchy than any file which is to be installed or removed, or the file cannot be backed up.

The log directory is undefined by default, so the command is normally used at the beginning of an installation script. If no argument is given the current log directory is printed.

*Install_NoLogDir
Forget the log directory
*Install_NoLogDir*Install_NoLogDir
None

Undefines the log directory. The command is normally used at the end of an installation script. While there is no log directory, the data for the log file is written to the screen.

*Install_Update
Install a file if it is newer than the destination
*Install_Update*Install_Update source_file dest_file
<source_file>-The file to install.
<dest_file>-The file to be replaced.

Copies source_file to dest_file if the source is newer than the destination. The rules which determine newness are given in Installer module. A file which is overwritten is first copied into the backup directory, and the details of the operation are appended to the log file. For a font, the messages files in the first application directory above dest_file are updated to include the new font.

*Install_Remove
Back up and remove a file or directory
*Install_Remove*Install_Remove file
<file>-The file or directory to remove.

Moves the file to its backup directory, and appends the details of the operation to the log file. A file of the same name which is already in the backup directory is first deleted. For a module, the version number multiplied by 100 is appended to the name of the file in the backup directory, and the version is mentioned in the log. For a font, the messages files in the first fonts directory above the file are updated to reflect its removal.

*Install_Merge
Merge the entries of two obeyfiles
*Install_Merge*Install_Merge base_file changes_file dest_file
<base_file>-The base source file.
<changes_file>-The changes source file.
<dest_file>-The destination file. This may be the same as one of the source files.

Combines the entries of two obeyfiles, placing the result in the destination file. The entries of the changes file are merged one by one into the base file, using the rules given in Merging obeyfiles. If the destination file is overwritten it is first copied into the backup directory. Each successful entry update is listed separately in the log file, with its new version number and any old version number.

Adding an application to those which are seen at startup, with a changes file which contains the line |App Configure>*:

*Install_Merge <Choices$Write>.Boot.PreDesktop tempfile <Choices$Write>.Boot.PreDesktop

The section ResApps and company Acorn are assumed to exist already, as part of the default file; all the other Acorn ResApps entries come first.

Creating the section Run after the section Boot, or after Auto if Boot does not yet exist, using a changes file which contains the line |Section Run>Boot Run>Auto:

*Install_Merge <Choices$Write>.Boot.Desktop tempfile <Choices$Write>.Boot.Desktop
*Install_DeMerge
Remove entries from an obeyfile
*Install_DeMerge*Install_DeMerge base_file changes_file dest_file
<base_file>-The base source file.
<changes_file>-The file whose entries identify those to be removed.
<dest_file>-The destination file.

Removes from the base file any entry whose section, company and application match an entry in the changes file, unless the version number of the entry in the base file is newer than that in the changes file. The result is placed in the destination file. The changes file must therefore include at least the entry headers of the most recent version of each entry to be removed. If the destination file is overwritten or deleted it is first copied into the backup directory, and the details of the operation are appended to the log file.

*Install_CheckSystem
Remove modules which are masked by newer ones
*Install_CheckSystem*Install_CheckSystem
None

Ensures that the versions of modules in the OS-version subdirectories of System$Dir are not older than those in previous-version subdirectories, or in the root Modules subdirectory. Any which are older are removed in the manner of *Install_Remove.

Examples

Handling a request to quit

A plug-in which edits a list of items checks, when it receives a request to quit, whether its data has been modified, and asks the user what to do. Only when the user chooses to cancel does it prevent the closure.

      static int complain = 1;

int message_plugin_quit(WimpMessage *message, void *handle)
{
  if (message->data.words[0] != plugin_class)
    return 1; /* not for us */

  if (complain && modified)
  {
    /* Claim the message so that the quit is stopped for now */
    message->hdr.your_ref = message->hdr.my_ref;
    wimp_send_message(Wimp_EUserMessageAcknowledge, message,
                    message->hdr.sender, 0, NULL);

    /* Ask the user to Discard, Cancel or Set; for Cancel, abort */
    /* the quit for everyone, otherwise let the sender continue */
    ...
  }
  return 1;
}

Opening a plug-in within a group

To open the screen saver plug-in of the Display group and set a source directory for it, the shell of the group is started with the name of the component. If the shell is already running, it receives the name in Message_OpenConfigWindow instead.

      Run <ConfigPluginShell$Dir>.!Run -root -openwith ScrnSetup.SvrSetup
     

Placing an entry before others

To ensure that an entry for a company is placed before all of the others in a section, whether or not the section exists already, the changes file contains positioning rules. The first line states that the section Installation is created after the section Comments, if it does not exist, and the second that the company Acorn is created before all of the other companies.

      |Section Installation>Comments
|Company Acorn<*

A later installer which needs to place an entry after one which may not yet be present can first install an empty entry such as Acorn Wimp 0.00 Installation. If a genuine entry already exists the empty one is ignored; if it is installed later, the position of the empty entry overrides the default rule. This is why non-empty entries must always have a version number of at least 0.01.