#define	S2F_C			Dirk Urbanek 1988
/*#define	K	Kommentar an*/
#define	intern		 /* Kann auch in Exec/Types.h definiert werden.*/

#include <Exec/Types.h>
#include <Exec/Memory.h>
#include <Exec/Ports.h>
#include <Exec/Tasks.h>
#include <Exec/Interrupts.h>
#include <Hardware/Intbits.h>
#include <Intuition/Intuition.h>
#include <Intuition/IntuitionBase.h>

#define	NO_ERR	0l
#define	NO_INT	2l
#define	NO_GFX	3l
#define	NO_MEM	4l
#define	NO_SIG	5l

#define	MAXSCREEN	9
#define	ENDTASTE	9
#define	OPENSCREEN	-1
#define	CLOSESCREEN	-2
#define	MOTHER		"s2f DU 88"

extern		APTR	 	 OpenLibrary	() ;
extern		void		*SetFunction	() ;
extern		APTR		 AllocMem	() ;
extern	struct	Task		*FindTask	() ;
intern		void		 PServer	() ;
intern		void		 NewOS		() ;
intern		void		 NewCS		() ;
intern		char		*ChangeTaskName	() ;

intern	struct	IntuitionBase	*IntuitionBase	;
intern	struct	Interrupt *PInt		= NULL	    ;
intern	struct	Task	  *ThisTask	= NULL	    ;
intern		LONG	   signal	= 28	    ;
intern		BYTE	   Count	= 0	    ;
intern		void	  *OldOS	= NULL	    ;
intern		void	  *OldCS	= NULL	    ;
intern		LONG	   TError	= NO_ERR    ;
intern		LONG	   OldPri	= 0l	    ;
intern	struct	Screen	  *NewScreen	= NULL	    ;
intern	struct	Screen	  *OldScreen	= NULL	    ;
intern	struct	Screen	  *ScreenList	[MAXSCREEN] ;
intern		LONG	   SCount	= 0	    ;
intern		char	  *OldName	= NULL	    ;
intern		BYTE	   LAFlag	= 0	    ;

 void
