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 : C - Créer un super Shell avec menu Intuition
(Article écrit par Frédéric Mazué et extrait d'Amiga News Tech - avril 1991)
|
|
Je vous propose aujourd'hui d'allier la convivialité du Workbench avec la rigueur du Shell. Comment ?
Tout simplement en ajoutant un menu Intuition aux fenêtres Shell (ou CLI, cela s'entend). Ceci
nous permettra d'utiliser depuis le Shell tous les raccourcis clavier que l'on voudra, avec en plus
une option spécial fainéants : le seul fait d'insérer une disquette dans un lecteur quelconque en
affichera le catalogue.
Une fenêtre Shell n'est ni plus ni moins qu'une fenêtre Intuition. Notre programme, lancé depuis cette
fenêtre, doit tout d'abord en rechercher le pointeur. C'est très simple : la structure "Process"
de notre programme contient un pointeur sur la console_task associée (le Shell). Il nous suffit d'envoyer
à cette console_task un DosPacket de type ACTION_DISK_INFO avec en arg1, un pointeur sur une structure
InfoData. En retour, on recevra le pointeur de la fenêtre utilisée par la console (pour en savoir plus
sur les DosPacket, vous pouvez vous reporter à l'excellent article
"Mettez un silencieux dans vos lecteurs de disquette").
Cette fenêtre, comme quelques essais permettent de s'en convaincre, n'utilise aucun drapeau IDCMP et ne
comporte donc pas de port utilisateur. Il nous faudra donc d'abord créer un port, puis l'attacher à la
fenêtre, modifier les drapeaux IDCMP puis installer le menu. Tout ceci ne mérite pas grandes explications car ce
n'est que l'utilisation de routines système bien connues. Voilà, le menu est installé et nous pouvons déjà
utiliser les raccourcis clavier ainsi définis, afin d'accéder ultra-rapidement à vos outils préférés
(moi c'est Devpac 2 et Genam2/Monam2).
Catalogue automatique
Cela est rendu possible par le fait qu'un message Intuition est généré lorsqu'on insère
une disquette. D'abord, il faut savoir que ce message sera envoyé à la fenêtre que celle-ci
soit active ou pas. Ce sera donc à notre programme d'effectuer ce test en examinant
ActiveWindow d'IntuitionBase.
Les routines qui déterminent dans quel lecteur la disquette a été insérée sont directement
inspirées de VirusX de Steve Tibett. Afin d'éviter le sac de noeuds entre les sorties de
plusieurs programmes, le catalogue est affiché dans une fenêtre DOS spécialement ouverte à
cet effet. L'option catalogue automatique peut être désactivée par le menu.
Rendre la main proprement
Ce programme, écrit avec le Lattice 5.10, doit être relié avec cback.o, de façon à tourner
en tâche de fond. Nous avons donc la situation suivante : deux programmes distincts utilisent
la même console_task. C'est pour cela que vous ne pourrez pas ajouter une option "endcli"
dans le menu.
L'option "quitter" arrête le programme, mais laisse le Shell actif qui
redevient un Shell classique. Si vous faites directement un "endcli" depuis le Shell, la
fenêtre ne sera toutefois pas fermée pour la même raison. Il vous suffira alors d'actionner
"Amiga-Q" (il serait bien sûr possible d'améliorer ceci, mais cela rallongerait considérablement
le listing, donc je préfère vous laisser exercer votre sagacité).
Remarquez toutefois qu'il
est impératif de supprimer tous les messages "pendants" au port de la fenêtre (fonction
SafelyIDCMP) et d'effacer soi-même le port, sinon c'est le gourou assuré.
Utilisation du programme
Il y a deux manières de lier le SuperShell à un Shell standard :
- Par simple appel depuis le Shell.
- Mais vous pouvez aussi le placer au début du fichier Shell-Startup (ou Cli-Startup).
Ainsi, tout Shell ouvert sera automatiquement un SuperShell.
/**************************************************************************/
/* Programme: SuperShell.c */
/* Fonction: Accroche un menu à une fenêtre Shell (ou CLI) */
/* Utilisation: - Appel depuis Shell */
/* - Installation dans le Shell-Startup */
/* ou dans le Cli-Startup */
/* Compilateur: Lattice C 5.10 */
/* Compilation: lc -cist -v -y */
/* Linkage: FROM LIB:cback.o+"SuperShell.o" */
/* TO "SuperShell" */
/* LIB LIB:lc.lib LIB:amiga.lib */
/* NODEBUG */
/* SMALLCODE */
/* SMALLDATA */
/* DEFINE __main=__tinymain */
/* Auteur: F MAZUE pour ANT le 18/12/90 */
/**************************************************************************/
#include <devices/trackdisk.h>
#include <exec/lists.h>
#include <exec/memory.h>
#include <exec/nodes.h>
#include <exec/ports.h>
#include <exec/types.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <string.h>
/**************************************************************************/
/* DECLARATION POUR CBACK */
/**************************************************************************/
extern BPTR _Backstdout;
char *_procname = "SuperShell";
LONG _BackGroundIO = 1;
LONG _stack = 4000;
LONG _priority = 20;
/**************************************************************************/
/* définition du menu qui sera ajouté à la fenêtre CLI */
/**************************************************************************/
struct TextAttr TOPAZ80 =
{
(STRPTR) "topaz.font",
TOPAZ_EIGHTY,
0,
0
};
struct IntuiText AutoText[] =
{
{2, 1, JAM2, 2, 1, NULL, " List ", NULL}
};
struct MenuItem AutoItem[] =
{
/* List */
{
NULL, 0, 0, 0, 0,
ITEMTEXT | ITEMENABLED | HIGHCOMP | CHECKIT | MENUTOGGLE | CHECKED, 0,
(APTR)&AutoText[0], NULL, NULL, NULL, MENUNULL
}
};
struct IntuiText ToolText[] =
{
{2, 1, JAM2, 2, 1, NULL, "Genam2", NULL},
{2, 1, JAM2, 2, 1, NULL, "Monam2", NULL},
{2, 1, JAM2, 2, 1, NULL, "Dpaint", NULL},
{2, 1, JAM2, 2, 1, NULL, "Quitter", NULL}
};
struct MenuItem ToolItem[] =
{
{ /* Genam2 */
&ToolItem[1], 0, 0, 0, 0,
ITEMTEXT | COMMSEQ | ITEMENABLED | HIGHCOMP, 0,
(APTR)&ToolText[0], NULL, 'G', NULL, MENUNULL
},
{ /* Monam2 */
&ToolItem[2], 0, 0, 0, 0,
ITEMTEXT | COMMSEQ | ITEMENABLED | HIGHCOMP, 0,
(APTR)&ToolText[1], NULL, 'M', NULL, MENUNULL
},
{ /* Dpaint */
&ToolItem[3], 0, 10, 0, 0,
ITEMTEXT | COMMSEQ | ITEMENABLED | HIGHCOMP, 0,
(APTR)&ToolText[2], NULL, 'P', NULL, MENUNULL
},
{ /* Quitter */
NULL, 0, 10, 0, 0,
ITEMTEXT | COMMSEQ | ITEMENABLED | HIGHCOMP, 0,
(APTR)&ToolText[3], NULL, 'Q', NULL, MENUNULL
}
};
struct Menu Menus[] =
{
{&Menus[1], 0, 0, 0, 0, MENUENABLED, "Tools", &ToolItem[0]},
{NULL, 80, 0, 0, 0, MENUENABLED, "Auto", &AutoItem[0]}
};
struct Menu *FirstMenu = &Menus[0];
struct IntuiText WinText[] =
{
{3, 0, JAM2, 54, 28, &TOPAZ80, "How to do a Menu", NULL},
{3, 0, JAM2, 70, 38, &TOPAZ80, "(with Style)", &WinText[0]}
};
struct NewWindow NewWindow =
{
202, 66, 234, 66, 2, 1, MENUPICK | CLOSEWINDOW,
WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE | ACTIVATE | NOCAREREFRESH,
NULL, NULL, "Menus", NULL, NULL, 0, 0, -1, -1, WBENCHSCREEN
};
/**************************************************************************/
/* fonctions de gestion du menu */
/**************************************************************************/
BOOL AdjustMenus(struct Menu *, struct TextAttr *);
VOID AdjustItems(struct RastPort *, struct MenuItem *, struct TextAttr *,
USHORT, USHORT, USHORT, USHORT);
VOID AdjustText(struct IntuiText *text, struct TextAttr *attr);
USHORT MaxLength(struct RastPort *, struct MenuItem *, USHORT);
struct IntuiMessage *message;
/**************************************************************************/
/* Pour ces deux fonctions, se reporter aux */
/* RMK Libraries and Devices pages 171 */
/**************************************************************************/
VOID StripIntuiMessages(struct MsgPort *mp, struct Window *win);
VOID IDCMPSafely(struct Window *win);
int handleIDCMP(struct Window *win);
/**************************************************************************/
/* pour recherche du pointeur de fenêtre du CLI courant */
/**************************************************************************/
#define BTOC(bptr) ((long)(bptr) << 2) /* conversion BCPL -> C */
#define CTOB(cptr) ((long)(cptr) >> 2) /* conversion C -> BCPL */
struct Window *GetWindow();
struct Window *CliWindow;
struct MsgPort *WinPort;
struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase *GfxBase = NULL;
/**************************************************************************/
/* pour gestion des drives */
/**************************************************************************/
LONG ChangeCount[4];
struct MsgPort *diskport;
struct IOExtTD *diskreq;
VOID InitDrive();
int DriveNum();
VOID CleanExit();
/**************************************************************************/
/* PROGRAMME PRINCIPAL */
/**************************************************************************/
VOID main()
{
int signal;
int signalmask;
int OK = 0;
if (!(IntuitionBase =
(struct IntuitionBase *)OpenLibrary("intuition.library", 0L)))
CleanExit();
if (!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0L)))
CleanExit();
CliWindow = (struct Window *)GetWindow();
if (!CliWindow) CleanExit();
diskport = (struct MsgPort *)CreatePort(NULL, NULL);
if (!diskport) CleanExit();
diskreq = (struct IOExtTD *)CreateExtIO((struct MsgPort *)diskport, sizeof(struct IOExtTD));
if (!diskreq) CleanExit();
WinPort = (struct MsgPort *)CreatePort(NULL, NULL);
/**********************************************************************/
/* On attache le port nouvellement créé à la fenêtre CLI */
/* Puis on modifie les flags IDCMP de la fenêtre */
/**********************************************************************/
CliWindow->UserPort = WinPort;
ModifyIDCMP(CliWindow, MENUPICK | DISKINSERTED);
SetWindowTitles(CliWindow, "SuperShell par F Mazué", (char *)-1);
RefreshWindowFrame(CliWindow);
InitDrive();
/**********************************************************************/
/* Maintenant, on initialise le menu et on l’attache à la fenêtre CLI */
/**********************************************************************/
AdjustMenus(FirstMenu, CliWindow->WScreen->Font);
SetMenuStrip(CliWindow, FirstMenu);
signalmask = 1L << CliWindow->UserPort->mp_SigBit;
do
{
signal = Wait(signalmask);
if (signal & signalmask) OK = handleIDCMP(CliWindow);
}
while (!OK);
SetWindowTitles(CliWindow, "AmigaShell", (char *)-1);
RefreshWindowFrame(CliWindow);
IDCMPSafely(CliWindow);
ClearMenuStrip(CliWindow);
CleanExit();
}
struct Window *GetWindow() {
struct Process *proc;
struct StandardPacket *packet;
struct InfoData *infodata;
long result;
struct Window *win;
proc = (struct Process *)FindTask(NULL);
if (!proc->pr_ConsoleTask)
return (NULL);
packet = (struct StandardPacket *)AllocMem(sizeof(struct StandardPacket), MEMF_CLEAR | MEMF_PUBLIC);
infodata = (struct InfoData *)AllocMem(sizeof(struct InfoData), MEMF_CLEAR | MEMF_PUBLIC);
packet->sp_Msg.mn_Node.ln_Name = (char *)&(packet->sp_Pkt);
packet->sp_Pkt.dp_Link = &packet->sp_Msg;
packet->sp_Pkt.dp_Port = &proc->pr_MsgPort;
packet->sp_Pkt.dp_Type = ACTION_DISK_INFO;
packet->sp_Pkt.dp_Arg1 = CTOB(infodata);
PutMsg((struct MsgPort *)proc->pr_ConsoleTask, (struct Message *)packet);
WaitPort(&proc->pr_MsgPort);
GetMsg(&proc->pr_MsgPort);
result = packet->sp_Pkt.dp_Res1;
win = (struct Window *)infodata->id_VolumeNode;
FreeMem(packet, sizeof(struct StandardPacket));
FreeMem(infodata, sizeof(struct InfoData));
if (!result) return (NULL);
return (win);
}
BOOL AdjustMenus(struct Menu *firstmenu, struct TextAttr *attr) {
struct RastPort textrp = {0};
struct Menu *menu;
struct TextFont *font;
USHORT start, width, height, space;
BOOL retval = FALSE;
if ((font = (struct TextFont *)OpenFont(attr))) {
SetFont(&textrp, font);
width = font->tf_XSize;
height = (font->tf_YSize < 8) ? 8 : font->tf_YSize;
height++;
start = 2;
menu = firstmenu;
while (menu)
{
menu->LeftEdge = start;
menu->Width = space =
TextLength(&textrp, menu->MenuName, (LONG)strlen(menu->MenuName)) +
width;
AdjustItems(&textrp, menu->FirstItem, attr, width, height, 0, 0);
menu = menu->NextMenu;
start += (space + (width * 2));
}
CloseFont(font);
retval = TRUE;
}
return(retval);
}
VOID AdjustItems(struct RastPort *txtrp, struct MenuItem *fi,
struct TextAttr *atr, USHORT wdth, USHORT hght, USHORT lv1,
USHORT edge)
{
struct MenuItem *item = fi;
register USHORT num;
USHORT strip_width, sub_edge;
if (fi == NULL) return;
strip_width = MaxLength(txtrp, item, wdth);
num = 0;
while (item)
{
item->TopEdge = (num * hght) - lv1;
item->LeftEdge = edge;
item->Width = strip_width;
item->Height = hght;
sub_edge = strip_width - wdth;
AdjustText((struct IntuiText *)item->ItemFill, atr);
AdjustItems(txtrp, item->SubItem, atr, wdth, hght, 1, sub_edge);
item = item->NextItem;
num++;
}
}
USHORT MaxLength(struct RastPort * txtrp, struct MenuItem * fi,
USHORT width)
{
USHORT maxval = 0, textlen;
struct MenuItem *item = fi;
struct IntuiText *itext;
while (item)
{
if(item->Flags & COMMSEQ)
{
width += (width + COMMWIDTH);
break;
}
item = item->NextItem;
}
item = fi;
while (item)
{
itext = (struct IntuiText *)item->ItemFill;
textlen = itext->LeftEdge +
TextLength(txtrp, itext->IText, (LONG)strlen(itext->IText)) + width;
maxval = (textlen < maxval) ? maxval : textlen;
item = item->NextItem;
}
return (maxval);
}
VOID AdjustText(struct IntuiText *text, struct TextAttr *attr)
{
struct IntuiText *nt;
nt = text;
while(nt)
{
nt->ITextFont = attr;
nt = nt->NextText;
}
}
/**************************************************************************/
/* Cette fonction initialise le tableau ChangeCount en: */
/* - examinant si les drives sont connectés (non = -1) */
/* - si oui, en examinant le status actuel pour remplir */
/* le tableau en conséquence */
/**************************************************************************/
VOID InitDrive()
{
LONG x;
BYTE error = 0;
for (x = 0; x < 4; x++) /* go thru all 4 possible drives */
{
error = OpenDevice("trackdisk.device", (LONG)x, (struct IORequest *)diskreq, 0L);
if (error > 0)
{
ChangeCount[x] = -1;
}
else {
diskreq->iotd_Req.io_Command = TD_CHANGENUM;
DoIO((struct IORequest *)diskreq);
ChangeCount[x] = diskreq->iotd_Req.io_Actual;
CloseDevice((struct IORequest *)diskreq);
}
}
}
/**************************************************************************/
/* Cette fonction renvoie dans un entier le numéro */
/* du drive dans lequel une disquette vient d'être insérée */
/**************************************************************************/
int DriveNum()
{
int RetVal = -1;
LONG x;
BYTE error = 0;
for (x = 0; x < 4; x++)
{
if (ChangeCount[x] == -1)
continue; /* pas de lecteur */
error = OpenDevice("trackdisk.device", (LONG)x,
(struct IORequest *)diskreq, 0L);
if (error > 0)
continue; /* quelque chose a raté */
diskreq->iotd_Req.io_Command = TD_CHANGESTATE;
DoIO((struct IORequest *)diskreq);
if (diskreq->iotd_Req.io_Actual != 0)
{
CloseDevice((struct IORequest *)diskreq);
continue;
}
diskreq->iotd_Req.io_Command = TD_CHANGENUM;
DoIO((struct IORequest *)diskreq);
if (diskreq->iotd_Req.io_Actual != ChangeCount[x]) {
RetVal = (int)x;
ChangeCount[x] = diskreq->iotd_Req.io_Actual;
CloseDevice((struct IORequest *)diskreq);
break;
}
CloseDevice((struct IORequest *)diskreq);
}
return(RetVal);
}
VOID IDCMPSafely(struct Window *win)
{
Forbid();
StripIntuiMessages(win->UserPort, win);
win->UserPort = NULL;
ModifyIDCMP(win, NULL);
Permit();
}
VOID StripIntuiMessages(struct MsgPort *mp, struct Window *win)
{
struct IntuiMessage *msg, *succ;
msg = (struct IntuiMessage *)mp->mp_MsgList.lh_Head;
while (succ = (struct IntuiMessage *)msg->ExecMessage.mn_Node.ln_Succ)
{
if (msg->IDCMPWindow == win)
{
Remove((struct Node *)msg);
ReplyMsg((struct Message *)msg);
}
msg = succ;
}
}
int handleIDCMP(struct Window *win)
{
int drive;
int done = 0;
USHORT code, flag;
struct IntuiMessage *message = NULL;
LONG class, itemNum, menuNum, file;
char cmd[10];
char titre[22];
strcpy(cmd, "list dfx:");
strcpy(titre, "CON:1/11/520/200/d£x:");
while (message = (struct IntuiMessage *)GetMsg(win->UserPort))
{
class = message->Class;
code = message->Code;
ReplyMsg((struct Message *)message);
switch (class)
{
case DISKINSERTED:
drive = DriveNum();
flag = ((struct MenuItem *)ItemAddress(
FirstMenu, (SHIFTMENU(1) | SHIFTITEM(0))))
->Flags;
if(CliWindow == IntuitionBase->ActiveWindow) {
if (flag & CHECKED) /* si auto cd selectionné */
{
cmd[7] = (char)(drive + 0x30); /* itoa */
titre[19] = (char)(drive + 0x30);
file = Open(titre, MODE_OLDFILE);
Execute(cmd, NULL, file);
Delay(150);
Close(file);
}
}
break;
case MENUPICK:
itemNum = ITEMNUM(code);
menuNum = MENUNUM(code);
switch (menuNum)
{
case 0:
switch (itemNum)
{
case 0:
Execute("genam2", NULL, _Backstdout);
break;
case 1:
Execute("monam2", NULL, _Backstdout);
break;
case 2:
Execute("Deluxe PaintIII: DPaint", NULL, _Backstdout);
break;
case 3:
done = 1;
break;
default:
break;
}
default:
break;
}
default:
break;
}
}
return (done);
}
VOID CleanExit() {
if (WinPort) DeletePort((struct MsgPort *)WinPort);
if (diskreq) DeleteExtIO((struct IORequest *)diskreq);
if (diskport) DeletePort((struct MsgPort *)diskport);
if (GfxBase) CloseLibrary((struct Library *)GfxBase);
if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
if (_Backstdout) {
Close(_Backstdout); /* on libère le CLI */
_Backstdout = 0;
}
exit(0);
}
|
Mise à jour de mai 2025 : une archive contenant le listing adapté à vbcc, et avec l'exécutable
compilé par vbcc, a été réalisée par Yann-Gaël Guéhéneuc et est disponible sur
obligement.free.fr/files/antsupershell.lha.
|