Suivez-nous sur X

|
|
|
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
|
|
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
|
|
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
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
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 :
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
|
|