Obligement - L'Amiga au maximum

Vendredi 06 juin 2025 - 12:25  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

Actualité (récente)
Actualité (archive)
Comparatifs
Dossiers
Entrevues
Matériel (tests)
Matériel (bidouilles)
Points de vue
En pratique
Programmation
Reportages
Quizz
Tests de jeux
Tests de logiciels
Tests de compilations
Trucs et astuces
Articles divers

Articles in English


Réseaux sociaux

Suivez-nous sur X




Liste des jeux Amiga

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z,
ALL


Trucs et astuces

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Glossaire

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Galeries

Menu des galeries

BD d'Amiga Spécial
Caricatures Dudai
Caricatures Jet d'ail
Diagrammes de Jay Miner
Images insolites
Fin de jeux (de A à E)
Fin de Jeux (de F à O)
Fin de jeux (de P à Z)
Galerie de Mike Dafunk
Logos d'Obligement
Pubs pour matériels
Systèmes d'exploitation
Trombinoscope Alchimie 7
Vidéos


Téléchargement

Documents
Jeux
Logiciels
Magazines
Divers


Liens

Associations
Jeux
Logiciels
Matériel
Magazines et médias
Pages personnelles
Réparateurs
Revendeurs
Scène démo
Sites de téléchargement
Divers


Partenaires

Annuaire Amiga

Amedia Computer

Relec


A Propos

A propos d'Obligement

A Propos


Contact

David Brunet

Courriel

 