main()
  {
   register struct Screen *s ;
   register	   BYTE    i ;

/* Ein ScreenToFront genügt ! */
     if(FindTask( MOTHER )) exit( 100 ) ;

     OldName = ChangeTaskName( MOTHER ) ;

/* IntuitionBase feststellen und bei Mißerfolg (?!) abbrechen */
     if(!(IntuitionBase=(struct IntuitionBase *)
				OpenLibrary("intuition.library",0l)))
	{ TError = NO_INT ; goto no_int ; }

/* Um mit den richtigen Werten zu arbeiten: Verbot des Taskwechsels */
Forbid() ;
/* und die Funktionszeiger von OpenScreen und CloseScreen richten */
/* -  und zwar auf uns !					  */
	OldOS = SetFunction( IntuitionBase , -198 , NewOS ) ;
	OldCS = SetFunction( IntuitionBase , -66  , NewCS ) ;

/* Ein Signal anfordern, damit wir keine Rechenzeit für die Abfrage   */
/* der Variablen brauchen. Systemperformance !	(s. Fensterjoungleur) */
     if(-1 == (signal = AllocSignal(-1)))
	{ TError = NO_SIG ; goto no_sig ; } ;

/* Damit die drei Hilfsprogramme wissen, wohin mit dem Signal. */
	ThisTask = FindTask(0l) ;

/* Speicher für den Interrupt muß angefordert und intialisiert werden */
     if(!(PInt=(struct Interrupt *)AllocMem(sizeof(struct Interrupt),MEMF_PUBLIC|MEMF_CLEAR)))
	{ TError = NO_MEM ; goto no_mem ; }

	PInt->is_Node.ln_Type	= NT_INTERRUPT	; /* Knotentyp		*/
	PInt->is_Node.ln_Pri	= -60		; /* Rainer Schätzwert	*/
	PInt->is_Node.ln_Name	= "S2fServer"	; /* Knotenname		*/
	PInt->is_Data		= NULL		; 
	PInt->is_Code		= PServer	; /* Die Serverroutine	*/

/* Dann müssen die bereits eröffneten Schirme festgestellt und  */
/*  in die Liste eingetragen werden.				*/
  for( s = IntuitionBase->FirstScreen , SCount=0
		; s && ( SCount < MAXSCREEN )
			;  s = s->NextScreen , SCount++ )
	   ScreenList[SCount] = s ;

/* Bevor die Anderen wieder mitspielen dürfen, muß eine gewisse Ablauf- */
/* sicherheit geschaffen werden. Die enorm hohe Priorität stört nicht,  */
/* da dieses Programm eh nur auf vom User gewünschte Ereignisse wartet.	*/
	OldPri = SetTaskPri( ThisTask , 10l ) ;
Permit() ;

/* ARBEITSSCHLEIFE ARBEITSSCHLEIFE ARBEITSSCHLEIFE ARBEITSSCHLEIFE */

    while( Count != ENDTASTE )
      {
	AddIntServer(INTB_PORTS,PInt) ;

       Wait(1<<signal) ;

	RemIntServer(INTB_PORTS,PInt) ;

       if( (LONG)Count >= 0 )
	{
#ifdef	K
	 printf("Funktionstaste: %3ld\n" , Count+1 ) ;
#endif	K
/* Funktionstaste gedrückt -> entsprechenden Schirm nach vorne bringen.*/
	 if( ((LONG)Count) < SCount )
	  ScreenToFront( ScreenList[(LONG)Count] ) ;
	}
       else
	{
	 if( (LONG)Count == OPENSCREEN )
	  {
#ifdef	K
	   printf("Ein Schirm wurde eröffnet !\n" ) ;
#endif	K
/* Schirm geöffnet -> Schirmliste ergänzen */
	   if( SCount < MAXSCREEN )
	    {
	     ScreenList[ SCount ] = NewScreen ;
	     SCount ++ ;
	    }
	  }
	 if( (LONG)Count == CLOSESCREEN )
	  {
#ifdef	K
	   printf("Ein Schirm wurde geschlossen !\n" ) ;
#endif	K
/* Schirm geschlossen -> Diesen Schirm aus der Liste nehmen. */
	   for( Count = 0 ; (LONG)Count < SCount ; Count++ )
	    if( ScreenList[(LONG)Count] == OldScreen ) break ;
	   SCount -- ;
/* und die anderen nachrücken lassen.	*/
	   for( i = Count ; i < SCount ; i++ )
	    {
	     ScreenList[i] = ScreenList[i+1] ;
	    }
	  }
	}
      }

/* ARBEITSSCHLEIFE ARBEITSSCHLEIFE ARBEITSSCHLEIFE ARBEITSSCHLEIFE */

/* Priorität wieder auf den alten Stand bringen und aufräumen. */
	SetTaskPri( ThisTask , OldPri ) ;

Forbid() ;
     FreeMem( PInt , sizeof(struct Interrupt) ) ;
no_mem:
     FreeSignal( signal ) ;
no_sig:
/* Die Funktionszeiger müssen wieder zurückgebogen werden. */
	SetFunction( IntuitionBase , -198 , OldOS ) ;
	SetFunction( IntuitionBase , -66  , OldCS ) ;

Permit() ;
     CloseLibrary( IntuitionBase ) ;
no_int:
     ChangeTaskName( OldName ) ;

   exit( TError * 10l ) ;
  }

 char *
ChangeTaskName( Name )
  char  *Name		;
  {
   register	   char *OldName  ;
   register struct Task *ThisTask ;

Forbid() ;
    ThisTask = FindTask(0l) ;
    OldName  = ThisTask->tc_Node.ln_Name ;
    ThisTask->tc_Node.ln_Name = Name ;
Permit() ;

   return( OldName ) ;
  }


#asm

; ************************************************************************
; **			Der Tastatur - Interrupserver			**
; ************************************************************************

	XREF	_LVOSignal
	XDEF	_PServer

_PServer

	move.b	$bfec01,d0		; Tastaturwert einholen
	not	d0			; und in eine lesbare Form
	ror.b	#1,d0			; bringen

	move.l	#_LAFlag,a0		; Flagadresse laden
	cmp.b	#$64,d0			; wurde Links - Alt gedrückt ?
	bne	AT			; nein -> AT
	move.b	#1,(a0)			; doch: LAlt - Flag setzen
	bra	weiter			; und diesen Server verlassen

