← ST-Computer 05 / 1995

Atarium - Iconify

Grundlagen

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 fü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 für AES >= 0x0400 und ä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 zusä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 ö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