Programmation : Assembleur - BigCLI, la création d'un Shell plein écran
(Article écrit par Max et extrait d'Amiga News Tech - janvier 1992)


Si vous avez la nostalgie des anciens ordinateurs dont le Shell était plein écran, BigCLI est fait pour vous...

BigCLI est un petit utilitaire très simple à réaliser, qui permet d'ouvrir chaque nouveau CLI ou Shell dans son propre écran - au sens Intuition du terme - et non dans une fenêtre sur le Workbench. Et quand je dis très simple à réaliser, je le pense vraiment. C'est tellement simple, que je m'étonne que personne ne l'ai fait avant (en tout cas, pas à ma connaissance).

Comment ça marche

La démarche que j'ai suivie n'est peut-être pas la plus orthodoxe qui soit. J'en discutais encore récemment avec Frédéric Mazué, qui avait, lui, trouvé le moyen de détourner un Shell sur n'importe quelle fenêtre Intuition déjà ouverte (imaginez le résultat d'un Dir au beau milieu de votre dessin Deluxe Paint !). A son humble avis de pourfendeur de bogues devant l'Éternel, ma méthode n'est pas très sûre et peut planter dans certaines conditions, qu'il reste d'ailleurs à définir... Rassurez-vous, malgré tous les essais auxquels je me suis livré, je n'ai encore jamais réussi à provoquer le moindre Guru. BigCLI est donc un programme sûr à 99% (bien que je n'aie pu le tester en Worbench 2.0).

La méthode en question consiste ni plus ni moins à détourner le vecteur OpenWindow() de la bibliothèque Intuition, de telle sorte que chaque fois que le Shell essaie d'ouvrir une nouvelle fenêtre, un écran particulier soit d'abord ouvert, qui accueillera ladite fenêtre. Cela suppose également, bien sûr, de détourner CloseWindow() afin de refermer cet écran en même temps que la fenêtre lors du EndCLI final.

Reste à savoir comment déterminer si c'est un Shell qui essaie d'ouvrir une nouvelle fenêtre, ou bien une application quelconque. Après maintes tentatives et étant donné la manière dont AmigaDOS gère l'ouverture d'une nouvelle console (à travers CreateTask() d'Exec), je me suis finalement décidé pour une petite astuce qui ne paye pas de mine : c'est le titre de la nouvelle fenêtre qui déterminera sa provenance. En d'autres termes, si la fenêtre à ouvrir possède un titre particulier, on assumera qu'il s'agit d'une fenêtre Shell, donc à ouvrir dans un écran propre.

Afin d'éviter tout risque de conflit, ce titre a été choisi avec soin. Il s'agit de __BigCLI__, avec deux soulignés de part et d'autre, les majuscules étant différenciées des minuscules.

Le problème se pose à nouveau lorsque, après un EndCLI vindicatif, le Shell veut refermer sa fenêtre : comment savoir s'il faut également fermer l'écran supplémentaire ouvert précédemment ? Là encore, la solution est simple : on utilisera le champ UserData de la structure Window associée à chaque fenêtre. Normalement, ce champ contient un pointeur sur des données propres au propriétaire de la fenêtre, s'il en a besoin. CON: ne l'utilisant pas, nous y inscrivons simplement une marque de reconnaissance. Dans notre propre routine CloseWindow(), ce champ est testé et, si la marque est reconnue, l'écran est fermé en même temps que la fenêtre.

Installation

Copiez le programme BigCLI_Inst dans votre répertoire C: et ajoutez dans votre startup-sequence, à l'endroit de votre choix (généralement juste avant la commande LoadWB), la ligne :

BigCLI_Inst

Notez qu'il n'est pas utile de spécifier "Run" ou un équivalent, le programme incorporant une version simplifiée de BackStart.i de Frédéric Mazué, qui permet de lancer un programme en tâche de fond et de rendre immédiatement la main au CLI appelant.

Si l'installation s'est correctement effectuée, un petit message vous en prévient.

Une fois le gestionnaire principal installé, le meilleur moyen d'invoquer BigCLI est encore d'insérer la ligne suivante dans le fichier shell-startup de votre répertoire "S" :

Alias BigCLI NewShell NewCON://// __BigCLI__

Ainsi, en tapant simplement BigCLI, vous obtiendrez un nouveau Shell plein écran. Les aficionados du Workbench pourront également mettre dans la partie "ToolTypes" de l'icône du Shell.

WINDOW.NewCON://// __BigCLI__

Pour supprimer le gestionnaire BigCLI de la mémoire, il suffit de lancer une seconde fois BigCLI_Inst, ou de lui envoyer, au moyen de la commande Break, un "Ctrl-F" bien placé entre les deux yeux.

Une dernière note pour finir : si toutes les commandes CLI (Dir, Copy, etc.) s'affichent bel et bien dans notre écran, les programmes qui demandent explicitement une fenêtre Workbench ne sont pas détournés. Par exemple, si vous lancez More depuis une fenêtre BigCLI, sa fenêtre s'ouvrira de toute manière sur l'écran du Workbench. Et ça, on ne peut rien y faire.

;
; BigCLI v1.1 - (c) Max pour ANT.
;
	opt	o+,ow-

	incdir	"Include:"

	include	"exec/tasks.i"
	include	"exec/ports.i"
	include	"exec/execbase.i"
	include	"intuition/intuition.i"
	include	"libraries/dos.i"
	include	"libraries/dosextens.i"

	include	"exec/exec_lib.i"
	include	"intuition/intuition_lib.i"
	include	"libraries/dos_lib.i"

; ************************************
CALLSYS	MACRO		; Petite macro très très pratique
	IFNC	'','\2'	; piquée à Loïc Far. Merci Loïc !
	movea.l	\2,a6
	ENDC
	jsr	_LVO\1(a6)
	ENDM

EXEC	MACRO
	CALLSYS	\1,$4.w
	ENDM

DOS	MACRO
	CALLSYS	\1,DosBase(a5)
	ENDM

INT	MACRO
	CALLSYS	\1,IntBase(a5)
	ENDM

; ************************************
	rsreset
MsgPort	rs.b	MP_SIZE	; MsgPort standard
DosBase	rs.l	1	; DOSBase
IntBase	rs.l	1	; IntuitionBase
OpenW	rs.l	1	; Ancien vecteur OpenWindow()
CloseW	rs.l	1	; Ancien vecteur CloseWindow()
count	rs.w	1	; Compteur d'écrans
VARSIZE	rs.w	0

NSFLAGS	EQU	CUSTOMSCREEN

NWFLAGS	SET	BACKDROP|BORDERLESS|RMBTRAP|ACTIVATE
NWFLAGS	SET	NWFLAGS|SIMPLE_REFRESH|NOCAREREFRESH

MARQUE	EQU	'MAX!'

; ************************************
; Version simplifiée de BackStart.i par F. Mazué.
;
; - ne sauve pas les arguments vu qu'on s'en sert pas
; - n'ouvre pas le console ('*') vu qu'on sert pas
; - ne gère pas le lancement depuis le Workbench !!
;
; ************************************

	section BackStart,code

RunBack	lea	dosname,a1	; Ouvre la dos.library
	moveq	#0,d0
	EXEC	OpenLibrary
	move.l	d0,d7
	beq.s	.nodos

	lea	RunBack(pc),a0	; Début du programme dans a0
	move.l	-(a0),d3	; Segment pour CreateProc()
	clr.l	(a0)		; coupé de la liste

	suba.l	a1,a1		; Où suis-je ?
	CALLSYS	FindTask
	movea.l	d0,a0
	movea.l	pr_CLI(a0),a0
	adda.l	a0,a0		; Conversion BCPL
	adda.l	a0,a0
	movea.l	cli_Module(a0),a0
	adda.l	a0,a0		; Conversion BCPL
	adda.l	a0,a0
	clr.l	(a0)		; Coupé du CLI !

	move.l	#myname,d1	; Nom du nouveau Process
	moveq	#0,d2		; sa priorité
	move.l	#4000,d4	; taille de sa pile
	movea.l	d7,a6
	CALLSYS	CreateProc	; Process créé (d3 est déjà ok)

	movea.l	$4.w,a1
	exg	a1,a6
	CALLSYS	CloseLibrary	; Referme la dos.library

	moveq	#0,d0
.nodos	rts

; ************************************
	section MainProg,code	; INDISPENSABLE !!

Start	lea	VARS(pc),a5

	lea	dosname(pc),a1
	moveq	#33,d0
	EXEC	OpenLibrary
	move.l	d0,DosBase(a5)
	beq	NoDos

	lea	intname(pc),a1
	moveq	#33,d0
	CALLSYS	OpenLibrary
	move.l	d0,IntBase(a5)
	beq	NoInt

	lea	myname(pc),a1	; On est déjà présent ?
	CALLSYS	FindPort
	tst.l	d0
	beq.s	Install

	movea.l	d0,a1		; Si oui, on se signale de quitter.
	movea.l	MP_SIGTASK(a1),a1
	move.l	#SIGBREAKF_CTRL_F,d0
	CALLSYS	Signal
	bra	Exit

; ************************************
Install	lea	MsgPort(a5),a1
	move.b	#NT_MSGPORT,MP+LN_TYPE(a1)
	move.l	#myname,MP+LN_NAME(a1)
	move.b	#PA_IGNORE,MP_FLAGS(a1)
	move.l	ThisTask(a6),MP_SIGTASK(a1)
	CALLSYS	AddPort

	; Ici, on recherche les informations sur l'écran du WB
	; afin de pouvoir ouvrir un écran identique pour chaque
	; nouveau Shell lancé.
	lea	-sc_SIZEOF(sp),sp	; sizeof(struct Screen)
	movea.l	sp,a0
	suba.l	a1,a1
	move.l	#sc_SIZEOF,d0
	moveq	#WBENCHSCREEN,d1
	INT	GetScreenData

	; Copie les paramètres de l'écran du WB
	; dans notre propre structure NewScreen.
	lea	ns(pc),a1
	move.w	sc_Width(sp),ns_Width(a1)
	move.w	sc_Height(sp),ns_Height(a1)
	move.w	sc_ViewPort+vp_Modes(sp),d0
	andi.w	#(V_HIRES|V_LACE),d0
	move.w	d0,ns_ViewModes(a1)
	lea	sc_SIZEOF(sp),sp

	; Détourne les vecteurs OpenWindow() et CloseWindow().
	EXEC	Forbid

	movea.l	IntBase(a5),a1
	lea	(_LVOOpenWindow).w,a0
	move.l	#NewOpenWindow,d0
	CALLSYS	SetFunction
	move.l	d0,OpenW(a5)	; Sauve l'ancien vecteur

	movea.l	IntBase(a5),a1
	lea	(_LVOCloseWindow).w,a0
	move.l	#NewCloseWindow,d0
	CALLSYS	SetFunction
	move.l	d0,CloseW(a5)	; Sauve l'ancien vecteur

	CALLSYS	Permit

	; Prévient l'utilisateur qu'on est installé.
	lea	ontxt(pc),a0
	bsr	ShowReq

	; Ok, on a fini, il ne reste plus qu'à attendre qu'on
	; nous demande de quitter.
WaitEnd	move.l	#SIGBREAKF_CTRL_F,d0
	EXEC	Wait

	; Reste-t-il des écrans BigCLI ouverts ?
	tst.w	count(a5)
	beq.s	Remove

	; Si oui, on affiche un Requester maison
	suba.l	a0,a0
	lea	autoreq(pc),a1
	lea	button1(pc),a2
	lea	button2(pc),a3
	moveq	#0,d0
	moveq	#0,d1
	move.l	#320,d2
	moveq	#90,d3
	INT	AutoRequest
	tst.l	d0
	beq.s	WaitEnd

	; Si on quitte quand même alors qu'il reste un (des)
	; écran(s) ouvert(s), il(s) ne sera(ont) jamais fermé(s) !

	; Restaure les vecteurs OpenWindow() et CloseWindow().
Remove	EXEC	Forbid
	movea.l	IntBase(a5),a1
	lea	(_LVOCloseWindow).w,a0
	move.l	CloseW(a5),d0
	CALLSYS	SetFunction

	movea.l	IntBase(a5),a1
	lea	(_LVOOpenWindow).w,a0
	move.l	OpenW(a5),d0
	CALLSYS	SetFunction

	CALLSYS	Permit

	; Supprime notre MsgPort
	lea	MsgPort(a5),a1
	CALLSYS	RemPort

	lea	offtxt(pc),a0
	bsr.s	ShowReq

	; Ferme l'intuition.library
Exit	movea.l	IntBase(a5),a1
	EXEC	CloseLibrary

NoInt	movea.l	DosBase(a5),a1
	CALLSYS	CloseLibrary

	; Retour au CLI/Shell
NoDos	moveq	#0,d0
	rts

; ************************************
ShowReq	move.l	a0,-(sp)

	lea	nwreq(pc),a0

	move.w	ns+ns_Width(pc),d0	; Centre le requester
	sub.w	nw_Width(a0),d0		; dans le WB
	asr.w	#1,d0
	move.w	d0,nw_LeftEdge(a0)

	move.w	ns+ns_Height(pc),d0
	sub.w	nw_Height(a0),d0
	asr.w	#1,d0
	move.w	d0,nw_TopEdge(a0)

	INT	OpenWindow
	move.l	d0,d2
	beq.s	.noreq

	lea	request(pc),a0
	move.l	(sp),rq_ReqText(a0)
	movea.l	d2,a1
	CALLSYS	Request

	moveq	#1*TICKS_PER_SECOND,d1
	DOS	Delay

	lea	request(pc),a0
	movea.l	d2,a1
	INT	EndRequest

	movea.l	d2,a0
	CALLSYS	CloseWindow

.noreq	addq.l	#4,sp
	rts

; ************************************
NewOpenWindow:
	movem.l	d2-d3/a2-a6,-(sp)

	lea	VARS(pc),a5	; a5 = nos variables
	movea.l	a0,a3		; a3 = NewWindow

	move.l	nw_Title(a0),d0	; Adresse du titre
	beq	.normal

	movea.l	d0,a0		; Compare le titre de la
	lea	.title(pc),a1	; nouvelle fenêtre
.cmp	cmpm.b	(a0)+,(a1)+	; à 'BigCLI'.
	bne	.normal		; C'est une fenêtre normale...
	tst.b	-1(a0)
	bne.s	.cmp

	; On est obligé d'utiliser une COPIE de la structure
	; NewScreen si on veut rester ré-entrant, c'est-à-dire
	; pouvoir être appelé par plusieurs programmes à la fois.
	lea	-ns_SIZEOF(sp),sp
	lea	ns(pc),a0
	movea.l	sp,a1
	moveq	#ns_SIZEOF-1,d0
.copy	move.b	(a0)+,(a1)+
	dbra	d0,.copy

	movea.l	sp,a0		; Ouvre l'écran
	CALLSYS	OpenScreen
	lea	ns_SIZEOF(sp),sp
	move.l	d0,nw_Screen(a3)
	beq.s	.rate1

	; Modifie la structure NewWindow de la fenêtre à ouvrir,
	; de sorte qu'elle s'accomode le mieux possible à l'écran.
	movea.l	d0,a0
	move.b	sc_BarHeight(a0),d0
	ext.w	d0
	addq.w	#1,d0

	move.w	sc_LeftEdge(a0),nw_LeftEdge(a3)
	move.w	sc_TopEdge(a0),nw_TopEdge(a3)
	add.w	d0,nw_TopEdge(a3)
	move.w	sc_Width(a0),nw_Width(a3)
	move.w	sc_Height(a0),nw_Height(a3)
	sub.w	d0,nw_Height(a3)
	move.l	#NWFLAGS,nw_Flags(a3)
	clr.l	nw_Title(a3)
	move.w	#CUSTOMSCREEN,nw_Type(a3)

	; Ok, on peut essayer d'ouvrir la fenêtre...
	movea.l	a3,a0
	movea.l	OpenW(a5),a2
	jsr	(a2)	; Saut à l'ancien vecteur OpenWindow().
	move.l	d0,d2
	beq.s	.rate2

	; On marque la fenêtre comme ouverte par BigCLI.
	movea.l	d2,a0
	move.l	#MARQUE,wd_UserData(a0)

	; Incrémente le compteur et retour au programme appelant.
	addq.w	#1,count(a5)
	move.l	d2,d0		; Adresse de la fenêtre dans d0
	movem.l	(sp)+,d2-d3/a2-a6
	rts

	; Procédures d'erreurs
.rate2	movea.l	nw_Screen(a3),a0
	CALLSYS	CloseScreen
	moveq	#0,d0
.rate1	movem.l	(sp)+,d2-d3/a2-a6
	rts

	; C'est une fenêtre "normale" (cad. pas BigCLI).
.normal	movea.l	a3,a0
	movea.l	OpenW(a5),a2
	jsr	(a2)	; Saut à l'ancien vecteur OpenWindow()
	movem.l	(sp)+,d2-d3/a2-a6
	rts

.title	dc.b	"__BigCLI__",0
	even

; ************************************
NewCloseWindow:
	movem.l	d2/a3-a6,-(sp)

	lea	VARS(pc),a5	; a5 = nos variables

	movea.l	wd_WScreen(a0),a3
	move.l	wd_UserData(a0),d2

	; Ferme déjà la fenêtre
	movea.l	CloseW(a5),a1
	jsr	(a1)	; Saut à l'ancien vecteur CloseWindow()

	; C'était une fenêtre BigCLI ?
	cmpi.l	#MARQUE,d2
	bne.s	.ret

	; Si oui, ferme aussi l'écran
	movea.l	a3,a0
	CALLSYS	CloseScreen

	; Et décrémente le compteur
	subq.w	#1,count(a5)

.ret	movem.l	(sp)+,d2/a3-a6
	rts

; ************************************
VARS	dcb.b	VARSIZE
dosname	dc.b	"dos.library",0
intname	dc.b	"intuition.library",0
myname	dc.b	"BigCLI v1.1 - © Max pour ANT",0
	even

	; Structure NewScreen utilisée pour ouvrir les écrans.
ns	dc.w	0,0,640,256,2
	dc.b	0,1
	dc.w	V_HIRES,NSFLAGS
	dc.l	0,0,0,0

	; Requester pour dire quand on s'intalle...
nwreq	dc.w	0,0,250,40
	dc.b	-1,-1
	dc.l	0,SIMPLE_REFRESH|NOCAREREFRESH ;|BORDERLESS
	dc.l	0,0,0,0,0
	dc.w	0,0,0,0
	dc.w	WBENCHSCREEN

request	dc.l	0
	dc.w	4,2,246,38,0,0
	dc.l	0,0,0
	dc.w	0
	dc.b	1,0
	dc.l	0
	dcb.b	32,0
	dc.l	0,0
	dcb.b	36,0

topazi	dc.l	.name
	dc.w	8
	dc.b	FSF_ITALIC,FPF_ROMFONT
.name	dc.b	"topaz.font",0
	even

ontxt	dc.b	2,0,RP_JAM1,0
	dc.w	10,25
	dc.l	topazi,.txt,maxtxt
.txt	dc.b	"BigCLI installé.",0
	even

offtxt	dc.b	2,0,RP_JAM1,0
	dc.w	10,25
	dc.l	topazi,.txt,maxtxt
.txt	dc.b	"BigCLI supprimé.",0
	even

maxtxt	dc.b	3,0,RP_JAM1,0
	dc.w	10,10
	dc.l	0,myname,0
	even

	; S'il reste des écrans ouverts quand on quitte...
autoreq	dc.b	2,1,RP_JAM1,0
	dc.w	16,6
	dc.l	0,.txt1,.req2
.txt1	dc.b	"Attention !",0
	even

.req2	dc.b	2,1,RP_JAM1,0
	dc.w	16,16
	dc.l	0,.txt2,.req3
.txt2	dc.b	"Un ou plusieurs écrans BigCLI",0
	even

.req3	dc.b	2,1,RP_JAM1,0
	dc.w	16,26
	dc.l	0,.txt3,.req4
.txt3	dc.b	"sont encore ouverts.",0
	even

.req4	dc.b	2,1,RP_JAM1,0
	dc.w	16,41
	dc.l	0,.txt4,0
.txt4	dc.b	"Quitter quand même ?",0
	even

button1	dc.b	2,1,RP_JAM1,0
	dc.w	6,3
	dc.l	0,.but1,0
.but1	dc.b	"Quitter",0
	even

button2	dc.b	2,1,RP_JAM1,0
	dc.w	6,3
	dc.l	0,.but2,0
.but2	dc.b	"Annuler",0
	even

; ************************************
	END


[Retour en haut] / [Retour aux articles]