AT	cmp.b	#$e4,d0			; wurde Links - Alt losgelassen ?
	bne	NAT			; nein -> NAT
	move.b	#0,(a0)			; ja: also LAlt - Flag löschen
	bra	weiter			; und diesen Server verlassen

NAT	tst.b	(a0)			; LAlt - Flag gesetzt ?
	beq	weiter			; nein -> diesen Server verlassen
	cmp.b	#$50,d0			; ja: wurde ein HighKey gedrückt ?
	blt	weiter			; nein -> diesen Server verlassen
	cmp.b	#$59,d0			; war es eine F-Taste ?
	bgt	weiter			; nein -> diesen Server verlassen
_FTaste:
	sub.b	#$50,d0			; F-Tastennummer (0-9) ermitteln
	move.l	#_Count,a0		; Adresse von Count laden
	move.b	d0,(a0)			; und die Tastenummer ablegen
	move.l	#_ThisTask,a1		; Mutters Adresse bestimmen
	move.l	(a1),a1
	move.l	#0,d0			; und das Signalbit setzen
	move.l	#_signal,a0
	move.l	(a0),d1			; ExecBase ist bei Interrupts
	bset.l	d1,d0			; immer in a6
	jsr	_LVOSignal(a6)		; Mutter ein Signal geben
weiter
	moveq.l	#0,d0
	rts


; ************************************************************************
; **		Die  'neue'  OpenScreen - Funktion			**
; ************************************************************************

	XDEF	_NewOS

_NewOS					; Zuerst wird die alte Funktion
	move.l	a1,-(a7) 		; angesprungen
	move.l	#_OldOS,a1
	move.l	(a1),a1
	jsr	(a1)
	move.l	(a7)+,a1

	movem.l	a0-a1/a6/d0-d1,-(a7)	; Die benutzten Register retten
	move.l	#_Count,a0		; Zur Identifikation Count -1 setzen
	move.b	#-1,(a0)		; Bedeutung: neuer Schirm
	move.l	#_NewScreen,a0		; Und die Adresse des neuen
	move.l	d0,(a0)			; Schirmes sichern
	move.l	#_ThisTask,a1		; Danach Mutter signalisieren, daß
	move.l	(a1),a1			; sich etwas geändert hat.
	move.l	#0,d0			; Dafür das Signalbit in d0 setzen
	move.l	#_signal,a0
	move.l	(a0),d1
	bset.l	d1,d0
	move.l	$4,a6			; Warum geht _SysBase bei Manx nicht ?
	jsr	_LVOSignal(a6)
	movem.l	(a7)+,a0-a1/a6/d0-d1	; Register restaurieren
	rts				; und zurück in das Userprogramm

; ************************************************************************
; **		Die  'neue'  CloseScreen - Funktion			**
; ************************************************************************


	XDEF	_NewCS

_NewCS					; Zuerst muss festgestellt werden,
					; wer sich da vom Acker macht
	movem.l	a0-a1/a6/d0-d1,-(a7)	; Die benutzten Register retten
	move.l	#_Count,a1		; Zur Identifikation Count setzen
	move.b	#-2,(a1)		; Bedeutung: neuer Schirm
	move.l	#_OldScreen,a1		; Und die Adresse des neuen
	move.l	a0,(a1)			; Schirmes sichern
	move.l	#_ThisTask,a1		; Danach Mutter signalisieren, daß
	move.l	(a1),a1			; sich etwas geändert hat.
	move.l	#0,d0			; Dafür das Signalbit in d0 setzen
	move.l	#_signal,a0
	move.l	(a0),d1
	bset.l	d1,d0
	move.l	$4,a6			
	jsr	_LVOSignal(a6)
	movem.l	(a7)+,a0-a1/a6/d0-d1	; Register restaurieren
	move.l	a1,-(a7) 		; Dann wird die Intuitionfunktion
	move.l	#_OldCS,a1		; angesprungen ( -fallen ? ).
	move.l	(a1),a1
	jsr	(a1)
	move.l	(a7)+,a1
	rts				; und zurück in das Userprogramm

#endasm
