Atarium - Iconify

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
Aus: ST-Computer 05 / 1995, Seite 90

Links

Copyright-Bestimmungen: siehe Über diese Seite