Copyright (c) Hyperion Entertainment and contributors.
Preferences
This page is currently being updated to AmigaOS 4.x. Some of the information contained here may not yet be applicable in part or totally. |
Contents
Preferences
To make the Amiga operating system easily configurable by the user, the OS comes with a family of editors and associated data files known collectively as Preferences. Preferences allows the user to set system-wide configuration options such as the printer driver to use, serial port baud rate and other items. To make an application appealing to the user, the system-wide Preferences settings should be respected as much as possible by applications. This chapter describes how to use the Preferences system in your programs.
Preferences Editors and Storage
In AmigaOS there can be any number of Preferences editors each with its own separate configuration file covering a specific area. All these Preferences editors have the same look and feel. Using separate Preferences editors and configuration files allows for adding new Preferences items (and editors) in future versions of the OS.
Preferences are store in various ".prefs" files located in the "ENV:sys" and "ENVARC:sys" directories. Preferences options currently in use are located in "ENV:sys". Permanent, saved copies of Preferences files are stored in "ENVARC:sys". These are copied to "ENV:" on an as-needed basis. Applications may also store their own preference files in "ENV:" but should use a sub-directory for that purpose.
Currently the following Preferences editors and files are available:
Preferences Editor | Preferences Configuration File |
---|---|
IControl | icontrol.prefs |
Input | input.prefs |
Palette | palette.ilbm |
Pointer | pointer.ilbm |
Printer | printer.prefs |
PrinterGfx | printergfx.prefs |
Overscan | overscan.prefs |
ScreenMode | screenmode.prefs |
Serial | serial.prefs |
- | wbconfig.prefs |
Font | wbfont.prefs, sysfont.prefs and screenfont.prefs |
Time | - |
WBPattern | wb.pat and win.pat |
Each .prefs file is managed by editor with the same name, except for wbconfig.prefs, which is written directly by Workbench and has no editor. One Preferences editor has no .prefs file, Time. That Preferences editor writes directly to the battery backed clock.
When the user makes a change to a Preferences item with one of the editors, the changes will be saved in either "ENV:sys" or both "ENV:sys" and "ENVARC:sys" depending on whether the user saves the changes with the "Use" gadget or "Save" gadget of the Preferences editor.
The "Use" gadget is for making temporary changes and the new preferences will be stored only in "ENV:sys". If the user reboots, the old preferences will be restored from the permanent copy in "ENVARC:sys".
The "Save" gadget is for making permanent changes and the new preferences will be stored in both "ENV:sys" and "ENVARC:sys". That way, if the user reboots, the new preferences will still be in effect since the system looks in "ENVARC:sys" to find out what preferences should be set to at boot time.
The ENV: Directory and Notification
One advantage of the new Preferences system is file notification. File notification is a form of inter-process communication that allows an application to be automatically notified if a change is made to a specific file or directory. This makes it easy for the application to react to changes the user makes to Preferences files.
File notification is also used by the system itself. The Preferences control program, IPrefs, sets up notification on most of the Preferences files in "ENV:sys". If the user alters a Preferences item (normally this is done with a Preferences editor), the system will notify IPrefs about the change and IPrefs will attempt to alter the user's environment to reflect the change.
For example, if the user opens the ScreenMode Preferences editor and changes the Workbench screen mode to high-resolution, the new settings are saved in "screenmode.prefs" in the "ENV:sys" directory. IPrefs sets up notification on this file at boot time, so the file system will notify IPrefs of the change. IPrefs will read in the Screenmode.prefs file and reset the Workbench screen to high resolution mode.
Here's a short example showing how to set up notification on the "serial.prefs" file in "ENV:sys". The program displays a message in a window whenever this file is changed (e.g., when the user selects the "Use" or "Save" gadget in the Serial Preferences editor).
;/* prefnotify.c. - Execute me to compile me with SAS/C 5.10 lc -cfistq -v -y -j73 prefnotify.c blink from LIB:c.o,prefnotify.o to prefnotify lib LIB:LC.lib LIB:amiga.lib quit ** prefnotify.c - notified if serial prefs change */ #include <exec/types.h> #include <exec/memory.h> #include <dos/dos.h> #include <dos/notify.h> #include <stdio.h> #include <clib/exec_protos.h> #include <clib/dos_protos.h> #ifdef LATTICE int CXBRK(void) { return(0); } /* Disable Lattice CTRL/C handling */ int chkabort(void) { return(0); } /* really */ #endif #define PREFSFILENAME "ENV:sys/serial.prefs" static UBYTE *VersTag = "\0$VER: prefnot 37.1 (09.07.91)"; extern struct Library *DOSBase; void main(int argc, char **argv) { BOOL done=FALSE; struct NotifyRequest *notifyrequest; UBYTE *filename; LONG signum; ULONG signals; /* We need at least V37 for notification */ if (DOSBase->lib_Version >= 37) { /* Allocate a NotifyRequest structure */ if (notifyrequest = AllocMem(sizeof(struct NotifyRequest), MEMF_CLEAR)) { /* And allocate a signalsbit */ if ((signum = AllocSignal(-1L)) != -1) { /* Initialize notifcation request */ filename = PREFSFILENAME; notifyrequest->nr_Name = filename; notifyrequest->nr_Flags = NRF_SEND_SIGNAL; /* Signal this task */ notifyrequest->nr_stuff.nr_Signal.nr_Task = (struct Task *) FindTask(NULL); /* with this signals bit */ notifyrequest->nr_stuff.nr_Signal.nr_SignalNum = signum; if ((StartNotify(notifyrequest)) == DOSTRUE) { printf("Select Serial Prefs SAVE or USE to notify this program\n"); printf("CTRL-C to exit\n\n"); /* Loop until Ctrl-C to exit */ while(!done) { signals = Wait( (1L << signum) | SIGBREAKF_CTRL_C ); if (signals & (1L << signum)) printf("Notification signal received.\n"); if (signals & SIGBREAKF_CTRL_C) { EndNotify(notifyrequest); done=TRUE; } } } else printf("Can't start notification\n"); FreeSignal(signum); } else printf("No signals available\n"); FreeMem(notifyrequest, sizeof(struct NotifyRequest)); } else printf("Not enough memory for NotifyRequest.\n"); } else printf("Requires at least V37 dos.library\n"); }
Preference File Format
To understand the format of Preferences files, you must be familiar with IFF file standard (see IFF Standard for the complete specification).
In general all Preferences files are stored in the IFF format with a type of PREF (see the exceptions noted below). Each file contains at least two Chunks, a header Chunk and a data Chunk.
The Header Chunk
The PRHD header chunk, contains a PrefHeader structure:
struct PrefHeader { UBYTE ph_Version; UBYTE ph_Type; ULONG ph_Flags; };
Currently all the fields are set to NULL. In future revisions these fields may be used to indicate a particular version and contents of a PREF chunk.
The Data Chunk
The data Chunk that follows the header Chunk depends on the kind of Preferences data the file contains. The types of Preferences data Chunks that are currently part of the system are:
Chunk Name | Used With |
---|---|
FONT | Fonts, used for all font Preferences files. In future the PrefHeader may indicate what the font is used for. |
ICTL | IControl |
INPT | Input |
OSCN | Overscan |
PGFX | PrinterGfx |
PTXT | PrinterText |
SCRM | ScreenMode |
SERL | Serial |
Each chunk contains a structure applicable to the type.
FONT
struct FontPrefs { LONG fp_Reserved[4]; UBYTE fp_FrontPen; /* Textcolor */ UBYTE fp_BackPen; /* Character background color */ UBYTE fp_DrawMode; struct TextAttr fp_TextAttr; BYTE fp_Name[FONTNAMESIZE]; /* Font name */ };
ICTL
struct IControlPrefs { LONG ic_Reserved[4]; /* System reserved */ UWORD ic_TimeOut; /* Verify timeout */ WORD ic_MetaDrag; /* Meta drag mouse event */ ULONG ic_Flags; /* IControl flags (see below) */ UBYTE ic_WBtoFront; /* CKey: WB to front */ UBYTE ic_FrontToBack; /* CKey: front screen to back */ UBYTE ic_ReqTrue; /* CKey: Requester TRUE */ UBYTE ic_ReqFalse; /* CKey: Requester FALSE */ };
The ic_Flags field can have the following values:
- ICF_COERCE_COLORS
- This indicates that a displaymode with a matching number of colors has preference over a correct aspect ration when screen coercing takes place.
- ICF_COERCE_LACE
- This indicates that choosing an interlaced display mode is allowed when coercing screens. Otherwise a non-interlaced display mode will be selected.
- ICF_STRGAD_FILTER
- This indicates that control characters should be filtered out of string gadget user input.
- ICF_MENUSNAP
- This indicates that an auto-scroll screen should be snapped back to origin when the mouse menu-button is selected.
Note that the command key values in the last four fields of the IControlPrefs structure are ANSI codes, not RAWKEY codes.
INPT
struct InputPrefs { LONG ip_Reserved[4]; UWORD ip_PointerTicks; /* Sensitivity of the pointer */ struct timeval ip_DoubleClick; /* Interval between clicks */ struct timeval ip_KeyRptDelay; /* keyboard repeat delay */ struct timeval ip_KeyRptSpeed; /* Keyboard repeat speed */ WORD ip_MouseAccel; /* Mouse acceleration */ };
OSCN
struct OverscanPrefs { ULONG os_Reserved[4]; ULONG os_DisplayID; /* Displaymode ID */ Point os_ViewPos; /* View X/Y Offset */ Point os_Text; /* TEXT overscan dimension */ struct Rectangle os_Standard; /* STANDARD overscan dimension */ };
PGFX
struct PrinterGfxPrefs { LONG pg_Reserved[4]; UWORD pg_Aspect; /* Horizontal or vertical */ UWORD pg_Shade; /* B&W, Greyscale, Color */ UWORD pg_Image; /* Positive or negative image */ WORD pg_Threshold; /* Black threshold */ UBYTE pg_ColorCorrect; /* RGB color correction */ UBYTE pg_Dimensions; /* Dimension type */ UBYTE pg_Dithering; /* Type of dithering */ UWORD pg_GraphicFlags; /* Rastport dump flags */ UBYTE pg_PrintDensity; /* Print density 1 - 7 */ UWORD pg_PrintMaxWidth; /* Maximum width */ UWORD pg_PrintMaxHeight; /* Maximum height */ UBYTE pg_PrintXOffset; /* X Offset */ UBYTE pg_PrintYOffset; /* Y Offset */ };
The possible values of each field are defined in <prefs/printergfx.h>. Note that your application is responsible for checking if the supplied values are valid.
PTXT
struct PrinterTxtPrefs { LONG pt_Reserved[4]; /* System reserved */ UBYTE pt_Driver[DRIVERNAMESIZE]; /* printer driver filename */ UBYTE pt_Port; /* printer port connection */ UWORD pt_PaperType; /* Fanfold or single */ UWORD pt_PaperSize; /* Standard, Legal, A4, A3 etc. */ UWORD pt_PaperLength; /* Paper length in # of lines */ UWORD pt_Pitch; /* Pica or Elite */ UWORD pt_Spacing; /* 6 or 8 LPI */ UWORD pt_LeftMargin; /* Left margin */ UWORD pt_RightMargin; /* Right margin */ UWORD pt_Quality; /* Draft or Letter */ };
SCRM
struct ScreenModePrefs { ULONG sm_Reserved[4]; ULONG sm_DisplayID; /* Displaymode ID */ UWORD sm_Width; /* Screen width */ UWORD sm_Height; /* Screen height */ UWORD sm_Depth; /* Screen depth */ UWORD sm_Control; /* BIT 0, Autoscroll yes/no */ };
SERL
struct SerialPrefs { LONG sp_Reserved[4]; /* System reserved */ ULONG sp_BaudRate; /* Baud rate */ ULONG sp_InputBuffer; /* Input buffer: 0 - 64K */ ULONG sp_OutputBuffer; /* Future: Output: 0 - 64K, def 0 */ UBYTE sp_InputHandshake; /* Input handshaking */ UBYTE sp_OutputHandshake; /* Future: Output handshaking */ UBYTE sp_Parity; /* Parity */ UBYTE sp_BitsPerChar; /* I/O bits per character */ UBYTE sp_StopBits; /* Stop bits */ };
Other Preferences File Formats
Not every Preferences file is stored as an IFF file of type PREF. The palette.ilbm and pointer.ilbm files contain a regular ILBM FORM to store their imagery. The win.pat and wb.pat files use a raw format with 16 bytes reserved, followed by a WORD giving the total size of the pattern, a WORD giving the bitplane count, and byte arrays (currently 32 bytes) for each bitplane. The format of the wbconfig.prefs file is private.
Reading a Preferences File
The following example shows a way to read a Preferences file.
;/* showprefs.c - Execute me to compile me with SAS C 5.10 LC -b0 -d0 -cfis -v -j73 showprefs.c Blink FROM showprefs.o TO showprefs LIBRARY LIB:Amiga.lib quit ** showprefs.c - parse and show some info from an IFF Preferences file ** NOTE: This example requires upcoming 2.1 prefs/ include files. ** ** IMPORTANT!! This example is not linked with startup code (eg. c.o). ** It uses strictly direct AmigaDOS stdio, and also demonstrates ** direct ReadArgs argument parsing. Therefore it is a CLI-only ** example. If launched from Workbench, packet errors would occur ** since the WbStartup message is still sitting in the process's ** pr_MsgPort, and the code would never be unloaded from memory. */ #include <exec/types.h> #include <dos/dos.h> #include <libraries/dos.h> #include <libraries/iffparse.h> #include <prefs/prefhdr.h> #include <prefs/font.h> #include <prefs/icontrol.h> #include <prefs/input.h> #include <prefs/overscan.h> #include <prefs/printergfx.h> #include <prefs/printertxt.h> #include <prefs/screenmode.h> #include <prefs/serial.h> #include <clib/exec_protos.h> #include <clib/dos_protos.h> #include <clib/iffparse_protos.h> struct ExecBase *SysBase; struct Library *DOSBase; struct Library *IFFParseBase; static UBYTE *IFFErrTxt[] = { "EOF", /* (end of file, not an error) */ "EOC", /* (end of context, not an error) */ "no lexical scope", "insufficient memory", "stream read error", "stream write error", "stream seek error", "file corrupt", "IFF syntax error", "not an IFF file", "required call-back hook missing", NULL, /* (return to client, never shown) */ }; LONG main(void) { struct RDArgs *readargs; LONG rargs[2]; struct IFFHandle *iffhandle; struct ContextNode *cnode; struct StoredProperty *hdrsp; struct StoredProperty *sp; UBYTE *filename; LONG ifferror, error = 0, rc = RETURN_OK; /* We must set up SysBase (we are not linked with startup code) */ SysBase = (*((struct Library **) 4)); /* This no-startup-code example may not be used from Workbench */ if ((((struct Process *)FindTask(NULL))->pr_CLI)==NULL) return(RETURN_FAIL); if (DOSBase = OpenLibrary("dos.library", 33)) { if (IFFParseBase = OpenLibrary ("iffparse.library", 36)) { if (readargs = ReadArgs("FILE/A", rargs, NULL)) { /* Test later if valid */ filename = (UBYTE *)rargs[0]; /* allocate an IFF handle */ if (iffhandle = AllocIFF()) { /* Open the file for reading */ if (iffhandle->iff_Stream = (LONG)Open(filename, MODE_OLDFILE)) { /* initialize the iff handle */ InitIFFasDOS (iffhandle); if ((ifferror = OpenIFF (iffhandle, IFFF_READ)) == 0) { PropChunk(iffhandle, ID_PREF, ID_PRHD); PropChunk(iffhandle, ID_PREF, ID_FONT); PropChunk(iffhandle, ID_PREF, ID_ICTL); PropChunk(iffhandle, ID_PREF, ID_INPT); PropChunk(iffhandle, ID_PREF, ID_OSCN); PropChunk(iffhandle, ID_PREF, ID_PGFX); PropChunk(iffhandle, ID_PREF, ID_PTXT); PropChunk(iffhandle, ID_PREF, ID_SCRM); PropChunk(iffhandle, ID_PREF, ID_SERL); for (;;) { ifferror = ParseIFF(iffhandle, IFFPARSE_STEP); if (ifferror == IFFERR_EOC) continue; else if (ifferror) break; /* Do nothing is this is a PrefHeader chunk, * we'll pop it later when there is a pref * chunk. */ if (cnode = CurrentChunk(iffhandle)) if (cnode->cn_ID == ID_PRHD || cnode->cn_ID == ID_FORM) continue; /* Get the preferences header, stored previously */ hdrsp = FindProp(iffhandle, ID_PREF, ID_PRHD); if (sp = FindProp(iffhandle, ID_PREF, ID_FONT)) { Printf("FrontPen: %ld\n", ((struct FontPrefs *)sp->sp_Data)->fp_FrontPen); Printf("BackPen: %ld\n", ((struct FontPrefs *)sp->sp_Data)->fp_BackPen); Printf("DrawMode: %ld\n", ((struct FontPrefs *)sp->sp_Data)->fp_DrawMode); Printf("Font: %s\n", (LONG)((struct FontPrefs *)sp->sp_Data)->fp_Name); Printf("ta_YSize: %ld\n", ((struct FontPrefs *)sp->sp_Data)->fp_TextAttr.ta_YSize); Printf("ta_Style: %ld\n", ((struct FontPrefs *)sp->sp_Data)->fp_TextAttr.ta_Style); Printf("ta_Flags: %ld\n", ((struct FontPrefs *)sp->sp_Data)->fp_TextAttr.ta_Flags); } else if (sp = FindProp(iffhandle, ID_PREF, ID_ICTL)) { Printf("TimeOut: %ld\n", ((struct IControlPrefs *)sp->sp_Data)->ic_TimeOut); Printf("MetaDrag: %ld\n", ((struct IControlPrefs *)sp->sp_Data)->ic_MetaDrag); Printf("WBtoFront: %ld\n", ((struct IControlPrefs *)sp->sp_Data)->ic_WBtoFront); Printf("FrontToBack: %ld\n", ((struct IControlPrefs *)sp->sp_Data)->ic_FrontToBack); Printf("ReqTrue: %ld\n", ((struct IControlPrefs *)sp->sp_Data)->ic_ReqTrue); Printf("ReqFalse: %ld\n", ((struct IControlPrefs *)sp->sp_Data)->ic_ReqFalse); /* etc */ } else if (sp = FindProp(iffhandle, ID_PREF, ID_INPT)) { Printf("PointerTicks: %ld\n", ((struct InputPrefs *)sp->sp_Data)->ip_PointerTicks); Printf("DoubleClick/Secs: %ld\n", ((struct InputPrefs *)sp->sp_Data)->ip_DoubleClick.tv_secs); Printf("DoubleClick/Micro: %ld\n", ((struct InputPrefs *)sp->sp_Data)->ip_DoubleClick.tv_micro); /* etc */ } else if (sp = FindProp(iffhandle, ID_PREF, ID_OSCN)) { Printf("DisplayID: 0x%lx\n", ((struct OverscanPrefs *)sp->sp_Data)->os_DisplayID); /* etc */ } else if (sp = FindProp(iffhandle, ID_PREF, ID_PGFX)) { Printf("Aspect: %ld\n", ((struct PrinterGfxPrefs *)sp->sp_Data)->pg_Aspect); /* etc */ } else if (sp = FindProp(iffhandle, ID_PREF, ID_PTXT)) { Printf("Driver: %s\n", (LONG)((struct PrinterTxtPrefs *)sp->sp_Data)->pt_Driver); /* etc */ } else if (sp = FindProp(iffhandle, ID_PREF, ID_SCRM)) { Printf("DisplayID: 0x%lx\n", ((struct ScreenModePrefs *)sp->sp_Data)->sm_DisplayID); /* etc */ } else if (sp = FindProp(iffhandle, ID_PREF, ID_SERL)) { Printf("BaudRate: %ld\n", ((struct SerialPrefs *)sp->sp_Data)->sp_BaudRate); /* etc */ } } CloseIFF(iffhandle); } if (ifferror != IFFERR_EOF) { rargs[1] = (LONG)IFFErrTxt[-ifferror - 1]; VFPrintf(Output(), "%s: %s\n", rargs); rc = RETURN_FAIL; } Close(iffhandle->iff_Stream); } else error = IoErr(); FreeIFF(iffhandle); } else { VFPrintf(Output(), "Can't allocate IFF handle\n", NULL); rc = RETURN_FAIL; } FreeArgs(readargs); } else error = IoErr(); CloseLibrary(IFFParseBase); SetIoErr(error); if (error) { rc = RETURN_FAIL; PrintFault(error, filename); } } else { rc = RETURN_FAIL; Write(Output(), "Kickstart 2.0 required\n", 23); } CloseLibrary(DOSBase); } return(rc); }
Preferences in 1.3 and Older Versions of the OS
In 1.3, the Preferences program allows the user to see and change many system wide parameters, like the Workbench colors, pointer image, printer settings etc. When a Preferences item is changed, the new setting can be used temporarily (until a reset occurs) or stored permanently in the "devs:system-configuration" file. Under 1.3, all Preferences items are stored in this file which the system reads at boot time to find out how to set various system-wide options.
struct Preferences *GetPrefs(struct Preferences *preferences, LONG size); struct Preferences *GetDefPrefs(struct Preferences *preferences, LONG size); struct Preferences *SetPrefs( struct Preferences *preferences, LONG size, BOOL inform );
None of these functions should be used in any new programs. They are only present for backwards compatibility.
Function Reference
The following are brief descriptions of the system functions that relate to the use of Preferences. See the SDK for details on each function call.
Function | Description |
---|---|
GetPrefs() | Old 1.3 (V34) function for making a copy of the Preferences structure |
SetPrefs() | Old 1.3 (V34) function for overwriting Preferences with new data |
GetDefPrefs() | Old 1.3 (V34) function for copying default Preferences from ROM |
StartNotify() | Release 2 DOS library function for monitoring a .prefs file for changes |
EndNotify() | Ends notification started with StartNotify() |
AllocIFF() | IFFParse library function that creates an IFFHandle for parsing |
InitIFFasDOS() | Initialize the IFFHandle as a DOS stream |
OpenIFF() | Initialize an IFFHandle for reading or writing a new stream |
PropChunk() | Specify a property chunk to store |
ParseIFF() | Parse an IFF file from the IFFHandle stream |
CurrentChunk() | Returns the top level context of an IFF stream |
FindProp() | Search for a property chunk previously declared with PropChunk() |
CloseIFF() | Closes an IFF context opened with OpenIFF() |
FreeIFF() | Frees the IFFHandle created with AllocIFF() |