XControl - Extensible Control Panel for TT/MEGA/ST Computers PRELIMINARY SPECIFICATION - SUBJECT TO CHANGE WITHOUT NOTICE This document is Copyright (C) 1990, Atari Corporation 890814 kbad First Draft 890816 kbad rev 1 - xform_do() spec, set-only CPXs 890817 kbad rev 2 - CPX file format 891220 kbad major rewrite, incorporating the latest CPX concepts 900109 kbad Corrected XControl window size, changes to XCPB and CPXINFO structs, added cpx_wmove() OVERVIEW This document describes a new Control Panel (XControl) for TT/MEGA/ST computers, which features loadable Control Panel extensions (CPXs) that perform various system configuration functions. XControl, with its loadable modules, gives the Control Panel the advantages of any software with modular design: ease of maintenance and expandability. Improvements to any part of XControl can be distributed individually, by distributing CPX updates, without the need for updating all parts of XControl. This scheme is more flexible for users, since XControl will only load the CPXs which a user needs. Software vendors can create and distribute their own CPXs to extend the functionality of XControl beyond what Atari provides, or to provide graphical front ends for their TSR utilities. HOW XCONTROL WORKS XControl is a combination of a master desk accessory, which loads the various CPXs and manages user selection of CPXs, and the extensions themselves, which perform the various system configuration tasks. When XControl is loaded, at boot time or on a resolution change, it looks for a folder called XCONTROL in the root of the boot device. If it finds the folder, it will read the header of each .CPX file it finds there. If the header indicates that a .CPX needs to be run at boot time, XControl will load the CPX and call its initialization hook. If the CPX header also indicates that the user prefers it to be memory resident, XControl will keep the CPX in memory. After checking CPXs and initializing those that need it, XControl waits like any other desk accessory for an AC_OPEN message. When selected from the Desk menu, XControl checks the XCONTROL folder again, to see if any CPXs have been added or removed since it was last invoked. New CPXs will be initialized as required. XControl then displays menu of loaded extensions. When a CPX is chosen from the main XControl menu, that CPX is loaded from the XCONTROL directory, and invoked via the XControl <-> CPX software interface described below. Basically, the CPX gets control of the work area of the XControl window, and can present its own interface there. XControl dispatches user events through the CPX, but handles most window related events itself. XControl also provides a number of utility routines to CPXs, including an extended form_do call which CPXs can use to handle simple dialog-style interfaces within the XControl window. It's expected that most CPXs will use this simple extended form_do() software interface so that the user can move or close the XControl window at will. Each CPX will provide at least an OK and Cancel button so that the user can return to the XControl master from the CPX. Each CPX must also be able to respond to an Abort signal from XControl, so that the user can dismiss XControl with the close box, and so that XControl can clean up if it is active while the main application is terminated. When the user exits a CPX back to XControl, the CPX is unloaded, and the memory it took up is recovered. CONTROL PANEL EXTENSIONS The concept of what constitues a CPX is very important to the implementation of the extensible Control Panel. A CPX is effectively a subroutine call. It is neither an application nor a desk accessory, but only a means for setting system parameters. Examples of CPX functions include: - Color selection - Keyboard/mouse configuration (repeat rate, audible keyclick, etc.) - RS232 port configuration - Printer configuration - Printer driver configuraton - Setting screen saver defaults Note the key word "configuration" in most of the above functions. A printer driver does not belong in a CPX, but the ability to configure a TSR printer driver would be a good thing to have in a CPX. The key concept to keep in mind here is that of the "Control Panel" - the one place where a user goes to toggle switches, press buttons, or whatever, to "control" the functions of the computer. Obviously, it is silly to have a CPX which controls the operation of a desk accessory. Instead, CPXs should primarily be used as graphical front ends for TSR utilities. XCONTROL <-> CPX SOFTWARE INTERFACE When XControl first starts up, it loads the headers of all the CPXs it can find. At boot time, it initializes each CPX which has the bootinit flag set in its header by jsr'ing to the start of the CPX's text segment. The cpx_init() function described below must be located at the start of the text segment. This function returns a pointer to a structure containing information about the CPX, including pointers to the calls it will use for further XControl interaction. "Set-only" CPXs may be implemented, they should set whatever is needed during the cpx_init() call and return NULL. If a CPX is set for bootinit, XControl will also check the setonly flag in the header to determine if the CPX is Set-only. XControl will only execute Set-only CPXs at boot time. They will not appear on the XControl main menu, and thus will never again be called after the cpx_init() call. [Does this make sense? The idea is that Set-only's don't get run] [every time you bring up XControl. So, you can't execute a Set-only] [just by copying it into your XCONTROL folder.. you must reboot] XControl uses an evnt_multi() for its user interaction. When a CPX is chosen by the user, XControl loads the CPX into memory, and calls cpx_init() with the `booting' paramter set to FALSE. XControl then invokes the cpx_call() routine to begin CPX interaction. This routine should first initialize the CPX interface. It may then handle the user interface via the extended form_do call (described below) and return FALSE, or return TRUE to allow XControl to manage the user interface by dispatching evnt_multi() events through the CPX event handling routines. XCONTROL ROUTINES XControl makes a custom form handler available to CPXs, so that they may use the standard AES forms interface, in a window, without worrying about handling window messages. The name of the routine is xform_do, and it functions exactly like the built-in AES form_do routine: int xform_do( OBJECT tree[], int startob ); Parameters and returns are as documented for the AES form_do call. The object tree should fit within the standard control panel window (256x160 pixels work area). This restriction may be lifted in a future version. A pointer to the xform_do routine is passed to a CPX when it is invoked from the XControl manager with the cpx_call() routine described below. More flexible user interfaces may be implemented by having XControl dispatch events from its evnt_multi() through a CPX when it is activated, but usually the xform_do() call will suffice. XControl also allows a CPX to save configuration information into its file. Normally, a CPX will have its default configuration located somewhere in its data segment. The cpx_save() call allows a CPX to write configuration data directly into its file, regardless of the name the user may have given it: void cpx_save( void *buf, long len, long file_offset ); XControl will handle disk errors and retries. Other XControl routines will be avaliable to CPXs as well, including resource fixup, AES utility routines, and string handling functions. [details later...] CPX ROUTINES Initialization CPXINFO *cpx_init( XCPB *xcpb ); This routine is called as soon as a CPX is loaded by XControl, and should be used by the CPX to initialize global variables, etc. This call must be the first routine in the text segment of a CPX. XControl passes on the stack a pointer to an XControl Parameter Block, with information of interest to the CPX. The XCPB struct looks like: typedef struct { unsigned cpx_version; /* hi byte major, low byte minor # */ short vdi_handle; /* from XControl's v_opnvwk() */ short booting; /* nonzero if this cpx_init() call is * part of XControl's initialization * (i.e. bootup or res change) */ short reserved; /* utility routines... */ short (*xform_do)( OBJECT tree[], short startob ); void (*rsh_fix)( void ); void (*cpx_save)( void *buf, long len, long file_offset ); short (*sl_x)( short base, short value, short min, short max ); short (*sl_arrow)( short base, short obj, short inc, short min, short max, short *numvar ); void (*sl_drag)( short base, short min, short max, short *numvar ); short (*mn_popup)( /* interface TBD */ ); /* etc... TBD */ } XCPB; cpx_init() returns a pointer to the following structure, or NULL if it is a "set-only" CPX: typedef struct { char cpx_title[]; /* Window title of CPX */ unsigned cpx_evmask; /* Wait mask for CPX evnt_multi */ /* Required for all CPXs: */ BOOLEAN (*cpx_call)( GRECT *work ); /* Optional interface routines, described below: */ void (*cpx_draw)( GRECT *clip ); void (*cpx_wmove)( GRECT *work ); BOOLEAN (*cpx_evhook)( int event, int *msg, MRETS *mrets, int *key, int *nclicks ); void (*cpx_timer)( int *event ); void (*cpx_key)( int kstate, int key, int *event ); void (*cpx_button)( MRETS *mrets, int nclicks, int *event ); void (*cpx_m1)( MRETS *mrets, int *event ); void (*cpx_m2)( MRETS *mrets, int *event ); } CPXINFO; Unused optional routines in the CPXINFO structure should be set to NULL. Invocation BOOLEAN cpx_call( GRECT *work ); Called when a CPX is first activated. The function is passed a rectangle describing the current work area of the XControl window. This allows a CPX to set up for user interaction, and optionally call the custom form_do routine to handle its user interface. cpx_call() should return FALSE if it is done (if it has used xform_do for its user interface), or TRUE to continue (if it wants XControl to continue dispatching events via the routines described below). Window management void cpx_draw( GRECT *clip ); Called when a CPX is active and the XControl window needs to be redrawn. This routine is required for all CPXs which use XControl to dispatch events. void cpx_wmove( GRECT *work ); Called when the user moves the XControl window, so that the CPX may fix up its object tree as necessary. Event Preemption Hook BOOLEAN cpx_evhook( int event, int *msg, MRETS *mrets, int *key, int *nclicks ); Hook called immediately after evnt_multi returns, BEFORE the event is handled by XControl. This routine should return TRUE (nonzero) to override default event handling, or FALSE (zero) to continue with event handling. This routine should not normally be required by a CPX, but is included for flexibility. Event Handling Functions While a CPX is active, these are called in response to the appropriate events. The contents of the `cpx_evmask' word in the CPXINFO structure determines what events will be returned by evnt_multi(). The event mask may be changed at any time while a CPX is active, and the new mask will be used for the next evnt_multi. Note that the routines are listed in the same order they will be called for multiple event returns from evnt_multi(). These routines should set the word pointed to by `event' to FALSE (zero) to return control to XControl and its main menu, or leave that word alone to continue with CPX interaction. Event Function ---------- --------------------------------------------------------- MU_TIMER void cpx_timer( int *event ); MU_KEYBD void cpx_key( int kstate, int key, int *event ); MU_BUTTON void cpx_button( MRETS *mrets, int nclicks, int *event ); MU_M1 void cpx_m1( MRETS *mrets, int *event ); MU_M2 void cpx_m2( MRETS *mrets, int *event ); Message events are handled by XControl, unless intercepted by cpx_evhook() as described above. CPX FILE FORMAT A CPX file header looks like: typedef struct { unsigned magic; /* magic number 0x???? */ struct { unsigned reserved : 30; unsigned resident : 1; unsigned bootinit : 1; } flags; long cpx_id; /* unique cpx identifier */ unsigned cpx_version; /* version of this cpx */ char i_text[14]; /* 12 characters icon text */ unsigned sm_icon[8*4]; unsigned lg_icon[16*4]; char reserved[300]; } CPXHEAD; /* sizeof(CPXHEAD) = 512 bytes */ The user can set the `resident' flag and the icon text via XControl. The rest of the CPX file has the same format as a GEMDOS executable file. A program will be provided to set up and prepend the header to the CPX executable. The executable part does not need to be completely relocatable, as XControl will perform whatever relocation is necessary when it loads the CPX. The first routine in the text segment of the object file must be the cpx_init() routine described above. The resource for the CPX file must be built into the file, and should be fixed up in place using the rsh_fix() facility of XControl.