Minimierung mit minimalem Aufwand
Wieder einmal ist eine CeBIT vorĂŒber. Wie erwartet, war zum Thema ATARI nicht viel zu entdecken (siehe Messebericht). Wer am Wochenende die Messe besuchte, dĂŒrfte aber das ganz und gar messeuntypische gute Wetter und das Vogelgezwitscher aus den E-PLus-Lautsprechern genossen haben. Und daĂ IBM, Apple und Motorola ganz allmĂ€hlich mit der PowerPC-Plattform ernstmachen (eigene Messehalle), wurde sicherlich auch gern vernommen.
PĂŒnktlich vor der CeBIT hatte Application Systems Heidelberg ĂŒberraschend angekĂŒndigt, daĂ MagiC 3 nun zunĂ€chst ohne Falcon-UnterstĂŒtzung auf den Markt kommen soll (nach der PrĂ€misse: besser jetzt erstmal fĂŒr STs und TTs als noch weiter aufschieben). Wie dem auch sei, da auch die MagiC-Mac-KĂ€ufer bereits eine Vorversion des MagiC-3-Kernels benutzen, wird es Zeit, auf neue Betriebssystemaufrufe einzugehen.
MagiC 3 und âIconifyâ
Es ist allgemein bekannt, daĂ die letzten Fassungen von ATARIs MultiTOS-AES bisher nur fĂŒr Entwickler zugĂ€nglich sind. Und es sieht nicht so aus, als wĂŒrde sich das in naher Zukunft Ă€ndern. Eines der âneuesten' Features war die sogenannte âIconificationâ, mittels derer man Fenster in minimaler GröĂe an den Bildschirmrand verbannen kann (bekannt und beliebt von den verschiedenen X-Window-Managern, Windows oder OS/2). MagiC 3 ist jedoch zu diesen Funktionen kompatibel, so daĂ eine Beschreibung der dafĂŒr notwendigen Funktionen nun angebracht ist. Achtung: auch diejenigen, die die Iconification bereits aus den MultiTOS-Entwicklerunterlagen kennen, werden hier noch etwas Neues entdecken können, denn einige sehr wichtige Erweiterungen waren von ATARI bisher nicht dokumentiert worden.
Zur Sache. Die Iconification-UnterstĂŒtzung durch das AES gliedert sich in folgende Teilbereiche:
(1) Darstellung eines neuen Schaltfeldes am Fensterrand (ein guter Grund, MagiC 3.x so zu konfigurieren, daà der Backdrop-Button nicht sichtbar ist, sondern statt dessen der gesamte Fenstertitel verwendet werden kann) und Verschicken einer dazugehörigen Nachricht
(2) Verwaltung freier Bildregionen fĂŒr iconifizierte Fenster (schlieĂlich sollen sie ja schön ordentlich nebeneinander stehen)
(3) Spezielle Behandlung iconifizierter Fenster (schmalerer Fenstertitel, Verschwinden der restlichen RĂ€nder usw.)
Welche Ănderungen ergeben sich dadurch fĂŒr Applikationen? Beginnen wir beim ersten Punkt: Ganz, wie von den anderen Fensterelementen gewohnt, setzt man auch hier einfach bei wind_create() ein zusĂ€tzliches Bit (SMALLER, 0x4000). Wenn der Benutzer das entsprechende Fensterelement anklickt, erhĂ€lt man entweder die GEM-Message WM_ICONIFY (dieses Fenster iconifizieren) oder WM_ALLICONIFY (alle Fenster der Applikation iconifizieren, mit CTRL-Taste). Dabei liefert das AES bereits ein Rechteck fĂŒr das iconifizierte Fenster mit (siehe Punkt 2). Im Moment werden die Fenster am unteren Bildrand von links nach rechts angeordnet, aber es ist sicherlich vorstellbar, daĂ Ort und Richtung eines Tages konfigurierbar sein werden.
Achtung: die GröĂe der iconifizierten Fenster ist zur Zeit immer gleich, aber auch dies könnte sich spĂ€ter mal Ă€ndern. Wer also einfach nur ein Icon hineinmalen will, sollte sich schon darum kĂŒmmern, unter UmstĂ€nden die RĂ€nder zu löschen und die Bitmap zu zentrieren!
Das so erhaltene Rechteck ĂŒbergibt man der neuen wind_set-Unterfunktion WF_ICONIFY, und das war es auch schon. Das AES sorgt automatisch fĂŒr den âUmbauâ der FensterrĂ€nder und merkt sich die bisherigen MaĂe des Fensters fĂŒr ein spĂ€teres WM_UNICONIFY-Event (das dann fast identisch behandelt wird).
Was das Programm mit dem Arbeitsbereich des âkleinenâ Fensters anfĂ€ngt, bleibt ganz dem Programmierer ĂŒberlassen. In der Regel wird man einfach ein festes Icon anzeigen, aber manchmal sind auch etwas aufwendigere Lösungen sinnvoll (etwa eine Analoguhr bei einem Kalenderprogramm, eine ProzeĂanzeige bei einem lĂ€ngeren Vorgang oder gar die miniaturisierte Fassung des Bildschirminhalts eines Terminalfensters). Die Abbildungen 1 und 2 zeigen Applikationen im minimierten Zustand (MultiTOS) und ein Fenster mit SMALLER-Schaltfeld (MagiC 3). Abbildung 3 zeigt Bindings fĂŒr diejenigen Funktionen, die von PureC nicht unterstĂŒtzt werden, sowie ein kleines StĂŒck Beispielcode.
SonderfÀlle
Im Gegensatz zu vielen anderen AES-Erweiterungen muĂ beim Iconify (zunĂ€chst) keine spezielle Abfrage auf AES-FĂ€higkeiten gemacht werden. Alle bekannten GEM-Versionen ertragen das Setzen des Smaller-Fensterelements ohne Murren. Und wenn das AES dann tatsĂ€chlich eine der Iconify-Messages schickt, kann man sich auch getrost darauf verlassen, daĂ das AES die anderen dafĂŒr benötigten wind_set-Opcodes kennt.
Soweit der Umfang des âursprĂŒnglichenâ Iconify-Verfahrens. Leider wurden beim Entwurf der Funktionen zwei AnwendungsfĂ€lle vergessen: Zum einen will man ein Fenster auch minimieren können, ohne daĂ der Benutzer dazu das entsprechende Fensterelement anwĂ€hlen mĂŒĂte (zum Beispiel, wenn es ĂŒber einen Tastatur-Shortcut gehen soll). Weiterhin sollte es auch möglich sein, ein Fenster bereits im iconifizierten Zustand zu öffnen (beispielsweise fĂŒr eine Applikation, die gleich als Icon starten soll).
FĂŒr diese FĂ€lle erlaubt MultiTOS auch eine etwas andere Vorgehensweise, die allerdings bislang nicht dokumentiert war. Eric Smith hat freundlicherweise sein EinverstĂ€ndnis gegeben, diese Informationen zu veröffentlichen.
Die erste wichtige Erweiterung ist, daĂ auch ein Fenster, das zwar erzeugt, aber noch gar nicht geöffnet worden ist, iconifiziert werden kann. Dazu ĂŒbergibt man einfach als Rechteck (-1, -1, -1, -1).
Schritt Nummer zwei: um dieses iconifizierte Fenster mittels wind_open() auf den Bildschirm zu bringen, ist wiederum eine Koordinatenangabe notwendig. Auch in diesem Fall darf (-1, -1, -1, -1) angegeben werden.
Leider bleiben ein paar Fragen offen, so daà der Programmierer dazu gezwungen ist, einige Entscheidungen nach eigenem Ermessen zu fÀllen. Einige Beispiele:
(1) Was tun, wenn das AES WM_ALLICONIFY meldet, aber bereits eines der Fenster der Applikation minimiert ist?
(2) Sollte man gleichzeitig mit dem Minimieren das Fenster auch nach unten legen (WF_BOTTOM)? In der Regel wird dies die Bedienung vereinfachen.
(3) Ăber welche Taste sollte ein Fenster minimiert werden? Es ist offensichtlich, daĂ gerade in dieser Frage alle Applikationen gleich reagieren sollten. Analog zum Applikationswechselgriff âAlt-Control-Tabâ schlage ich hiermit âAlt-Control-Leertasteâ vor, denn diese beiden Shortcuts wird man hĂ€ufig miteinander kombinieren (wenn zusĂ€tzlich eine Shift-Taste gedrĂŒckt wird, sollte man WM_ALLICONIFY ausfĂŒhren).
Das Beispiel-Listing enthĂ€lt ein winziges Rahmenprogramm, in dem absichtlich alles nicht Relevante (Redraw, Verschieben, Mausklickbehandlung etc.) weggelassen wurde. Es dient zur Demonstration des Konzepts und beinhaltet alle nötigen Definitionen fĂŒr PureC, um sofort loslegen zu können. Wichtig ist insbesondere die Funktion appl_xgetinfo(), die gemeinsam von Martin Osieka (âWinxâ) und Andreas Kromke (âMagiCâ) definiert wurde und es erlaubt, erweiterte FĂ€higkeiten des AES auch dann abzufragen, wenn die AES-Versionsnummer noch nicht 4.00 betrĂ€gt (betrifft zum Beispiel die frĂŒhen Versionen von MagiCMac).
Abb. 1: Drei minimierte Applikationen
New bugs on the block
Man ist immer wieder ĂŒberrascht, wenn man auch heute noch in ATARIs System-Software bisher unbekannte Fehler entdeckt. Im folgenden zwei Beispiele:
MetaDOS hĂ€ngt ja bekanntlich in mehr oder weniger allen GEMDOS-Funktionen, um gegebenenfalls diejenigen Aufrufe, die ein MetaDOS-GerĂ€t betreffen, an den zustĂ€ndigen GerĂ€tetreiber weiterleiten zu können. So auch die GEMDOS-Funktion Frename() (Umbenennen von Dateien). Leider ist den Entwicklern dabei entgangen, daĂ diese Funktion als ersten Parameter einen reservierten Wert, und nicht etwa den Zeiger auf den ersten Dateinamen erhĂ€lt. Daher war es reiner Zufall, daĂ Frename() in den allermeisten FĂ€llen tatsĂ€chlich dort ankam, wo es hingehörte (im normalen GEMDOS, denn wer benennt schon Dateien auf einer CD um ...). Immerhin konnte dieser Fehler zu gelegentlichen ĂŒberraschenden Meldungen der Art âDaten auf Disk X: defektâ fĂŒhren. Dieser Fehler wird in der nĂ€chsten Version von MetaDOS (2.60) beseitigt sein.
Auch beim zweiten Problem besteht ein Zusammenhang mit MetaDOS, nur steckt dieses Mal der Fehler im GEMDOS des TOS 4.04 (und möglicherweise allen anderen Falcon-GEMDOS-Versionen). Es war sicherlich die Vorstellung, GEMDOS robuster zu machen, die einen der kalifornischen Entwickler auf die Idee brachte, in Dsetdrv() eine Sicherheitsabfrage auf ungĂŒltige Laufwerkskennungen einzubauen. Wir erinnern uns: Dsetdrv() erhĂ€lt als Parameter die Nummer des aktuellen Laufwerks und gibt eine LONG-Bitmap der vorhandenen GEMDOS-Laufwerke zurĂŒck. Unter TOS 4.04 liefert diese Funktion fĂŒr ungĂŒltige Laufwerkskennungen den GEMDOS-Fehler -46 zurĂŒck, was eine zwar sehr interessante, aber dennoch völlig falsche Bitmap ergibt.
Abb. 2: Ein Fenster mit Smaller-Schaltfeld
Jedes Programm, das sich darauf verlĂ€Ăt, daĂ der RĂŒckgabewert immer (ungeachtet der Eingabe) die korrekte Bitmap enthĂ€lt, kommt dadurch ins Schlingern (zum Beispiel das ATARI-Desktop oder Gemini). Nun ĂŒbergibt man in der Regel ja keine falschen Laufwerkskennungen, daher ist das Problem bisher kaum aufgefallen. MetaDOS jedoch bearbeitet Dsetdrv() wie folgt:
(1) Laufwerkskennung merken,
(2) Aufruf an GEMDOS weiterleiten und dessen RĂŒckgabewert zurĂŒckleiten. Die Kennung eines MetaDOS-GerĂ€tes ist dem ROM-GEMDOS jedoch unbekannt, so daĂ sich beispielsweise unter Gemini folgender Effekt ergibt:
(a) Benutzer öffnet Verzeichnisfenster einer CD (dabei wird das entsprechende Laufwerk zum aktuellen Laufwerk),
(b) Die Gemini-Shell benutzt Dsetdrv (Dgetdrv ()) um die aktuell vorhandenen Laufwerke zu erfragen. Resultat: gĂŒltige Laufwerkssymbole verschwinden, andere tauchen plötzlich auf (Ă€hnliche Effekte sind auf dem ATARI-Desktop nach Beendigung eines Programms zu beobachten).
Dies ist also ein waschechter GEMDOS-Fehler. Da aber keine TOS-Up-dates mehr zu erwarten sind und das Problem in der Regel sowieso nur mit MetaDOS auftritt, wurde der Einfachheit halber der Code im MetaDOS so umgestellt, daĂ der Effekt nicht mehr auftreten kann.
/*
@(#)Atarium/icondemo.c
(c)1995 MAXON Computer
Autor: Julian F. Reschke, 20. MĂ€rz 1995
Demo zum Iconify
*/
#include <aes.h>
/* Erweiterungen fuÌr PureC */
#define SMALLER 0x4000
#define WM_BUTTOMED 33
#define WM_ICONIFY 34
#define WM_UNICONIFY 35
#define WM_ALLICONIFY 36
#define WF_ICONIFY 26
#define WF_UNICONIFY 27
/* appl_getinfo fuÌr AES >= 0x0400 und aÌltere
Systeme mit entsprechender Erweiterung */
static int
appl_xgetinfo (int type, int *out1, int *out2 ,
int *out3, int *out4)
{
static short hasagi = -1;
if (hasagi < 0)
hasagi = _GemParBlk.global[0] >= 0x400 ||
appl_find( "?AGI\0\0\0\0") == 0;
return !hasagi ? 0 :
appl_getinfo (type, out1, out2, out3, out4);
}
/* Mittels appl_getinfo wird abgefragt, ob Iconify möglich ist */
static int
has_iconify (void)
{
static int hasit = -1;
if (hasit < 0)
{
int dum, val = 0;
hasit = 0;
appl_xgetinfo (11, &val, &dum, &dum, &dum);
if (val & 128) hasit = 1;
}
return hasit;
}
/* Events bearbeiten * /
static void
do_events (int whandle)
{
int mb[8], which, key, shiftstate;
int done = 0, dummy;
int iconified = 0;
int wx, wy, ww, wh;
/* FenstermaĂe merken */
wind_get (whandle, WF_CURRXYWH, &wx, &wy, &ww, &wh);
while(!done)
{
which = evnt.multi (MU_KEYBD|MU_MESAG,
0,0,0,0,0,0,0,0,0,0,0,0,0,
mb, 0, 0, &dummy, &dummy, &dummy,
&shiftstate, &key, &dummy);
if (which & MU_KEYBD)
{
/* ^Q und ^U beenden */
if ((key & 0xff) == 17) done = 1;
if ((key & 0xff) == 21) done = 1;
/* Vorschlag: Alt-Ctrl-Blank minimiert,
mit zusaÌtzlicher Shift-Taste
entspricht es WM_ALLICONIFY */
if ((key & 0xff00) == 0x3900 && (shiftstate & 12) == 12 &&
has_iconify ())
{
which &= ~MU_KEYBD;
which |= MU_MESAG;
mb[0] = WM_ICONIFY;
mb[3] = whandle;
}
}
if (which & MU__MESAG)
{
switch (mb[0])
{
case WM_CLOSED:
done = 1;
break;
case WM_ICONIFY:
case WM_ALLICONIFY:
case WM_UNICONIFY:
if (!iconified)
{
iconified = 1;
wind_close(whandle);
wind_set (whandle, WF_ICONIFY, -1, -1, -1, -1);
wind_open (whandle, -1, -1, -1, -1);
}
else
{
iconified = 0;
wind_set (whandle, WF_UNICONIFY, wx, wy, ww, wh);
}
break;
}
}
}
}
/* Fenster erzeugen, Events bearbeiten, Fenster schlieĂen * /
static void
doit (void)
{
int whandle;
/* Fenster erzeugen und oÌffnen */
whandle = wind_create (NAME|CLOSER|SMALLER, 0, 0, 32767, 32767);
if (whandle < 0) {
form_alert (1, "[1][Out of window|handles!]" "[ OK ]");
return;
}
wind_set (whandle, WF_NAME, " Iconify-Demo ");
wind_open (whandle, 50, 100, 300, 100);
/* Eventschleife aufrufen */
do_events (whandle);
/* Fenster schlieĂen und vernichten */
wind_close (whandle);
wind_delete (whandle);
}
int
main (void)
{
appl_init ();
graf_mouse (ARROW, 0);
doit ();
appl_exit ();
return 0;
}
Abb. 3: Beispielcode
Julian F. Reschke