
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*                                                                       *
*                                                                       *
*                    * * * *                                            *
*                   *     *                                             *
*                  *     *   _________________________________________  *
*                 *     *   /                                        /  *
*                *     *   /           Assembly Source of           /   *
*               *     *   /           CloseWbPatch  v1.1           /    *
*  * * * *     *     *   /                                        /     *
*   *     *   *     *   /          - BURNAND  Patrick -          /      *
*    *     * *     *   /                                        /       *
*     *     *     *    ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯        *
*      *         *                                                      *
*       * * * * *                                                       *
*                                                                       *
*                                                                       *
*                                                                       *
*   This source code is distributed with the CloseWbPatch package and   *
*   may not be distrbuted by another way.   It must always be kept in   *
*   original and unmodifed form.   This file is distributed for lear-   *
*   ning purposes and as example only.  You are allowed to print this   *
*   file but you aren't allowed to distribute it in printed form.  If   *
*   you want  to  make  others uses of this source code,  contact the   *
*   author.   My adress can be found in the doc file of this program.   *
*                                                                       *
*                                                                       *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *




** Main

** 1.0


**  CONSTANTES GLOBALES  **

ExecBase	EQU	4


**  PROCÉDURES INTERNES  **

* XREF NewFunction			Code de la nouvelle fonction CloseWorkbench()


**  PROCÉDURES EXTERNES  **

AddPort		EQU	-$0162
AllocMem	EQU	-$00c6
AllocSignal	EQU	-$014a		Exec.AllocSignal (SignalNum) (d0)
ClearCacheU	EQU	-$027c		Exec.ClearCacheU () ()
CloseLibrary	EQU	-$019E		Exec.CloseLibrary (library) (a1)
CopyMem		EQU	-$0270
CreateMsgPort	EQU	-$029a
DeleteMsgPort	EQU	-$02a0
FindPort	EQU	-$0186
FindTask	EQU	-$0126		Exec.FindTask (name) (a1)
Forbid		EQU	-$0084
FreeMem		EQU	-$00d2
FreeSignal	EQU	-$0150		Exec.FreeSignal (SignalNum) (d0)
GetMsg		EQU	-$0174
OpenLibrary	EQU	-$0228		Exec.OpenLibrary (name, version) (a1, d0)
Permit		EQU	-$008a
PutMsg		EQU	-$016e
RemPort		EQU	-$0168
ReplyMsg	EQU	-$017a		Exec.ReplyMsg (message) (a1)
SetFunction	EQU	-$01a4
SetTaskPri	EQU	-$012c
WaitPort	EQU	-$0180


**  CODE  **

Main:
	Movem.l	a3/a6,-(a7)

	Move.l	ExecBase,a6			OwnTask := FindTask (NIL);                                             OwnTask := pointeur sur la tâche courante
	Suba.l	a1,a1
	Jsr	FindTask(a6)
	Move.l	d0,OwnTask

	Move.l	d0,a3
