Programmierung von CPX-Modulen

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.

Wie funktioniert CPX?

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.

Modul-Aufbau

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.

CPX-Programmierung

Bei der Entwicklung eigener Module sollte man einige Programmierrichtlinien beachten:

XControl-Funktionen

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.

Modul-Funktionen

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 (8
8)
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



Links

Copyright-Bestimmungen: siehe Über diese Seite
Classic Computer Magazines
[ Join Now | Ring Hub | Random | << Prev | Next >> ]