Neben der Überarbeitung der Hardware und des Betriebssystem hat ATARI den STE- und TT-Rechnern auch ein neues Kontrollfeld spendiert. Es ist modular aufgebaut und kann somit auch vom Anwender erweitert werden.
Zusammen mit dem Steuerprogramm XControl, welches für die Verwaltung der einzelnen Module zuständig ist und Funktionen zur Verfügung stellt, werden von ATARI bereits Module zur Rechnerkonfiguration mitgeliefert. Das modulare Kontrollfeld kann auch auf den alten ST-Modellen verwendet werden; ATARI gibt dafür allerdings keine 100% Funktionsgarantie.
Das Kontrollfeld und die zusätzlichen Module (bis zu 99 können von XControl verwaltet werden) dienen ausschließlich der Konfiguration des Rechners, von Programmen (z.B. Mausbeschleuniger) und Zusatz-Hardware (z.B. Grafikkarten) und sollten auch zu keinem anderen Zweck verwendet werden.
Nach dem Start des Rechners wird XControl geladen. Dieses sucht im CPX-Verzeichnis nach aktiven CPX(Control Panel eXtension)Modulen und lädt deren Header ein. Eventuell wird anschließend eine Initialisierungsroutine aufgerufen, die jedem Modul die Möglichkeit zur Konfiguration gibt. Danach wartet XControl, wie jedes Accessory, auf seine Aktivierung durch Anwahl in der Menüzeile. Wird ein Modul durch Auswählen in XControl aktiviert, wird zuerst seine Initialisierungroutine eine zweiten Mal aufgerufen. Hierbei müssen globale Variablen initialisiert werden. Darunter fallen auch sämtliche Resource-Informationen, da diese im Modul enthalten sein müssen [ein späteres Laden mittels rsrcjoadf) ist, durch die damit verbundene Zerstörung der Resource-Daten des momentan aktiven (Haupt-) Programms, nicht möglich]. Anschließend übergibt XConrol die Kontrolle an das Modul durch Aufruf seiner Hauptroutine.
Wie der obigen Beschreibung entnommen werden kann, unterscheidet sich der Aufbau eines Moduls von dem eines normalen Programms. Bei einer Modul-Datei befinden sich an erster Stelle der CPX-Header, 512 Bytes lang (Aufbau siehe Bild 1). Danach folgen der GEMDOS-Programmheader, das Text- und Daten-Segment sowie Relozierungsinformationen. Der CPX-Header enthält wichtige Information über das Modul, die von XControl benötigt werden. Neben den Informationen über die Darstellung innerhalb des Kontrollfeldes befinden sich auch Daten über die Art des Moduls darin. Ein Flag zeigt z.B. an, ob das Modul resident im Speicher gehalten werden soll (dann wird bei der Initialisierung nicht nurder Header, sondern das ganze Modul in den Speicher geladen!) oder nicht. Wenn es sich um ein Set-Only-Modul handelt (es werden nur bei der Initialisierung Daten an eine Hardware oder ein Programm übergeben und das Modul danach nicht mehr aufgerufen) oder bei der Initialisierung die Routine des Moduls nicht mit aufgerufen werden soll, findet XControl diese Informationen innerhalb des Headers. Dieser Header muß für jedes .'o-dul erzeugt werden. Von ATARI können eingetragene Entwickler ein Tool zur Erzeugung des Headers beziehen. Auf den Disketten zum Heft befindet sich ein von Uwe Hax und Oliver Scholz entwickelter Header-Generator.
Bei der Entwicklung eigener Module sollte man einige Programmierrichtlinien beachten:
Bei den vom Kontrollfeld zur Verfügung gestellten Funktionen handelt es sich um Routinen zur Objektanpassung (rsh_...), zur Bearbeitung von Pop-Up-Menüs (Popup), zur einfachen Slider-Bearbeitung (Sl_...), zur Formular- und Dialog-Verwaltung (Xform_do ,XGen_A\ert, Set_Evnt_Mask, Gef...Reef, MFsave, CPX_Save), zur Zwischenspeicherbearbeitung (GefJ3uffer) und zur Cookie-Jar Abfrage (gefcook/e). Durch Ausnutzung dieser Routine erhält der Programmierer die Möglichkeit kompakte Module zu entwickeln. Besonders die Funktionen zur Slider- und Pop-Up-Menü-Verarbeitung sind sehr hilfreich. Letztere übernimmt z.B. die komplette Abwicklung von Pop-Ups. Sie wird nach Anwahl des Pop-Up-erzeugenden Buttons mit einer Liste der Menüeinträge aufgerufen. Sie verwalten nun vollständig die Selektion eines Eintrags. Bei mehr als 5 Einträgen wird der erste und letzte durch Pfeile ersetzt, und die Liste kann gescrollt werden.
Die Modul-Initialisierungs-Routine (siehe Tabelle 2) muß, wie oben bereits erwähnt, einen Zeiger auf eine Liste der moduleigenen Routinen zurückliefern. Da XControl nicht bekannt ist, wo die einzelnen Routinen eines Moduls sich befinden (abgesehen von der Initialisierungs-Routine, die direkt am Anfang des Text-Segments stehen muß), kann es nur über diese Liste auf die Routinezugreifen. Die vom CPX-Modul zur Verfügung zu stellenden Routinen können Tabelle 3 entnommen werden. Es handelt sich dabei um Reaktions-Routinen, die dann aufgerufen werden, wenn eine Operation des Moduls notwendig wird. Ein recht praktischer Umstand von XControl, der bei der Entwicklung von neuen CPX-Modulen wirksam wird, ist die Tatsache, daß man XControl auch als Programm starten kann. Dazu muß es von XCONTROL.ACC in XCONTROL.APP umbenannt werden. Nun können Module ausgetestet werden, ohne jedes Mal einen Reset ausführen zu müssen.
Aufruf: rsh_fix(num_objs, num_frst, num_frimg, num_tree, rs_object, rs_tedinfo, rs_string(), rs_iconblk, rs_bitblk, rs_frstr, rs_frimg, rs_trindex, rs_imdope)
Funktion: Umwandlung der Koordinatendarstellung eines Objektbaums von Zeichen- in Pixel-Darstellung auf der Basis von 8*16 Pixel großen Zeichen.
Parameter: num..: die entsprechenden Konstanten aus *.RSH (wird vom RCS angelegt)
rs_...: Zeiger auf die gleichnamigen Strukturen aus *.RSH
Rückgabe: keine
Aufruf: rsh_obfix(tree, curob)
Funktion: Umwandlung der Koordinatendarstellung eines Objekts von Zeichen- in Pixel-Darstellung auf der Basis von 8*16 Pixel großen Zeichen [entspricht rsrc_obfix()]
Parameter: tree: Zeiger auf umzuwandelnden Objektbaum
curob: Nummer des zu konvertierenden Objekts
Rückgabe: keine
Aufruf: Popup(items[], num_items, default_item, font_size, button, world)
Funktion: Automatische Verwaltung eines Pop-Up-Menüs. Bei mehr als 5 Einträgen wird selbständig gescrollt.
Parameter: items(): Zeiger auf Liste der Menüeinträge.
Alle Einträge müssen gleich lang sein. Außerdem sollten jedem Eintrag zwei Leerzeichen voran- (für Haken) und ein Leerzeichen nachgestellt werden,
num_items: Anzahl der Menüeinträge
default_item: Nummer des vorgewählten (abgehakten) Eintrags (Zählung beginnt mit 0; bei -1 wird kein Eintrag vorgewählt).
font_size: Auswahl der Zeichengröße:
3: groß (816)
5: klein (88)
button: Zeiger auf Rechteckstruktur GRECT) des Pop-Up-Menü-Buttons
world: Zeiger auf Rechteckstruktur des CPX
Rückgabe: angeklickter Eintrag; -1, wenn keiner angewählt wurde
Aufruf: Sl_size(tree, base, slider, num_items, visible, direction, min_size)
Funktion: berechnet Größe des darzustellenden Sliders im Verhältnis zur Gesamtzahl der Listeneinträge
Parameter: tree: Zeiger auf Objektbaum
base: Nummer des Slider-Hintergrundobjekts
slider: Nummer des Slider-Objekts (Child von base)
num_items: Gesamtanzahl der Listeneinträge
visible: Anzahl der darstellbaren Einträge
direction: Richtung:
0: vertikal
1: horizontal
min_size: minimale Pixel-Größe des Sliders
Rückgabe: keine
Aufruf: Sl_x(tree, base, slider, value, min, max, foo)
Sl_y(tree, base, slider, value, min, max, foo)
Funktion: Positionierung des Sliders
Parameter: tree: Zeiger auf Objektbaum
base:Nummer des Slider-Hintergrundobjekts
slider: Nummer des Slider-Objekts (Child von base)
value: neuer Wert für Slider(-Position)
min: minimaler Wert
max: maximaler Wert
foo: Zeiger auf eine Funktion, die bei der Slider-Neupositionierung mit aufgerufen wird
Rückgabe: keine
Aufruf: Sl_arrow(tree, base, slider, obj, inc, min, max, value, direction, foo)
Funktion: bearbeiten die Pfeil, bzw. Hintergrundanwahl innerhalb der Slider-Bearbeitung
Parameter: tree: Zeiger auf Objektbaum
base: Nummer des Slider-Hintergrundobjekts
slider: Nummer des Slider-Objekts (Child von base)
obj: Nummer des angewählten Objekts (Pfeil, Hintergrund)
inc: Anzahl der zu blätternden Listeneinträge
min: minimaler Wert max: maximaler Wert
value: Adressen für aktuellen Wert
direction: Richtung:
0: vertikal
1: horizontal
foo: Zeiger auf eine Funktion, die bei der Slider-Neupositionierung mit aufgerufen wird
Rückgabe: keine
typedef struct
{
WORD magic /* CPX-Kennung = 100 */
struct
{
unsigned reserved: 13; /* reserviert */
unsigned resident: 1;/* Modul ist resident */
unsigned booting: 1; /* Boot-Initialisierung */
unsigned setonly: 1; /* Set-Only-Modul */
} flags;
LONG cpx_id; /* eindeutige CPX-ID (4 ASCII-Zeichen) */
WORD cpx_version; /* CPX-Versionsnummer */
char i_text[14]; /* Icon-Name */
WORD sm_icon[48]; /* Icon-Bitmap (32*24 Pixel) */
WORD i_color; /* Icon-Farbe */
char title_text[18];/* Texte neben Icon */
WORD t_color: /* Textfarbe */
char buffer[64]; /* nicht flüchtiger Speicher */
char reserved[306]; /* reserviert */
} CPXHEAD;
Bild 1: Struktur des CPX-Headers
typedef struct
{
WORD handle; /* von graf_handle()-Aufruf */
WORD booting; /* Boot-Initialisierung */
WORD reserved; /* reserviert */
void *reserve1; /* reserviert */
void *reserve2; /* reserviert */
...
/* Definition der von XContol bereitgestellten Funktionen */
...
WORD Country_Code; /* Länderkennung */
} XCPB;
Bild 2: Aufbau der XCPB-Struktur
Aufruf: Sl_dragx(tree, base, slider, min, max, value, foo)
Sl_dragy(tree, base, slider, min, max, value, foo)
Funktion: Verwaltung des Verschiebens eines Sliders bei gedrückter Maustaste
Parameter: tree: Zeiger auf Objektbaum
base: Nummer des Slider-Hintergrundobjekts
slider: Nummer des Slider-Objekts (Child von base)
min: minimaler Wert
max: maximaler Wert value: Adressen für aktuellen Wert
foo: Zeiger auf eine Funktion, die bei der Slider-Neupositionierung mit aufgerufen wird
Rückgabe: keine
Aufruf: Xform_do(tree, startob,puntmsg)
Funktion: Formular-Verwaltung [ähnlich form_do()]
Parameter: tree: Zeiger auf zu verwaltenden Obkjektbaum
startob: Startobjekt
puntmsg: Zeiger auf Mitteilungspuffer
Rückgabe: Nummer des angeklickten Objekts; bei -1 enthält puntmsg eine der folgenden vier Mitteilungen:
WM_REDRAW(20): Objekte, die nicht zum Objektbaum gehören (und deshalb nicht automatisch neugezeichnet werden), müssen selbst erneuert werden [die dazu notwendige Rechteckliste liefern die Funktionen GetFirstRect() und GetNextRect(); siehe unten]
WM_CLOSE(22): Das Modul wurde mit OK beendet.
AC_CLOSE(41): Das Modul wurde mit Abbruch beendet.
CT_KEY(53): Die Tasten HELP, UNDO oder eine Funktionstaste wurden gedrückt (High-Byte von puntmsg[3] enthält Scan- und Low-Byte ASCII-Code).
Aufruf: GetFirstRect(prect)
Funktion: liefert erstes Element der Rechteckliste des neuzuzeichnenden Bereichs
Parameter: prect: Zeiger auf Rechteckstruktur (GRECT) des zu aktualisierenden Bereichs
Rückgabe: Zeiger auf Rechteckstruktur des zu restaurierenden Bereichs; NULL: kein Bereich vorhanden
Aufruf: GetNextRect(prect)
Funktion: liefert nächstes Element der Rechteckliste des neuzuzeichnenden Bereichs
Parameter: keine
Rückgabe: Zeiger auf Rechteckstruktur des zu restaurierenden Bereichs; NULL: keine weiteren Bereiche vorhanden
Aufruf: Set_Evnt_Mask(mask, ml, m2, time)
Funktion: bestimmt, auf welche Events ein Event-CPX reagieren soll
Parameter: mask: Events [wie evnt_multi()]
m1, m2: Zeiger auf Struktur, die Mausrechteck und -richtung für Event angibt time: Zeit (Millisekunden) für Timer-Event [damit keine Programme blockiert werden (das CPX-Modul läuft zusätzlich zu einem anderen Programm (oder zum Desktop), erfolgt spätestens nach 30 Sekunden ein Timerevent]
Rückgabe: keine
Aufruf: XGen_Alert(id)
Funktion: Erzeugt vordefinierte Alarmboxen; weitere müssen selbst erzeugt werden. [form_alert() ist dazu nicht sinnvoll, da damit erzeugte Alarmboxen bezüglich des Bildschirms und nicht der CPX-Box zentriert werden],
Parameter: id: Nummer der darzustellenden Alarmbox:
0: SAVE_DEFAULTS (Voreinstellungen sichern?)
1: MEM_ERR (Fehler bei Speicheranforderung!)
2: FILE_ERR (Fehler beim Schreiben/Lesen von Datei!)
3: FILE_NOT_FOUND (Datei nicht gefunden!)
Rückgabe: 0: Abbruch wurde angewählt; sonst wurde OK angeklickt
Aufruf: CPX_Save(ptr, num)
Funktion: Default-Parameter werden in das DATE-Segment des aktuellen CPX gespeichert
Parameter: ptr: Zeiger auf die zu speichernden Daten
num: Byte-Anzahl der zu speichernden Daten
Rückgabe: 0: ein Fehler ist aufgetreten; sonst: alles ok
Aufruf: Get_Buffer()
Funktion: ermittelt Zeiger auf einen 64 Byte großen CPXeigenen Speicherbereich
Parameter: keine
Rückgabe: Zeiger auf Speicherbereich
Aufruf: getcookie(cookie, p_value)
Funktion: sucht nach gewünschtem Cookie und liefert, sofern vorhanden, seinen Wert
Parameter: cookie: Cookie-ID (vier ASCII-Zeichen)
p_value: Zeiger zur Ablage des Cookie-Wertes
Rückgabe: 0: Cookie nicht gefunden; sonst: Cookie gefunden
Aufruf: MFsave(saveit, mf)
Funktion: Form des Mauszeigers kann zwischengespeichert und wieder hergestellt werden
Parameter: saveit: bestimmt Operationsart:
0: MFRESTORE (Mausform restaurieren)
1: MFSAVE (Mausform Zwischenspeichern)
mf: Zeiger auf einen Speicherbereich zur Ablage der Mauszeigerdaten
Rückgabe: keine
Tabelle 1: Liste der von XControl bereitgestellten Funktionen
Aufruf: cpx_init(xcpb)
Funktion: Funktion muß die erste im Modul sein. Sie wird von XControl zur Initialisierung aufgerufen.
Parameter: xcpb: Zeiger auf XCPB-Struktur (wird dem Modul geliefert!)
Rückgabe: Zeiger auf die CPXINFO-Struktur, oder NULL, wenn Set-Only-Modul (liefert das Modul zurück!)
Tabelle 2: Initialisierungs-Funktion der CPX-Module
Aufruf: cpx_call(word)
Funktion: Hauptroutine; Aufruf von XControl nach Anwahl des Moduls
Parameter: word: Rechteckstruktur (GRECT) der Arbeitsfläche des XControl-Fensters
Rückgabe: 0: Ende der Bearbeitung; sonst: CPX soll weiterbearbeitet werden Nachfolgende Routinen werden nur von Event-CPX benötigt:
Aufruf: cpy_draw(clip)
Funktion: Aufruf bei einem Redraw
Parameter: clip: Zeiger auf Rechteckstruktur des neuzuzeichnenden Bereichs
Rückgabe: keine
Aufruf: cpx_wmove(work)
Funktion: XControl-Fenster wurde bewegt
Parameter: work: Zeiger auf Rechteckstruktur mit den neuen Fensterkoordinaten
Rückgabe: keine
Aufruf: cpx_timer(event)
Funktion: Aufruf bei Timerevent
Parameter: event: Zeiger auf Ausgabewert: 1: CPX soll verlassen werden
Rückgabe: keine
Aufruf: cpx_key(kstate, key, event)
Funktion: Aufruf bei Keyboardevent
Parameter: kstate: Status der Umschalttasten
key: gedrückte Taste (High-Byte: Scancode, Low-Byte: ASCII-Code)
event: Zeiger aus Ausgabewert: 1: CPX soll verlassen werden
Rückgabe: keine
Aufruf: cpx_button(mrets, nclicks, event)
Funktion: Aufruf bei Maustasten-Event
Parameter: mrets: Zeiger auf Mausparameter
nclicks: Anzahl der Maustastenklicks
event: Zeiger aus Ausgabewert: 1: CPX soll verlassen werden
Rückgabe: keine
Aufruf: cpy_m1 (mrets, event)
cpy_m2(mrets, event)
Funktion: Aufruf, wenn Mauszeiger bestimmte Rechtecke verläßt oder betritt
Parameter: mrets: Zeiger auf Mausparameter
event: Zeiger aus Ausgabewert: 1: CPX soll verlassen werden
Rückgabe: keine
Aufruf: cpx_hook(event, msg, mrets, key, nclicks)
Funktion: Aufruf direkt nach event_multi(), bevor XControl den Event bearbeitet
Parameter: event: aufgetretenes Ereignis
msg: Zeiger auf den Ereignispuffer
mrets: Zeiger auf Mausparameter key: Tastendruck
nclicks: Anzahl der Maustastenklicks
Rückgabe: bestimmt weitere Verarbeitungsweise:
0: Event-Verarbeitung fortsetzen
1: Event-Verarbeitung abbrechen
Aufruf: cpx_clos(flag)
Funktion: wird bei jeder AC_CLOSE- und WM_CLOSE-Mitteilung aufgerufen; das Modul muß sofort eventuell reservierten Speicher freigeben
Parameter: flag: Art der Mitteilung:
0: AC.CLOSE
sonst: WM_CLOSE
Rückgabe: keine
Tabelle 3: Liste der in CPXINFO aufgeführten Funktionen eines CPX-Moduls