*	Move.l	OwnTask,a3			IF  (Process.pr_CLI # NIL)  THEN                                       SI  (le programme n'est pas lancé depuis le CLI)
	Tst.l	$ac(a3)
	Bne.w	M_NoWorkbench

*						  REPEAT                                                                 REPETER
M_WaitWbMsg:
*	Move.l	ExecBase,a6			    ! := WaitPort (OwnTask.pr_MsgPort);                                    Attendre sur le port de la tâche
*	Move.l	OwnTask,a3
	Lea	$5c(a3),a0
	Jsr	WaitPort(a6)

*	Move.l	ExecBase,a6			    WbMsg := GetMsg (OwnTask.pr_MsgPort);                                  WbMsg := message du workbench
*	Move.l	OwnTask,a3
	Lea	$5c(a3),a0
	Jsr	GetMsg(a6)
	Move.l	d0,WbMsg

*	Tst.l	d0
*	Tst.l	WbMsg				  UNTIL  (WbMsg # NIL);                                                  JUSQU'À CE QUE  (WbMsg soit valide)
	Beq.s	M_WaitWbMsg

	Move.l	ExecBase,a6			  ReplyMsg (WbMsg);                                                      Rendre le message au workbench
	Move.l	WbMsg(pc),a1
	Jsr	ReplyMsg(a6)

	Moveq	#0,d0				  ABORT;
	Movem.l	(a7)+,a3/a6
	Rts
M_NoWorkbench:
*						END;                                                                   FIN


*	Move.l	ExecBase,a6			Forbid ();                                                             Interdire la commutation des tâches
	Jsr	Forbid(a6)

*	Move.l	ExecBase,a6			OldPort := FindPort (PortNamePtr);                                     Voir si le patch est déjà installé
	Lea	PortNamePtr(pc),a1
	Jsr	FindPort(a6)
	Move.l	d0,OldPort

*	Move.l	ExecBase,a6			Permit ();                                                             Autoriser la commutation des tâches
	Jsr	Permit(a6)

	Tst.l	OldPort				IF  (OldPort=NIL)  THEN                                                SI  (le patch n'est pas encore installé)
	Bne.w	M_NoMsgPort

*	Move.l	ExecBase,a6			  SigBit := AllocSignal (-1);
	Moveq	#-1,d0
	Jsr	AllocSignal(a6)
	Move.b	d0,SigBit

	Cmp.b	#$FF,d0
*	Cmp.b	#$FF,SigBit			  IF  NOT (SigBit=-1)  THEN                                              Allouer un signal
	Beq.w	M_NoSignal                                                                                               SI  (l'allocation du signal a fonctionné)

	Lea	MsgPort(pc),a0                                                                                             Installer le port de message
	Move.b	SigBit(pc),15(a0)		    MsgPort.mp_SigBit := SigBit;                                           Bit de signal
	Move.l	OwnTask(pc),16(a0)		    MsgPort.mp_SigTask := OwnTask;                                         Signaler notre propre tâche

*	Move.l	ExecBase,a6			    AddPort (MsgPort);                                                     Rendre le port public (visible des autres tâches)
	Lea	MsgPort(pc),a1
	Jsr	AddPort(a6)

*	Move.l	ExecBase,a6			    IntuitionBase := OpenLibrary (ADR(IntuitionName),36);                  Ouvrir la librairie Intuition
	Lea	IntuitionName(pc),a1
	Moveq	#36,d0
	Jsr	OpenLibrary(a6)
	Move.l	d0,IntuitionBase

	Tst.l	d0
*	Tst.l	IntuitionBase			    IF  (IntuitionBase#NIL)  THEN                                          SI  (l'ouverture de la librairie a fonctionné)
	Beq.w	M_NoIntuition

*	Move.l	ExecBase,a6			      OldFunction := SetFunction (IntuitionBase, -$004e, ADR(NewFunction));  Installer la nouvelle fonction
	Move.l	d0,a1
*	Move.l	IntuitionBase,a1
	Suba.l	a0,a0
	Move.w	#-$004e,a0
	Move.l	#NewFunction,d0
	Jsr	SetFunction(a6)
	Move.l	d0,OldFunction

*						      DO                                                                     FAIRE
Forever:
*	Move.l	ExecBase,a6			        ! := WaitPort (MsgPort);                                               Attendre un message de l'éventuelle autre tâche
	Lea	MsgPort(pc),a0
	Jsr	WaitPort(a6)

*	Move.l	ExecBase,a6			        ! := GetMsg (MsgPort);                                                 Prendre le message
	Lea	MsgPort(pc),a0
	Jsr	GetMsg(a6)

	Eor.b	#$FF,Active			        Active := NOT (Active);                                                Inverser l'état d'activation du patch

	Lea	M_EasyStruct(pc),a1
	Move.l	#ActiveText,12(a1)		        M_EasyStruct.Text := ActiveText                                        Texte de la requête := ActiveText
	Move.l	#OkGadgets,16(a1)		        M_EasyStruct.Gadgets := OkGadgets                                      Gadgets de la requête := OkGadgets

	Tst.b	Active				        IF  (Active=FALSE)  THEN                                               SI  (le patch n'est pas actif)
	Bne.s	M_Inactive
	Move.l	#InactiveText,12(a1)		          M_EasyStruct.Text := InactiveText                                      Texte de la requête := InactiveText
M_Inactive:
*						        END;                                                                   FIN

	Movem.l	a2/a3/a6,-(a7)
	Move.l	IntuitionBase(pc),a6
	Suba.l	a2,a2						(IDCMP_Ptr)
*	Suba.l	a3,a3						(ArgList)
	Move.l	a2,a3
*	Suba.l	a0,a0						(Window)
	Move.l	a3,a0
	Jsr	EasyRequestArgs(a6)		        ! := EasyRequestArgs(NIL, M_EasyStruct, NIL, NIL)                      Afficher la requête
	Movem.l	(a7)+,a2/a3/a6

	Bra.s	Forever				      LOOP                                                                   INDÉFINIMENT

*	Move.l	ExecBase,a6			      CloseLibrary (IntuitionBase);                                          Fermer la librairie Intuition
	Move.l	IntuitionBase(pc),a1
	Jsr	CloseLibrary(a6)
M_NoIntuition:
*						    END;                                                                   FIN

*	Move.l	ExecBase,a6			    Forbid ();                                                             Interdire la commutation des tâches
	Jsr	Forbid(a6)

*	Move.l	ExecBase,a6			    RemPort (MsgPort);                                                     Rendre le port de message privé (Invisible des autres tâches)
	Lea	MsgPort(pc),a1
	Jsr	RemPort(a6)

*	Move.l	ExecBase,a6			    Permit ();                                                             Autoriser la commutation des tâches
	Jsr	Permit(a6)

*	Move.l	ExecBase,a6			    FreeSignal (SigBit);                                                   Libérer le bit de signal
	Moveq	#0,d0
	Move.b	SigBit(pc),d0
	Jsr	FreeSignal(a6)

M_NoSignal:
*						  END;                                                                   FIN
	Bra.s	M_NoMsgPortF
M_NoMsgPort:
*						ELSE                                                                   SINON

*	Move.l	ExecBase,a6			  PutMsg (OldPort, Message);                                             Envoyer un message à l'autre tâche
	Move.l	OldPort(pc),a0
	Lea	Message(pc),a1
	Jsr	PutMsg(a6)

M_NoMsgPortF:
*						END;                                                                   FIN

	Moveq	#0,d0				RETURN  M_Return;                                                      Retourner le code d'erreur
	Movem.l	(a7)+,a3/a6
	Rts


**  CONSTANTES GLOBALES  **

Version		dc.b	'$VER: CloseWbPatch 1.1 (14.10.96)',0
CloseWbTitle	dc.b	'CloseWbPatch 1.1 by Burnand Patrick',0


**  CONSTANTES LOCALES  **

IntuitionName	dc.b	'intuition.library',0
PortNamePtr	dc.b	'CloseWbPatch',0
Message		dc.l	0		Message.mn_Node.ln_Succ
		dc.l	0		Message.mn_Node.ln_Pred
		dc.b	0		Message.mn_Node.ln_Type
		dc.b	0		Message.mn_Node.ln_Pri
		dc.l	PortNamePtr	Message.mn_Node.ln_Name
		dc.l	0		Message.mn_ReplyPort
		dc.w	24		Message.mn_Length
		dc.l	-1		Contenu du message
ActiveText	dc.b	'CloseWbPatch is now active !',0
InactiveText	dc.b	'CloseWbPatch is now inactive !',0
OkGadgets	dc.b	'Ok !',0


**  VARIABLES GLOBALES  **

OldFunction	dc.l	0	APTR						Pointeur sur la fonction originale
Active		dc.b	$FF	BOOLEAN						Initialisé à FALSE


**  VARIABLES LOCALES  **

MsgPort		dc.l	0		MsgPort.mp_Node.ln_Succ
		dc.l	0		MsgPort.mp_Node.ln_Pred
		dc.b	4		MsgPort.mp_Node.ln_Type = NT_MSGPORT
		dc.b	0		MsgPort.mp_Node.ln_Pri = 0
		dc.l	PortNamePtr	MsgPort.mp_Node.ln_Name = PortNamePtr
		dc.b	0		MsgPort.mp_Flags = PA_SIGNAL
		dc.b	0		MsgPort.mp_SigBit
		dc.l	0		MsgPort.mp_SigTask
		dc.l	0		MsgPort.mp_MsgList
		dc.l	0		...
		dc.l	0		...
		dc.w	0		...
M_EasyStruct	dc.l	20		sizeof(EasyStruct)
		dc.l	0		Flags
		dc.l	CloseWbTitle	Title
		dc.l	0		TextFormat
		dc.l	0		GadgetFormat
OwnTask		dc.l	0		APTR		Exec.TaskPtr
ActualPri	dc.b	0		BYTE
SigBit		dc.b	0		BYTE		Exec.SignalBit
		dc.b	0
OldPort		dc.l	0		APTR		Exec.MsgPortPtr
IntuitionBase	dc.l	0		APTR		Intuition.LibraryBasePtr
WbMsg		dc.l	0		APTR		Exec.MessagePtr







** NewFunction (): BOOLEAN

** 1.1


**  PARAMETRES  **

* Entree:
* Sortie:
*	BOOLEAN		TRUE si le workbench a été fermé.  FALSE sinon.


**  CONSTANTES GLOBALES  **

TaskNameMaxLen	EQU	30


**  PROCÉDURES EXTERNES  **

WBenchToFront	EQU	-$0156		Intuition.WBenchToFront () ()
WBenchToBack	EQU	-$0150		Intuition.WBenchToBack () ()
EasyRequestArgs	EQU	-$024c


**  CODE  **

	XDEF	NewFunction

NewFunction:
	Tst.b	Active				IF  (Active=TRUE)  THEN                                                SI  (le patch est actif)
	Beq.w	NF_Inactive

	Jsr	WBenchToFront(a6)		  IF  (WBenchToFront()=TRUE)  THEN                                       Mettre l'écran du Workbench en avant-plan
	Tst.b	d0                                                                                                       SI  (l'écran du workbench existe)
	Beq.w	NF_NoWorkbench

	Move.l	a6,-(a7)
	Move.l	ExecBase,a6			    ! := FindTask (NIL);                                                   ! := pointeur sur la tâche courante
	Suba.l	a1,a1
	Jsr	FindTask(a6)
	Move.l	(a7)+,a6

	Lea	CloseWbText0(pc),a0						Générer chaîne à afficher
	Lea	CloseWbText(pc),a1
NF_CpLoop1:
	Move.b	(a0)+,(a1)+
	Bne.s	NF_CpLoop1
	Subq.w	#1,a1

	Move.l	d0,a0								Ajouter le nom de la tâche
	Move.l	10(a0),a0							Copier # chars maxi
	Move.b	#TaskNameMaxLen,d0
NF_CpLoop2:
	Subq.b	#1,d0
	Beq.s	NF_CpLoop2_O
	Move.b	(a0)+,(a1)+
	Bne.s	NF_CpLoop2
	Subq.w	#1,a1
NF_CpLoop2_O:

	Lea	CloseWbText1(pc),a0						Ajouter fin du txt
NF_CpLoop3:
	Move.b	(a0)+,(a1)+
	Bne.s	NF_CpLoop3

	Movem.l	a2/a3,-(a7)
	Lea	NF_EasyStruct(pc),a1			(EasyStruct)
	Move.l	#CloseWbText,12(a1)		    NF_EasyStruct.Text := CloseWbText1                                     Texte de la requête := CloseWbText1
	Move.l	#CloseWbGadgets1,16(a1)		    NF_EasyStruct.Gadgets := CloseWbGadgets1                               Gadgets de la requête := CloseWbGadgets1
	Suba.l	a2,a2					(IDCMP_Ptr)
*	Suba.l	a3,a3					(ArgList)
	Move.l	a2,a3
*	Suba.l	a0,a0					(Window)
	Move.l	a3,a0
	Jsr	EasyRequestArgs(a6)		    IF  (EasyRequestArgs(NIL, NF_EasyStruct, NIL, NIL) = 0)  THEN          Afficher la requête
	Movem.l	(a7)+,a2/a3                                                                                                SI  (l'utilisateur sélectionne non)
	Tst.b	d0
	Bne.s	NF_Yes

	Move.b	#0,NF_Return			      NF_Return := FALSE;                                                    Le code de retour est faux  (écran n'a pas pu être fermé)

	Bra.s	NF_No				    ELSE                                                                   SINON
NF_Yes:
NF_Loop:
*						      REPEAT                                                                 REPETER
	Move.l	OldFunction(pc),a0		        Flag := OldFunction();                                                 Essayer de fermer l'écran (en appelant fonction originale)
	Jsr	(a0)                                                                                                           Le Flag égale ce que retourne la fonction originale
	Move.b	d0,Flag
*	Move.b	Flag,NF_Return			        NF_Return := Flag;                                                     Le code de retour égale le Flag
	Move.b	d0,NF_Return

*	Tst.b	Flag				        IF  (Flag=FALSE)  THEN                                                 SI  (le Flag=FALSE)
	Tst.b	d0
	Bne.s	NF_FlagOk

	Movem.l	a2/a3,-(a7)
	Lea	NF_EasyStruct(pc),a1				(EasyStruct)
	Move.l	#CloseWbText2,12(a1)		          NF_EasyStruct.Text := CloseWbText2                                     Texte de la requête := CloseWbText2
	Move.l	#CloseWbGadgets2,16(a1)		          NF_EasyStruct.Gadgets := CloseWbGadgets2                               Gadgets de la requête := CloseWbGadgets2
	Suba.l	a2,a2						(IDCMP_Ptr)
*	Suba.l	a3,a3						(ArgList)
	Move.l	a2,a3
*	Suba.l	a0,a0						(Window)
	Move.l	a3,a0
	Jsr	EasyRequestArgs(a6)		          IF  (EasyRequestArgs(NIL, NF_EasyStruct, NIL, NIL)=0)  THEN            Afficher la requête
	Movem.l	(a7)+,a2/a3                                                                                                      SI  (la requête retourne faux)
	Tst.b	d0
	Bne.s	NF_Retry

	Eor.b	#$FF,Flag			            Flag := TRUE;                                                          Le Flag égale TRUE
*						          END;                                                                   FIN
NF_Retry:
*						        END;                                                                   FIN
NF_FlagOk:
	Tst.b	Flag				      UNTIL  (Flag=TRUE);                                                    JUSQU'À CE QUE  (le Flag=TRUE)
	Beq.s	NF_Loop

NF_No:
*						    END;                                                                   FIN

	Bra.s	NF_NoWorkbenchF			  ELSE                                                                   SINON
NF_NoWorkbench:
	Move.b	#0,NF_Return			    NF_Return := FALSE;                                                    Le code de retour est faux  (écran non-présent)
NF_NoWorkbenchF:
*						  END;                                                                   FIN

	Bra.s	NF_InactiveF
NF_Inactive:
*						ELSE                                                                   SINON

	Move.l	OldFunction(pc),a0		  NF_Return := OldFunction();                                            Essayer de fermer l'écran (en appelant fonction originale)
	Jsr	(a0)                                                                                                     Le code de retour égale ce que retourne la fonction originale
	Move.b	d0,NF_Return

NF_InactiveF:
*						END;                                                                   FIN

	Moveq	#0,d0				RETURN NF_Return;                                                      Retourner le code de retour
	Move.b	NF_Return(pc),d0
	Rts


**  VARIABLES GLOBALES  **

*	XREF	OldFunction
*	XREF	Active


**  CONSTANTES LOCALES  **

CloseWbText0	dc.b	'The task named "',0
CloseWbText0F
CloseWbText1	dc.b	'" wants',10
		dc.b	"to close the Workbench screen...",0
CloseWbText1F
CloseWbGadgets1	dc.b	"Allow closing|Don't close",0
CloseWbText2	dc.b	"Unable to close the Workbench screen.",10
		dc.b	"Close all the non-Workbench windows.",0
CloseWbGadgets2	dc.b	'Retry|Cancel',0


**  VARIABLES LOCALES  **

Flag		dc.b	0	BOOLEAN						Initialisé à FALSE
NF_Return	dc.b	0	BOOLEAN						Initialisé à FALSE
NF_EasyStruct	dc.l	20		sizeof(EasyStruct)
		dc.l	0		Flags
		dc.l	CloseWbTitle	Title
		dc.l	0		TextFormat
		dc.l	0		GadgetFormat

CloseWbText:	ds.b	(CloseWbText0F-CloseWbText0)+(CloseWbText1F-CloseWbText1)+TaskNameMaxLen+2
*						Buffer pour chaîne à afficher

	End
