home *** CD-ROM | disk | FTP | other *** search
-
- 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')
-