Atarium: Drag&Drop

Unter den vielen neuen Möglichkeiten der Benutzerführung ist der Begriff 'Drag & Drop' schon länger in aller Munde. In MultiTOS sind neue Mechanismen implementiert, die diese Art, Programme miteinander kommunizieren zu lassen, erweitern. Doch schon lange vorher konnte man auf dem ATARI (und anderswo) , ziehen und loslassen' (so der Versuch einer Eindeutschung).

Bereits im ursprünglichen ATARI-Desktop konnte man Datei-, Verzeichnis- und Laufwerkssymbole über den Bildschirm ziehen und über einem Ziel (einem Laufwerkssymbol oder einem Desktop-Fenster) fallenlassen. Das Desktop faßt dies als Befehl zum Kopieren auf, und wir alle haben uns in den Jahren daran gewöhnt.

Das alternative Desktop 'Gemini' brachte uns - angelehnt an den 'Finder' des Macintosh - die Möglichkeit, Datei- und Ordnersymbole auch auf dem Desktop-Hintergrund abzulegen. An der grundsätzlichen Funktionalität (Kopieren oder gegebenenfalls Verschieben) hat dies aber nichts geändert. Neu war lediglich, daß man gezielt Dateien auf die Symbole von Programmdateien (oder Script-Dateien) ziehen konnte, um sie als Parameter zu übergeben. Die von vielen geschätzte Integration von Kommando-Shell und grafischer Oberfläche wird in Gemini auch wiederum durch ,Drag&Drop' unterstützt: wenn man Datei- oder Verzeichnissymbole in das Shell-Fenster zieht, wird der zugehörige Pfadname an der aktuellen Cursor-Position eingefügt.

