home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The CDPD Public Domain Collection for CDTV 3
/
CDPDIII.bin
/
pd
/
commodities
/
newedit
/
newedit.artikel
< prev
next >
Wrap
Text File
|
1992-09-24
|
11KB
|
238 lines
NewEdit V1.6:
Stringgadgets aufpoliert
Stringgadgets gehören nicht gerade zu den
Stärken von Intuition. Zwar hat sich
mit Kickstart 2.0 einiges getan, daß aber
noch mehr möglich ist, zeigt NewEdit 1.5.
Copy und Paste zwischen Stringgadgets und
dem Clipboard werden damit Wirklichkeit.
Bereits in der AmigaPlus 8/92 wurde auf die Programmierung
der Stringhooks unter Kickstart 2.0 eingegangen. Intuition
bietet dafür zwei verschiedene Ansatzpunkte:
Man kann lokale Stringhooks für jeweils ein einzelnes
Stringgadget oder sogar eine neue globale Stringhook
einhängen. Lokale Strinkhooks eignen sich dabei besonders
für programmspezifische Sonderfunktionen. Denkbar wäre
zum Beispiel eine Abfrage auf Tastenkürzel anderer Gadgets
auch im Stringgadget, die anhand der gedrückten ALT-Taste
erkannt werden.
Ganz andere Qualitäten bietet die globale Stringhook. Jene
wird als Teil von Intuition vor allen lokalen Stringhooks
aufgerufen und beinhaltet normalerweise die bekannten
Editiermöglichkeiten. An dieser Stelle setzt NewEdit 1.6
an.
NewEdit basiert auf dem gleichnamigen Programm von Oliver Wagner
(AmigaPlus Diskette 9/92). Es kann von der Shell oder auch
der Workbench gestartet werden und installiert dann
seine eigene Stringhook vor die original Intuition-Hook. Mit
CONTROL-C oder durch nochmaligen Aufruf von NewEdit wird die
Hook wieder entfernt.
NewEdit V1.6 ist ein Commodity, daß sich bei der
commodities.library anmeldet und von dort de-/aktiviert
und entfernt werden kann. Dazu braucht man lediglich
im Listview des ExChange Programms "NewEdit" anzuklicken
und kann es dann wie gewohnt vorübergehend deaktivieren oder
ganz entfernen.
Damit es dabei zu keinem verhängnisvollem Absturz kommt (die
Edithook ist gerade aktiv, während NewEdit beendet wird...),
wird eine Semaphore verwendet. Semaphores sind von Exec
verwaltete "Zählvariablen", die einen exklusiven Zugriff auf
kritische Resourcen ermöglichen. Das heißt, eigentlich handelt
es ich hierbei um eine besondere Node-Struktur in einer
verketteten Liste, jedoch lassen sie sich als Zählvariablen
besser veranschaulichen:
Eine Semaphore ist mit einem positiven Wert - beim Amiga ist
dies Eins - initialisiert. Jeweils ein Programm kann Zugriff auf
eine Semaphore haben, nämlich dann, wenn diese einen Wert größer
gleich 0 hat. Dies geschieht mittels ObtainSemaphore(), wobei der
Semaphorewert um Eins erniedrigt wird.
Versuchen nun weitere Tasks auf dieselbe Semaphore zuzugreifen,
so werden sie angehalten und in eine Warteschlange eingereiht.
Erst wenn der aktuelle Besitzer der Semaphore mit der Funktion
ReleaseSemaphore() den Zähler wieder erhöht, wird der nächste
Task (der beim Zählerstand -1 angehalten wurde) aktiviert. Dies
geschieht für den Programmierer völlig transparent. Man sollte
daher immer daran denken, daß ein Aufruf von ObtainSemaphore()
beliebig lange "dauern" kann.
Für NewEdit ist noch von Bedeutung, daß mit Kickstart 2.0
ein gemeinsamer Zugriff auf eine Semaphore durch
ObtainSemaphoreShared() möglich ist. Dies macht sich die
Stringhook zu nutzen, die so theoretisch mehfach gleichzeitig
benutzt werden kann. Dabei bleibt die Semaphore für einen
exklusiven Zugriff jedoch gesperrt. Wenn NewEdit sich also
beenden und damit die Stringhook wieder entfernen will,
wird es solange bei ObtainSemaphore() aufgehalten, bis alle
Edithooks ordnungsgemäß verlassen sind.
Doch kommen wir zur eigentlichen Stringhook. Diese bietet
nun eine Reihe von neuen Edierfunktionen, die das Arbeiten
in Stringgadgets deutlich verbessern. So kann man nun mit
ALT CURSOR LEFT auf den Anfang des vorherigen, beziehungsweise
mit ALT CURSOR RIGHT zum Start des nächsten Wortes springen.
Analog löscht ALT BACKSPACE das vorherige Wort und ALT DEL
das nächste Wort. Die bereits vorhandenen SHIFT Funktionen,
die sich jeweils bis an den Zeilenanfang/das Zeilenende auswirken,
und AMIGA X zum Löschen der kompletten Zeile, bleiben erhalten.
Falls mehrere Stringgadgets in einem Fenster vorhanden sind,
so kann mit der rechten Alttaste und CURSOR UP/DOWN zwischen
diesen frei gewechselt werden. Voraussetzung ist, daß der
Programmierer für seine Stringgadgets die TAB-Wechselfunktion
freigegeben hatte (das heißt, in der Gadgetstruktur ist
GFLG_TABCYCLE gesetzt). Die Kombination der Cursortasten mit
der rechten Alttaste wurde deshalb gewählt, um nicht in
Konflikt mit verschiedenen Filerequestern (wie zum Beispiel
dem MFR) zu kommen, die für ihre Dateiauswahl ebenfalls
die Cursortasten verwenden. Außerdem kann man mit ESCAPE ein
Stringgadget verlassen, als hätte man RETURN gedrückt.
Zum Schluß noch das Bonbon unter den neuen Editierfunktionen:
Wie oft hat man sich nicht schon darüber geärgert, wenn man
in seinem Editor nach einer Textstelle suchen will, diese
auch gerade markiert hatte und doch muß man nun in den
Suchrequester den ganzen Text von Hand erneut abtippen.
Dabei gibt es doch das Clipboard, das heute zum Glück
von den meisten Editoren für Blockoperationen genutzt wird.
Auch aus den neuen Consolen kann man markierten Text mit
AMIGA-C ins Clipboard kopieren.
NewEdit 1.6 unterstützt ebenfalls das Clipboard! Wie
gewohnt kann man nun mit AMIGA C den ganzen Inhalt eines
Stringgadgets in das Clipboard kopieren und mit AMIGA V
Text aus dem Clipboard an der Cursurposition einfügen.
Wenn man sich daran einmal gewöhnt hat, möchte man diese
Funktionen nicht mehr missen. Bleibt die Frage, warum
Commodore hier so inkonsequent ist und bisher nicht
selbst diese Fähigkeiten implementiert hat?
Der programmtechnische Umgang mit dem Clipboard gestaltet
sich etwas schwierig. Das Clipboard enthält immer IFF-Daten,
wobei nur das Format FTXT für Clipboardtext von NewEdit
unterstützt wird (ILBM Daten würden einem Stringgadget
auch nicht viel Freude bereiten). Um die IFF-Daten lesen
und schreiben zu können, verwendet NewEdit die Commodores
iffparse.library.
Die IffParse Library zählt leider zu den unübersichtlichsten
Libraries unter 2.0. Um den Umgang damit zu erleichtern,
finden sich in clipboard.c vier Funktionen, mit denen
normale Strings in das Clipboard Unit 0 geschrieben und davon
gelesen werden können. Dahinter verbirgt sich der Kampf
mit den Elementen: Zuerst muß die iffparse.library
geöffnet, ein sogenannter IFFHandle angelegt und für das
ClipBoard initialisiert werden. Die iffparse.library
kann nämlich sowohl auf DOS-Filehandle, als auch speziell
auf das clipboard.device zugreifen. Dies alles erledigt
init_iffparse(). Pendant dazu ist close_iffparse(), daß am
Ende wieder alles freigibt und schließt.
Mit write_clip() kann nun Text in das Clipboard geschrieben
werden. Dazu muß eine korrekte Iff-FTXT-Struktur erzeugt
werden. Iff-Daten bestehen immer aus einem Kopf und einem
Rumpf, wobei diese sogennanten Chunks wiederum beliebig
geschachtelt sein können. Analog ist die Logik der
iffparse.library, nämlich rekursiv. Erzeugt werden die Daten
auf einem Stapel - zuerst werden der FTXT-Kopf, dann der
CHRS-Daten-Chunk (der auch den eigentlichen ASCII-Text
enthält) mit PushChunk() darauf abgelegt. Dann wird die
so erzeugte IFF-Struktur weggespeichert und der Stapel
wieder gelehrt (zu jedem PushChunk() ein PopChunk() ).
read_clip() liest entsprechend aus dem Clipboard heraus.
Erschwehrend kommt nun hinzu, daß im Clipboard beliebige
IFF-Formate liegen können und nur ein FTXT-Chunk
eingelesen werden soll. Die iffparse.library bietet hierzu
die Funktion StopChunk(), mit der ihr mitgeteilt wird,
welche Daten gesucht werden. Danach wird mit ParseIFF()
über einem IFFHandle (bei NewEdit auf das Clipboard
initialisiert) eine IFF Struktur solange durchsucht,
bis der gewünschte Datenchunk erreicht ist. Wie gesagt,
IFF-Daten können beliebig verschachtelt sein.
Wenn nun ParseIFF() zurückkehrt, so ist entweder das
Ende der IFF-Daten oder der gesuchte Datenchunk
erreicht. Welches Format nun im aktuellen Chunk vorliegt
erfährt man mittels CurrentChunk(), das eine sogenannte
ContextNode füllt. Hierin kann man nun entgültig auf
das gesuchte Format testen und gegebenenfalls mit
ReadChunkBytes() die eigentlichen ASCII-Zeichen
einlesen. Wie man liest, habe ich nicht zu viel
versprochen - die iffparse.library ist kompliziert.
Um zu ursprünglichen Stringhook zurückzukehren noch
zwei Hinweise: Die Stringhook von NewEdit ruft immer
noch Intuition's ursprüngliche Edithook auf, wodurch
alle üblichen Editierfunktionen erhalten bleiben und
vorallem das Stringgadget immer aktualisiert wird.
Allerdings muß mitunter verhindert werden, daß dort
die bereits interpretierten Tasten erneut ausgewertet
werden. Sonst würde zum Beispiel nach AMIGA-V zusätzlich
noch ein V im Stringgadget auftauchen. Das Problem
ist etwas unsauber gelöst: Der Inputeventcode der
aktuellen Taste wird auf den unbenutzten Wert 0
verdreht, wodurch die weiteren Editierhooks untätig
bleiben. Außerdem vermerkt NewEdit in dem Feld
EditOp der übergebenen SGWork-Struktur die Operation
EO_BIGCHANGE, falls Text eingefügt oder Worte gelöscht
wurden. Somit können spätere Edithooks auf diesen
Wert achten.
Datenstrukturen:
Die SignalSemaphore-Struktur:
struct SignalSemaphore {
struct Node ss_Link; /* Verkettung innerhalb von SysBase->SemList, */
/* enthält vorallem Priorität und Name */
WORD ss_NestCount; /* der eigentliche Zähler */
struct MinList ss_WaitQueue; /* Warteschlange für anfragende Tasks */
struct SemaphoreRequest ss_MultipleLink;
struct Task *ss_Owner; /* Adresse des momentanen Besitzer-Tasks */
WORD ss_QueueCount; /* Größe der Warteschlange */
};
Die IFFHandle-Struktur:
struct IFFHandle {
ULONG iff_Stream;
ULONG iff_Flags;
LONG iff_Depth; /* Tiefe des Context-Stacks. */
/* Dahinter noch weitere private Felder... */
};
Die ContextNode Struktur:
struct ContextNode {
struct MinNode cn_Node;
LONG cn_ID; /* Chunk-ID, beu uns ID_CHRS (vgl. unten) */
LONG cn_Type; /* Datentyp, für uns nur ID_FTXT */
LONG cn_Size; /* Größe des zugehörigen Chunks */
LONG cn_Scan; /* Anzahl Zeichen bisher geschrieben/-lesen */
/* Dahinter noch weitere private Felder... */
};
/* universelle IFF ID's */
#define MAKE_ID(a,b,c,d) \
((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))
#define ID_FORM MAKE_ID('F','O','R','M')
#define ID_LIST MAKE_ID('L','I','S','T')
#define ID_CAT MAKE_ID('C','A','T',' ')
#define ID_PROP MAKE_ID('P','R','O','P')
#define ID_NULL MAKE_ID(' ',' ',' ',' ')
#define ID_FTXT MAKE_ID('F','T','X','T')
#define ID_CHRS MAKE_ID('C','H','R','S')