Das Desktop des TOS 2.06 brachte als Neuerungen ein Druckersymbol (darauf gezogene Dateien wurden ausgedruckt, unter ,Gemini' leicht mit einem Shellscript zu erreichen) und die Möglichkeit, Dateien als Parameter auf in Fenstern liegende Symbole von Programmdateien zu ziehen.

Das VA-Protokoll (Venus-Accessory) in Gemini erlaubt es Accessories (und parallel laufenden GEM-Programmen), mit Gemini zu kommunizieren. So kann beispielsweise das PD-Programm, Tree View' von Stephan Gerle an Gemini das Kommando verschicken, ein bestimmtes Verzeichnisfenster zu öffnen. Umgekehrt kann man von Gemini aus Icons auf die Fenster anderer Programme, die das VA-Protokoll verstehen, ziehen.

Generell braucht man sich natürlich bei der Idee des ,Ziehens und Fallenlassens' nicht auf Datei- und Ordnersymbole zu beschränken. Warum sollte man nicht beispielsweise einen selektierten Textausschnitt aus einem Editor auf das Druckersymbol des Desktops ziehen?

Wie sieht es nun mit ,Drag&Drop' im MultiTOS aus? ATARI setzt ein sehr flexibles Protokoll ein, das selbst nicht Bestandteil des Betriebssystems ist und daher auch unter anderen Betriebssystemvarianten eingesetzt werden könnte, vorausgesetzt sie unterstützen Multitasking und das Pipe-Dateisystem ([!]).

Das AES-Message-Protokoll ist seit langem bekannt und leider mit einigen Schwächen behaftet. Zuverlässig arbeitet das System ausschließlich dann, wenn man sich auf Mitteilungen in der Standardlänge von acht 16-Bit-Werten beschränkt. Längere Mitteilungen waren zwar prinzipiell vorgesehen, haben aber nicht zuverlässig funktioniert. Die meisten Programme, die per AES-Messages Daten austauschen, verschicken daher nur Zeiger auf die Daten (so auch Gemini im VA-Protokoll). Unter MultiTOS dürfen allerdings Programme (normalerweise) nicht auf fremde Speicherbereiche zugreifen, und so mußte eine neue Lösung gefunden werden.

Die offensichtliche' Verbesserung wäre natürlich eine Erweiterung des AES-Message-Mechanismus gewesen. Diesen Weg ist ATARI allerdings nicht gegangen, vermutlich um sich einen Eingriff in einen sehr komplexen Teilbereich des AES zu ersparen. Ganz im Gegenteil: unter MultiTOS kann man tatsächlich nur noch maximal 16 Bytes lange Mitteilungen verschicken.

Statt dessen macht sich ATARIs Lösung die Existenz der bidirektionalen Pipes von MiNT zunutze. AES-Mitteilungen werden ausschließlich dazu benutzt, um die Kommunikationspartner zusammenzubringen', die gesamte restliche Datenübertragung erfolgt dann über eine Pipe, auf die man mit den gewohnten GEMDOS-Dateifunktionen zugreifen kann.

Um eine Dragdrop-Kommunikation zu beginnen, legt man im Verzeichnis 'U:\PIPE' eine Datei namens , DR AG-DROP, xx' an, wobei ein, x jeweils für die Buchstaben A bis Z stehen kann. Damit können prinzipiell 676 gleichzeitige Dragdrop-Vorgänge stattfinden, was sicherlich ausreichen wird. Zum Anlegen der Pipe kann man einfach Fcreate() verwenden, da es, wenn bereits eine gleichnamige Pipe existiert, eine ordentliche Fehlermeldung zurückliefert. Beim Anlegen der Pipe sollte das Hidden-Bit (Bit l) gesetzt werden: dadurch erhält die lesende Seite ein EOF, wenn die andere Seite der Pipe geschlossen worden ist.

Anschließend wird die DRAGDROP-Message verschickt. Die Belegung der Mitteilungsstruktur ist dabei:

buffer[0]: AP_DRAGDROP (63)
buffer[1]: AES-apid des Senders
buffer[2]: 0 (keine Überlänge)
buffer[3]: Kennung des Zielfensters
buffer[4]: X-Position des Mauszeigeis
buffer[5]: Y-Position des Mauszeigers
buffer[6]: Keyboard-Shift-Status (siehe etwa evnt_keybd())
buffer[7]: die zwei Zeichen der Pipe-Extension

Die ersten drei Felder (buffer[0] bis buffer[2]) sind genauso belegt, wie man es bereits von anderen AES-Mitteilungen kennt. buffer[3] enthält die Kennung des Zielfensters, die der Sender mittels wind_find() ermitteln kann.

Wenn anstelle einer gültigen Fensterkennung -1 übergeben wird, dann ist das Ziel der Drag&Drop-Operation kein spezielles Fenster, sondern die Applikation generell. Normalerweise sollte die Mitteilung dann so interpretiert werden, daß ein zusätzliches Fenster für die angegebenen Daten geöffnet wird.

Desktops können sich dies zunutze machen, um bei dafür vorbereiteten Applikationen den Mehrfachstart (zum Beispiel dann, wenn der Anwender zweimal nacheinander zur Applikation gehörige Dokumentdateien .öffnet') zu vermeiden. Statt dessen erhält die bereits laufende Applikation nur die Aufforderung, die angegebene Datei zu öffnen.

buffer[4], buffer[5] und buffer[6] enthalten Informationen über die Position des Mauszeigers und den Zustand der Umschalttasten (Shift etc.). Damit kann der Empfänger seine Reaktion von der genauen Mausposition und dem Tastaturstatus (Beispiel: Control für Verschieben anstelle von Kopieren) abhängig machen, buffer[7] schließlich enthält die beiden variablen Zeichen des Pipe-Namens.

Es ist keine besondere Rückmeldung auf diese Mitteilung vorgesehen. Der Sender muß sich daher der MiNT-Funktion Fselect() bedienen, um festzustellen, ob irgend jemand auf der Gegenseite die Pipe zum Lesen geöffnet hat und empfangsbereit ist. ATARI empfiehlt dabei eine Timeout-Zeit von drei bis vier Sekunden.

Leider kann der Sender nicht im voraus feststellen, ob die zum Zielfenster gehörige Applikation überhaupt das Drag&Drop-Protokoll unterstützt. Daher wird im Zweifelsfall die oben angegebene Timeout-Zeit ereignislos verstreichen, bevor der Anwender eine Rückmeldung erhält. Dieses Problem läßt sich leider nicht umgehen; allerdings sollten neue Applikationen, die das Drag&Drop-Protokoll (noch) nicht unterstützen wollen, wenigstens erst einmal eine, Verweigerungs' -Antwort schicken. Damit bekommt der Sender sofort eine Rückmeldung, und die lästige Wartezeit ist vermieden.

Eine solche Routine kann in jedes GEM-Programm mit minimalem Aufwand eingebaut werden. Listing 1 zeigt ein entsprechendes Listing (vgl. [2]): anhand der Mitteilung wird der Dateiname für die zu benutzende Pipe zusammengesetzt, diese geöffnet, und das Status-Byte für 'nicht empfangsbereit' ('negative acknowledge', DD_NAK (1)) hineingeschrieben.

Wenn die angesprochene Applikation hingegen empfangsbereit ist, sollte sie das Status-Byte DD_OK' (0) zurückschicken. Anschließend müssen sich beide Seiten über die Art der zu verschickenden Daten einigen.

Kernpunkt des Drag&Drop-Protokolls sind unterschiedliche Arten von Datentypen, die als vier Zeichen lange Buchstabenfolgen dargestellt werden. Beim Verschieben von Desktop-Icons handelt es sich normalerweise um Daten vom Typ ARGS, also um Argumente (Parameter) für Programme. Der Datentyp PATH ist reserviert, um Informationen über das vom Benutzer gewählte Zielobjekt zu erfragen. Datentypen, die mit einem Punkt beginnen, sind als Extension zu interpretieren (analog zu den Dateiformaten, die im GEM-Clipboard benutzt werden). So würde beispielsweise .TXT für Textinformationen im ASCII-Format stehen.

Listing nodrop.c

/* Dieses Programmfragment signalisiert dem Drag&Drop-
Sender, daB das eigene Programm diese Art von Prozesskommunikation nicht versteht
(vgl. ST-Magazin 6/1993) (c)1993 by MAXON-Cowputer */

#ifndef AP_DRAGDROP 
#define AP_DRAGDROP 63 
#define DD_NAK      1 
#endif

/* In der Event-Schleifa (mb iat der Meaaage-Puffer) */ case AP_DRAGDROP: {
static char pipename[] =
"U:\\PIPE\\DRAGDROP.AA"; long fd;
pipename[18] = mb[7] & 0x00ff; 
pipename[17] = (mb[7] & 0xff00) >> 8;

fd = Fopen (pipename, 2);

if (fd >= 0)
{
	char c = DD_NAK;
	Fwrite ((int) fd, 1, &c);
	Fclose ((int) fd); 
} 
} 
break;

Der Empfänger muß nun (nach dem Senden von DDjOK) eine Liste von acht für ihn brauchbaren Datentypen senden -sortiert nach Präferenz. So kann ein Grafikprogramm bei spielsweise mitteilen, daß es Vektorgrafikdaten (GEM) und Rasterbilddaten (TIF) versteht, erstere aber vorzieht (dazu würde GEM in der Liste vor TIF auftreten). Wenn weniger als acht Datentypen verstanden werden, wird der Rest der Liste mit Null-Bytes aufgefüllt. Insgesamt müssen also genau 32 Bytes übermittelt werden.

Der Datentyp ARGS steht rur eine Kommandozeile, also im Allgemeinen einen oder mehrere Datei- oder Verzeichnisnamen, die voneinander durch Leerzeichen getrennt sind. Für Dateinamen, die selbst Leerzeichen enthalten (mit den erweiterten Dateisystemen von MiNT ohne Weiteres möglich), ist eine Sonderbehandlung nötig. Dazu wird der Dateiname durch einfache Anführungsstriche eingeschlossen, und jeder Anführungsstrich, der im Namen auftritt, durch einen doppelten ersetzt. Aus der Datei Eric 's file würde also Eric"sfile.

Bei PATH hingegen handelt es sich um einen Spezialfall, in dem der Empfänger quasi zum Sender der gewünschten Information wird. Dazu gleich mehr.

Der Sender entscheidet nun anhand der vom Empfänger übermittelten Liste von Datentypen, welches Format verwendet werden soll. Dabei dient die Liste nur als Richtlinie; der Sender kann also durchaus eine andere Reihenfolge benutzen oder auch noch andere Formate,anbieten'. Die Übermittlung der Daten erfolgt in zwei Schritten: zunächst wird ein Header verschickt, der alle Informationen über die Daten, ihr Format und ihre Länge enthält, Der Empfänger kann darauf auf verschiedene Art und Weise reagieren. Insbesondere kann er sich ein anderes Format ,wünschen' (dazu gleich mehr).

Der Header besteht aus insgesamt fünf I Feldern (siehe Abbildung 1). Erbeginnt mit der Gesamtlänge des Headers als Integer (also zwei Bytes) und dem bereits beschriebenen Datentyp (vier Zeichen), Die folgenden vier Bytes enthalten die Länge der zu übertragenden Daten.

Als nächstes kommt eine Zeichenkette, die einen ,Namen' für die Daten enthält (und auch leer sein darf). Sie sollte den Inhalt der Daten beschreiben. Schließlich kommt ein zu den Daten zugehöriger Dateiname. Auch er ist nullterminiert.

Der Header ist erweiterbar, da zu Beginn seine Länge übergeben wurde. Daher sollte man ,überzählige' Bytes nach dem letzten Feld ignorieren.

Nachdem er den Header eingelesen hat, kann der Empfänger mit verschiedenen Status-Bytes reagieren. Bereits bekannt sind DD_OK (0, Weitermachen") und DD_NAK (l, "Drag&Drop abbrechen"). DD_EXT (2) wird verschickt, wenn der ' Empfänger das angebotene Datenformat nicht mag. Daraufhin wird der Sender einen neuen Header mit einem anderen Format schicken oder seinerseits die Übertragung abbrechen. Dies kann sich solange wiederholen, bis sich Sender und Empfänger auf ein Format geeinigt haben, oder bis feststeht, daß es keine Möglichkeit der Verständigung gibt.

DD_LEN(3) kann benutzt werden, wenn man nicht so viele Daten entgegennehmen kann, wie die Gegenseite verschicken will. DD_TRASH (4), DD_PRINTER (5) und DD_CLIPBOARD (6) signalisieren dem Sender, daß das Ziel der Operation ein Mülleimer-, ein Drucker- oder ein Klemmbrettsymbol war. In diesen Fällen sollte der Sender die Übertragung abbrechen und mit den Daten wie angegeben verfahren (also sie löschen, ausdrucken oder in das GEM-Klemmbrett schreiben). Alle anderen Werte sind für künftige Anwendungen reserviert.

Header bei Drag&Drop
Position Länge Inhalt
0 2 Bytes Länge des Headers 1
2 4 Bytes Datentyp (z. B. 'ARGS')
6 4 Bytes Länge der Daten
10 variabel (n) 'Name'der Daten (nullterminiert)
10 + n variabel Dateiname

Genau dann, wenn der Empfänger mit DDjOK geantwortet hat, wird mit der Übertragung der Daten begonnen. Dabei werden genauso viele Bytes geschrieben wie im Header angegeben und anschließend die Pipe geschlossen.

Eine Ausnahme bildet nur der Datentyp PATH. Hier geht die Übertragung andersherum, und der Sender liest genauso viele Bytes wie angegeben. Hier muß also der Sender nach DD_OK direkt die Daten übermitteln. Sie sollten den vollen Pfadnamen (mit \terminiert) bzw. Dateinamen des Zielfenster enthalten.

Noch zwei wichtige Hinweise: normalerweise wird eine Applikation vom Kernel terminiert, wenn sie in eine Pipe schreibt, die von niemandem zum Lesen geöffnet ist. Dies läßt sich verhindern, indem man das Signal SIGPIPE ignoriert (durch ,Psignal (SIGPIPE, SIGJGN)', wobei,SIGPIPE' 13 und ,SIGJGN' 1 ist). Weiterhin sollte keine der beiden Seiten wind_update() benutzen. Anderenfalls könnte es zu einem Deadlock kommen, wenn eine der Seiten versucht, eine Bildschirmausgabe - etwa eine Alertbox- zu machen.

Nun noch zwei aktuelle Meldungen zur System-Software: Eric Smith hat die Sourcen der MiNT-Version 1.08 freigeben. Dabei gelten die üblichen COPyright-Bestimmungen (Weitergabe nur als Quelltext erlaubt). Weiterhin gibt es vom Diablo-Emulator die Version 1.6. mit die seit MiNT-Version 0.96 aufgetretener, Probleme beseitigt werden. Die neue Version ist als 'diablo!6.zoo' in verschiedenen Mailboxen (zum Beispiel Maus MS und MTK) verfügbar und macht das Patch Programm 'DIABFIX' überflüssig.

Soviel für diesen Monat - wenn nichts dazwischenkommt, gibt es dann nächstes Mal Beispielroutinen für das Drag&Drop Protokoll.

Quellennachweis:

[1] Eric Smith: "Drag and Drop protocol, revision 1.1", ATARI Corporation 1993
[2] Julian F. Reschke: "Noch mehr Tips für MiNT", ST-Magazin 6/1993, Seite 54

Die zur Betatest-Version von MiNT 1.08 gehörigen Dateien

MiNT 1.08, Betatest-Version für Programmierer

mintl OSs.zoo (301949 Bytes) Sourcecode der Betatest-Version von MiNT 1.08;geeignet für GNU-CC und Pure-C-MiNT-übraries (Patchlevel 34, mit viel interessantem Beispielcode)

mntinc34.zoo (111433 Bytes) Headerfiles
mntlib34.zoo (394656 Bytes) Die C-Quelltexte
mntolb34.zoo (285972 Bytes) die fertig übersetzten Bibliotheken für GNU-cc.

Diese Dateien sollten in jeder besser sortierten Mailbox zu finden sein. Leser mit Internet-Zugang können die Dateien auch u. a. auf den ftp-Servern atari.archive.umich.edu und ftp.uni-muenster.de im Verzeichnis ATARI/MINTfinden. Selbstverständlich kann es sein, daß bis zum Erscheinungstermin eine neue MiNT-Version oder neue Libraries (Patchlevel >= 35) verfügbar sind.


Julian F. Reschke
Aus: ST-Computer 10 / 1993, Seite 110

Links

Copyright-Bestimmungen: siehe Über diese Seite