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 - PublicMenus (première partie)
(Article écrit par Max et extrait d'Amiga News Tech - juin 1992)
|
|
Ha ha ! Après trois longs mois de dur labeur, l'Utilitaire du mois revient dans l'ANT. Mesdames,
mesdemoiselles, messieurs et les autres, je suis fier de vous présenter (roulements de tambour)... PublicMenus version 1.0.
De quoi est-ce que s'agit-il donc au juste ? Disons pour simplifier et pour entretenir le suspens, que
les PublicMenus sont aux menus ce que les PublicScreens du système 2.0 sont aux écrans...
Plus précisément, il s'agit d'un menu déroulant dans le plus pur style "pop-up"
que plusieurs applications, totalement indépendantes les unes des autres, peuvent se partager à loisir.
Ce menu n'est de plus pas attaché à une fenêtre particulière, comme le sont ceux d'Intuition, mais est
toujours déroulé dans l'écran le plus "en avant".
Menus partagés
Pour être partagé, le menu se doit d'être partageable (cet article a été écrit en étroite collaboration
avec M. de la Palisse). Et qu'est-ce qui est le plus partageable sur Amiga, sinon les bibliothèques de
fonctions (libraries) ? En conséquence, notre utilitaire du mois est une bibliothèque
(publicmenus.library pour ne pas la nommer), donc qu'il faudra ouvrir, utiliser à loisir puis bien sûr refermer.
Il s'agit donc d'un utilitaire destiné plus spécialement (on peut même dire : exclusivement) aux programmeurs
et qui ne pourra pas être utilisé tel quel par le commun des mortels.
Mais, me direz-vous (car je vous connais) : quel est donc l'intérêt d'une telle bibliothèque ?
A ceci je répondrai que chacun y trouvera l'intérêt qu'il souhaite. Par exemple, moi, je me suis
concocté quelques petits programmes tournant en tâche de fond (c'est-à-dire sans ouvrir d'écran ni
de fenêtre) qui utilisent le menu publique pour donner accès à quelques options de configuration :
une alarme, un économiseur d'écran, une version améliorée du ScreenSaver et du ScreenRoller
(voir cet article), un exécuteur de programmes à
la MyMenu... D'autres pourraient l'utiliser dans le cas de programmes s'iconifiant eux-mêmes
(par exemple PowerPacker, via l'option "Sleep") pour permettre un réveil sur commande sans encombrer
l'écran du Workbench d'une inutile fenêtre... Bref, c'est à chacun de voir.
Distribution
Avant d'aller plus loin, il me faut préciser qu'une version 1.1 de la bibliothèque
a été envoyée à Fred Fish dans le fol espoir de la voir un jour diffusée sur l'une des disquettes de la
célèbre collection. Cette distribution contient non seulement l'exécutable mais aussi une volumineuse
documentation (en anglais et en français), les fichiers Include C et assembleur indispensables à tout
programmeur désirant l'utiliser, ainsi que plusieurs exemples d'utilisation, également en C et en assembleur
(bien sûr, les abonnés avec disquette y auront aussi droit). Seuls les fichiers sources ne sont pas fournis,
afin d'éviter que trop de versions différentes ne circulent. Je vous recommande donc vivement de surveiller
le catalogue Fish et de vous procurer la version 1.1 dès qu'elle sera disponible
(NDLR : la version 1.1 est également disponible sur la disquette ANT 34).
Comment ça marche ?
Une fois la bibliothèque installée et au moins un menu publique déclaré, rien ne se passe... En fait,
la bibliothèque attend que l'utilisateur appuie sur le bouton droit de la souris en conjonction avec la
touche Amiga gauche. A ce moment-là, le menu est affiché et tout se passe exactement de la même manière
qu'avec Intuition. Les items peuvent être des textes ou des images et tous les modes de sélection standards
d'Intuition (HIGHNONE, HIGHCOMP, HIGHBOX et HIGHIMAGE) sont gérés. Un menu peut être désactivé soit totalement,
soit partiellement, puis réactivé. Enfin, même les raccourcis clavier sont gérés avec la touche Amiga gauche).
Je vous l'ai dit, c'est tout comme Intuition, mais sans Intuition.
Qui fait quoi ?
Chaque application désirant utiliser le menu public devra au préalable ouvrir la bibliothèque, en
utilisant tout à fait normalement la fonction OpenLibrary() d'Exec. Lors de la première ouverture, une
tâche est créée, destinée à gérer à la fois l'affichage du menu et les mouvements et clics de la souris.
Cette tâche installe un Input-Handler d'une priorité supérieure à celle d'Intuition, afin que celle-ci
ne s'aperçoive de rien. Évidemment, lorsqu'Exec décide qu'il est temps de retirer la bibliothèque
du système, l'Input-Handler et la tâche sont tous deux supprimés.
On peut donc résumer la situation ainsi : c'est une tâche (au sens Exec du terme) qui est le coeur du système,
la bibliothèque ne faisant qu'office de lien entre les applications l'utilisant et la tâche.
Les fonctions
Comme toute bibliothèque digne de ce nom, la publicmenus.library offre quelques fonctions qu'il convient
de connaître. Les premières seront vues rapidement, car elles ont leur équivalent soit dans la bibliothèque
C standard, soit dans amiga.lib ou Exec 2.0 (le mystère disparaîtra totalement quand je vous aurai dit
qu'elles ont été judicieusement baptisées StringLen(), NewMsgPort(), FreeMsgPort(), NewIORequest()
et FreeIORequest(), afin que le nom ne rentre pas en conflit avec CreateMsgPort() et compagnie).
Ces fonctions ont été incluses en pensant aux programmeurs en assembleur utilisateurs de la version 1.3
d'AmigaDOS (et de toute façon, j'en avais besoin).
Suivent AddPMenu(), RemPMenu(), OffPMenu(), OnPMenu() et PItemAddress(). Les deux premières permettent
respectivement d'ajouter et d'enlever un menu public et les trois suivantes agissent comme leur équivalent
Intuitionnesque. Reportez-vous à la description ci-jointe pour plus de détails sur leur fonctionnement et
leurs paramètres respectifs.
Assemblage
La bibliothèque entière a été écrite en assembleur avec le Devpac 2 (puis le Devpac 3, mais aucune
de ses particularités n'a été utilisée). Utilisez le petit script listé ci-dessous pour assembler
les deux fichiers sources et relier les deux fichiers objets en un seul exécutable nommé libs:publicmenus.library.
Notez qu'il y a de quoi taper : entre la bibliothèque elle-même, les includes (C et assembleur) et
le fichier FD (Cf. LibTool),
nous n'aurons pas trop de deux mois pour achever complètement notre oeuvre.
Listing 1 : include:libraries/publicmenus.h
#ifndef LIBRARIES_PUBLICMENUS_H
#define LIBRARIES_PUBLICMENUS_H
/*
** PublicMenus v1.1 - © 1992, RingarSoft
**
** publicmenus.h -structures et constantes
**
*/
#ifndef EXEC_PORTS_H
#include "exec/ports.h"
#endif /* EXEC_PORTS_H */
#ifndef INTUITION_INTUITION_H
#include "intuition/intuition.h"
#endif /* INTUITION_INTUITION_H */
/****** PublicMenu ******/
struct PublicMenu {
struct Menu IntuiMenu; /* Menu Intuition standard */
struct MsgPort *OwnerPort; /* Votre MessagePort */
};
#define PublicItem MenuItem
#define PublicSubItem MenuItem
/****** Quelques re-définitions *************************************/
#define PMENUENABLED MENUENABLED
#define PITEMENABLED ITEMENABLED
#define PITEMTEXT ITEMTEXT
#define PMENUTOGGLE MENUTOGGLE
/****** PublicMessage ***********************************************/
struct PublicMessage {
struct Message ExecMessage; /* Message Exec standard */
UWORD MenuPick; /* Valeur du MenuPick */
UWORD Qualifiers; /* Qualificateurs */
ULONG Seconds, Micros; /* Heure Système */
};
/****** Divers ******************************************************/
#define NOPMENU 0x001F
#define NOPITEM 0x003F
#define NOPSUB 0x001F
#define PMENUNULL 0xFFFF
#define PMENUNUM(n) (n & 0x1F)
#define PITEMNUM(n) ((n >> 5) & 0x003F)
#define PSUBNUM(n) ((n >> 11) & 0x001F)
#define SHIFTPMENU(n) (n & 0x1F)
#define SHIFTPITEM(n) ((n & 0x3F) << 5)
#define SHIFTPSUB(n) ((n & 0x1F) << 11)
#define MAKEPNUM(i,s) (SHIFTPSUB(s)|SHIFTPITEM(i)|NOPMENU)
#define PCHECKWIDTH CHECKWIDTH
#define PCOMMWIDTH COMMWIDTH
#define LOWPCHECKWIDTH LOWCHECKWIDTH
#define LOWPCOMMWIDTH LOWCOMMWIDTH
/****** Nom de la Librairie *****************************************/
#define PUBLICMENUSNAME "publicmenus.library"
#endif /* LIBRARIES_PUBLICMENUS_H */
|
Listing 2 : include:libraries/publicmenusbase.h
#ifndef LIBRARIES_PUBLICMENUSBASE_H
#define LIBRARIES_PUBLICMENUSBASE_H
/*
** PublicMenus v1.1 - © 1992, RingarSoft
**
** publicmenusbase.h - structure de base
**
*/
#ifndef EXEC_TYPES_H
#include "exec/types.h"
#endif /* EXEC_TYPES_H */
#ifndef EXEC_LIBRARIES_H
#include "exec/libraries.h"
#endif /* EXEC_LIBRARIES_H */
#ifndef EXEC_SEMAPHORES_H
#include "exec/semaphores.h"
#endif /* EXEC_SEMAPHORES_H */
/****** Library base structure ***************************************/
struct PublicMenusBase {
struct Library pmb_Lib; /* Librarie standard */
UBYTE pmb_Flags, pmb_Pad;
ULONG pmb_SegList;
struct PublicMenu *pmb_PMenuStrip; /* Le PublicMenuStrip */
UWORD pmb_PMenuCount; /* Nombre de PMenus */
struct SignalSemaphore pmb_Semaphore; /* Pour accès unique */
struct Task *pmb_PMenusTask; /* PMenus.task */
};
#endif /* PMENUSBASE_H */
|
Listing 3 : include:proto/publicmenus.h
#ifndef EXEC_TYPES_H
#include <exec/types.h>
#endif
extern struct PublicMenusBase *PMenusBase;
SHORT StringLen(char *);
struct MsgPort *NewMsgPort(char *, LONG);
void FreeMsgPort(struct MsgPort *);
struct IORequest *NewIORequest(struct MsgPort *, LONG);
void FreeIORequest(struct IORequest *);
void LockPMenus(void);
void UnlockPMenus(void);
BOOL AddPMenu(struct PublicMenu *);
void RemPMenu(struct PublicMenu *);
void OffPMenu(struct PublicMenu *, USHORT);
void OnPMenu(struct PublicMenu *, USHORT);
struct PublicItem *PItemAddress(struct PublicMenu *, USHORT);
#ifndef NO_PRAGMAS
/* pragmas pour le SAS/C 5.10. Désolé, je ne connais pas le Manx ! ------*/
#pragma libcall PMenusBase StringLen 1E 801
#pragma libcall PMenusBase NewMsgPort 2A 802
#pragma libcall PMenusBase FreeMsgPort 30 801
#pragma libcall PMenusBase NewIORequest 36 802
#pragma libcall PMenusBase FreeIORequest 3C 901
#pragma libcall PMenusBase LockPMenus 42 0
#pragma libcall PMenusBase UnlockPMenus 48 0
#pragma libcall PMenusBase AddPMenu 4E 801
#pragma libcall PMenusBase RemPMenu 54 801
#pragma libcall PMenusBase OffPMenu 5A 802
#pragma libcall PMenusBase OnPMenu 60 802
#pragma libcall PMenusBase PItemAddress 66 802
#endif
|
Listing 4 : include:libraries/publicmenus.i
IFND LIBRARIES_PUBLICMENUS_I
LIBRARIES_PUBLICMENUS_I SET 1
**
** PublicMenus v1.1 - © 1992, RingarSoft
**
** publicmenus.i - structures et constantes
**
**
IFND EXEC_PORTS_I
INCLUDE "exec/ports.i"
ENDC ; EXEC_PORTS_I
IFND INTUITION_INTUITION_I
INCLUDE "intuition/intuition.i"
ENDC ; INTUITION_INTUITION_I
******* PublicMenu ***************************************************
STRUCTURE PublicMenu,0
STRUCT pmu_IntuiMenu,mu_SIZEOF ; Menu Intuition standard
APTR pmu_OwnerPort ; Votre MessagePort
LABEL pmu_SIZEOF
******* PublicItem ***************************************************
STRUCTURE PublicItem,mi_SIZEOF ; Identique à MenuItem
LABEL pmi_SIZEOF
******* The PublicSubItem structure **********************************
STRUCTURE PublicSubItem,mi_SIZEOF ; Itendique à MenuItem
LABEL pms_SIZEOF
******* Quelques re-définitions **************************************
PMENUENABLED EQU MENUENABLED
PITEMENABLED EQU ITEMENABLED
PITEMTEXT EQU ITEMTEXT
PMENUTOGGLE EQU MENUTOGGLE
******* PublicMessage ************************************************
STRUCTURE PublicMessage,0
STRUCT pmn_ExecMessage,MN_SIZE ; Message Exec standard
UWORD pmn_MenuPick ; Valeur du MenuPick
UWORD pmn_Qualifiers ; Qualificateurs
ULONG pmn_Seconds ; Heure Système
ULONG pmn_Micros ; '' ''
LABEL pmn_SIZEOF
******* Divers *******************************************************
;#define PMENUNUM(n) (n & 0x1F)
;#define PITEMNUM(n) ((n >> 5) & 0x003F)
;#define PSUBNUM(n) ((n >> 11) & 0x001F)
;
;#define SHIFTPMENU(n) (n & 0x1F)
;#define SHIFTPITEM(n) ((n & 0x3F) << 5)
;#define SHIFTPSUB(n) ((n & 0x1F) << 11)
NOPMENU EQU $001F
NOPITEM EQU $003F
NOPSUB EQU $001F
PMENUNULL EQU $FFFF
PCHECKWIDTH EQU CHECKWIDTH
PCOMMWIDTH EQU COMMWIDTH
LOWPCHECKWIDTH EQU LOWCHECKWIDTH
LOWPCOMMWIDTH EQU LOWCOMMWIDTH
******* Nom de la librairie ******************************************
PUBLICMENUSNAME MACRO
dc.b "publicmenus.library",0
ds.w 0
ENDM
ENDC ; LIBRARIES_PUBLICMENUS_I
|
Listing 5 : include:libraries/publicmenusbase.i
IFND LIBRARIES_PUBLICMENUSBASE_I
LIBRARIES_PUBLICMENUSBASE_I SET 1
**
** PublicMenus v1.1 - © 1992, RingarSoft
**
** publicmenusbase.i - structure de base
**
**
IFND EXEC_TYPES_I
INCLUDE "exec/types.i"
ENDC ; EXEC_TYPES_I
IFND EXEC_LIBRARIES_I
INCLUDE "exec/libraries.i"
ENDC ; EXEC_LIBRARIES_I
IFND EXEC_SEMAPHORES_I
INCLUDE "exec/semaphores.i"
ENDC ; EXEC_SEMAPHORES_I
******* Library base structure ***************************************
STRUCTURE PublicMenusBase,0
STRUCT pmb_Lib,LIB_SIZE ; Librairie standard
UBYTE pmb_Flags
UBYTE pmb_Pad
ULONG pmb_SegList
APTR pmb_PMenuStrip ; Le PublicMenuStrip
UWORD pmb_PMenuCount ; Nombre de PMenus
STRUCT pmb_Semaphore,SS_SIZE ; Pour accès unique
APTR pmb_PMenusTask ; PMenus.task
LABEL PublicMenusBase_SIZEOF
ENDC ; LIBRARIES_PUBLICMENUSBASE_I
|
Listing 6 : include:libraries/publicmenus_lib.i
_LVOStringLen EQU -30
;_LVOReserved EQU -36
_LVONewMsgPort EQU -42
_LVOFreeMsgPort EQU -48
_LVONewIORequest EQU -54
_LVOFreeIORequest EQU -60
_LVOLockPMenus EQU -66
_LVOUnlockPMenus EQU -72
_LVOAddPMenu EQU -78
_LVORemPMenu EQU -84
_LVOOffPMenu EQU -90
_LVOOnPMenu EQU -96
_LVOPItemAddress EQU -102
|
Listing 7 : PTask.i
;
; PTask.i - Définition des variables de la tâche principale
;
IFND INTUITION_INTUITION_I
INCLUDE "intuition/intuition.i"
ENDC
IFND GRAPHICS_RASTPORT_I
INCLUDE "graphics/rastport.i"
ENDC
IFND EXEC_INTERRUPTS_I
INCLUDE "exec/interrupts.i"
ENDC
IFND LIBRARIES_DOS_I
INCLUDE "libraries/dos.i"
ENDC
; Utilisation particulière du Menu
pmu_MenuPick EQU mu_JazzX ; Valeur MenuPick
pmu_LastSelNum EQU mu_JazzY ; Dernière sélection (numéro)
pmu_LastSelect EQU mu_BeatX ; Dernière sélection (adresse)
; Description d'un signal
rsreset
SignalData rs.b 0
sgd_SigBit rs.l 1 ; N° du bit de signal
sgd_SigMask rs.l 1 ; Masque du signal
sgd_SIZEOF rs.w 0
; Structure d'une "boîte" (dessin des menus)
rsreset
Box rs.b 0
bx_LeftEdge rs.w 1 ; Coordonnée X1
bx_TopEdge rs.w 1 ; Coordonnée Y1
bx_Width rs.w 1 ; Largeur
bx_Height rs.w 1 ; Hauteur
bx_RightEdge rs.w 1 ; Coordonnée X2
bx_BottomEdge rs.w 1 ; Coordonnée Y2
bx_LeftOffset rs.w 1 ; Décalage X
bx_TopOffset rs.w 1 ; Décalage Y
bx_ItemList rs.l 1 ; Premier Item
bx_BitMap rs.b bm_SIZEOF ; BitMap
bx_Flags rs.w 1 ; Flags (cf. ci-dessous)
bx_SIZEOF rs.w 0
; Flags (numéros de bits)
BX_PARENT_OFF EQU 0 ; Item ou Menu père désactivé
BX_DRAWN EQU 1 ; Boîte dessinée (rasters alloués)
; Les variables proprement dites
rsreset
PmuBase rs.l 1 ; Base de la library
pMainTask rs.l 1 ; Adresse de la tâche (pour le Handler)
IntBase rs.l 1 ; IntuitionBase
GfxBase rs.l 1 ; GfxBase
LayBase rs.l 1 ; LayersBase
pMainPort rs.l 1 ; MsgPort pour les envoyer les messages
pMainSignal rs.l 1 ; Signal pour le port (masque)
pInputPort rs.l 1 ; MsgPort pour l'input.device
pInputIO rs.l 1 ; IORequest pour l'input.device
pConsoleIO rs.l 1 ; IORequest pour le console.device
ConBase rs.l 1 ; ConsoleBase
pHostScreen rs.l 1 ; Screen utilisé pour dessiner les menus
pHostFont rs.l 1 ; Fonte utilisée
pAKeyImage rs.l 1 ; Image du CheckMark
pCheckImage rs.l 1 ; Image de la Command Key (Amiga gauche)
pQualifiers rs.w 1 ; Qualificateurs (mis par le Handler)
pCode rs.w 1 ; MenuPick (mis par le Handler)
pExit1 rs.b 1 ; Flag de fin (boucle principale)
pExit2 rs.b 1 ; Flag de fin (boucle Menus)
pMenues rs.b 1 ; TRUE si les menus sont dessinés
pPAD rs.b 1
pMenuNum rs.w 1 ; Menu courant (numéro)
pCurrentMenu rs.l 1 ; Menu courant (adresse)
pCurrentItem rs.l 1 ; Item courant
pCurrentSub rs.l 1 ; Sub courant
pTempItem rs.l 1 ; Stockage temporaire
pSIGNALS rs.b 0
pMoveSignal rs.b sgd_SIZEOF ; Signal pour la souris
pLDownSignal rs.b sgd_SIZEOF ; Signal bouton gauche appuyé
pLUpSignal rs.b sgd_SIZEOF ; Signal bouton gauche relâché
pRDownSignal rs.b sgd_SIZEOF ; Signal bouton droit appuyé
pRUpSignal rs.b sgd_SIZEOF ; Signal bouton droit relâché
pKeySignal rs.b sgd_SIZEOF ; Signal touche COMMSEQ appuyée
PMB_NB_SIGNALS EQU 6
pSigMasks rs.l 1 ; Masque de tous les signaux
pRastPort rs.b rp_SIZEOF ; RastPort pour le dessin
pMenuBox rs.b bx_SIZEOF ; Boîte des Menus
pItemBox rs.b bx_SIZEOF ; Boîte des Items
pSubBox rs.b bx_SIZEOF ; Boîte des SubItems
pInterrupt rs.b IS_SIZE ; Pour l'input.device
pConsoleBuff rs.l 1 ; Pour le console.device
VARSIZE rs.w 0 ; Taille des variables
; ************************************
; Constantes
HANDLER_PRI EQU 65
BORDER EQU 2
OVERLAP EQU 2
AKEYWIDTH_H EQU 27
AKEYWIDTH_L EQU 16
CHECKWIDTH_H EQU 19
CHECKWIDTH_L EQU 13
INIT_OK EQU SIGBREAKF_CTRL_C
INIT_FAILED EQU SIGBREAKF_CTRL_D
QUIT_SIGNAL EQU SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F
; ************************************
CALLSYS MACRO
jsr _LVO\1(a6)
ENDM
EXEC MACRO
movea.l $4.w,a6
CALLSYS \1
ENDM
INT MACRO
movea.l IntBase(a5),a6
CALLSYS \1
ENDM
GRAF MACRO
movea.l GfxBase(a5),a6
CALLSYS \1
ENDM
LAY MACRO
movea.l LayBase(a5),a6
CALLSYS \1
ENDM
PMENUS MACRO
movea.l PmuBase(a5),a6
jsr _LVO\1(a6)
ENDM
DEFSTR MACRO
dc.b \1,0
even
ENDM
|
Listing 8 : PLib.s
;
; PublicMenus - © 1992, RingarSoft pour ANT
;
; PLib.s - Fonctions de la Library
; Assemblé avecDevpac Amiga 3.02
;
OPT o+,ow+,ow2-
OPT l+
INCDIR "Include:" ; A changer au besoin
INCLUDE "exec/types.i"
INCLUDE "exec/libraries.i"
INCLUDE "exec/initializers.i"
INCLUDE "exec/resident.i"
INCLUDE "exec/ports.i"
INCLUDE "exec/memory.i"
INCLUDE "exec/execbase.i"
INCLUDE "libraries/publicmenus.i"
INCLUDE "libraries/publicmenusbase.i"
INCLUDE "libraries/publicmenus_lib.i"
INCLUDE "PTask.i"
VERSION EQU 1 ; Version de la library
REVISION EQU 1 ; Numéro de révision
STACKSIZE EQU 4000 ; Pile de la tâche
TASKPRI EQU 3 ; Priorité de la tâche
; Labels à exporter
XDEF StringLen,NewMsgPort,FreeMsgPort
XDEF NewIORequest,FreeIORequest
; Lables à importer
XREF MainTask,InitTask,EndTask
; ************************************
RunLib moveq #0,d0
rts
; ************************************
RomTag dc.w RTC_MATCHWORD ; RT_MATCHWORD
dc.l RomTag ; RT_MATCHTAG
dc.l EndTag ; RT_ENDSKIP
dc.b RTF_AUTOINIT ; RT_FLAGS
dc.b VERSION ; RT_VERSION
dc.b NT_LIBRARY ; RT_TYPE
dc.b 0 ; RT_PRI
dc.l PMenusName ; RT_NAME
dc.l PMenusID ; RT_IDSTRING
dc.l Init ; RT_INIT
EndTag EQU *
; ************************************
Init dc.l PublicMenusBase_SIZEOF ; Taille de LibBase
dc.l FuncTable ; Init. fonctions
dc.l DataTable ; Init. données
dc.l InitRoutine ; Init. routine
FuncTable:
dc.l Open,Close ; Fonctions système
dc.l Expunge,Reserved
dc.l StringLen,Reserved ; Fonctions spécifiques
dc.l NewMsgPort,FreeMsgPort,NewIORequest,FreeIORequest
dc.l LockPMenus,UnlockPMenus
dc.l AddPMenu,RemPMenu,OffPMenu,OnPMenu
dc.l PItemAddress
dc.l -1 ; Fin de la table
DataTable:
INITBYTE LN_TYPE,NT_LIBRARY
INITLONG LN_NAME,PMenusName
INITBYTE LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
INITWORD LIB_VERSION,VERSION
INITWORD LIB_REVISION,REVISION
INITLONG LIB_IDSTRING,PMenusID
dc.l 0
; ************************************
; Cette routine est appelée après que la library ait été
; chargée. La base est dans D0, la liste des segments dans A0.
; Si elle retourne NULL, OpenLibrary() échouera.
InitRoutine:
movem.l d2-d3/a2-a5,-(sp)
movea.l d0,a5
move.l a0,pmb_SegList(a5)
clr.l pmb_PMenuStrip(a5) ; Initialise les variables
clr.w pmb_PMenuCount(a5) ; importantes...
lea pmb_Semaphore(a5),a0
CALLSYS InitSemaphore
lea TaskMemList(pc),a0 ; Alloue d'un coup toute la
CALLSYS AllocEntry ; mémoire nécessaire à la
bclr #31,d0 ; tâche (variables, pile...)
bne.s .InitFailed
movea.l d0,a2 ; a2 = MemList
movea.l ML_ME+(ME_SIZE*0)+ME_ADDR(a2),a4 ; a4 = Task
movea.l ML_ME+(ME_SIZE*1)+ME_ADDR(a2),a3 ; a3 = VARS
movea.l ML_ME+(ME_SIZE*2)+ME_ADDR(a2),a1 ; a1 = Stack
move.l a4,pmb_PMenusTask(a5)
move.l a5,PmuBase(a3) ; La tâche en aura besoin...
move.l a4,pMainTask(a3)
move.b #NT_TASK,LN_TYPE(a4) ; Initialise la structure Task
move.b #TASKPRI,LN_PRI(a4)
move.l #TaskName,LN_NAME(a4)
move.l a1,TC_SPLOWER(a4)
lea STACKSIZE(a1),a1
move.l a1,TC_SPUPPER(a4)
; Astuce : l'adresse des variables est poussée sur la pile
; de la tâche ; elle n'aura qu'à se servir !
move.l ThisTask(a6),-(a1)
move.l a3,-(a1)
move.l a1,TC_SPREG(a4)
; Autre astuce : on ajoute la MemList allouée ci-dessus au
; champ TC_MEMENTRY de la structure Task. Ainsi, la mémoire
; sera automatiquement libérée par Exec lorsque la tâche
; se terminera.
lea TC_MEMENTRY(a4),a0
NEWLIST a0
movea.l a2,a1
CALLSYS AddHead
movea.l a4,a1 ; Ajoute la tâche...
lea StartTask(pc),a2 ; (InitPC)
suba.l a3,a3 ; (FinalPC)
CALLSYS AddTask
; Attend que la tâche ait fini son initialisation
move.l #INIT_FAILED,d3
move.l #INIT_OK,d0
or.l d3,d0
CALLSYS Wait
and.l d3,d0 ; Si l'initiation a échoué,
bne.s .InitFailed ; retourne NULL (la tâche
move.l a5,d0 ; se terminera d'elle-même)
bra.s .InitOk
.InitFailed:
moveq #0,d0
.InitOk movem.l (sp)+,d2-d3/a2-a5
rts
TaskMemList:
dcb.b LN_SIZE
dc.w 3 ; Nombre d'entrées
dc.l MEMF_CLEAR|MEMF_PUBLIC,TC_SIZE ; Structure Task
dc.l MEMF_CLEAR,VARSIZE ; Variables
dc.l MEMF_CLEAR,STACKSIZE ; Pile
; ************************************
; La nouvelle Tâche commence réellement ici...
StartTask:
movea.l 4(sp),a5 ; Récupère l'adresse des variables
movea.l 8(sp),a4 ; Tâche qui a appelé OpenLibrary()
bsr InitTask ; Initialisation (cf. PTask.s)
beq.s .TaskFailed ; Manqué !
move.l #INIT_OK,d0 ; Tout va bien !
movea.l a4,a1
EXEC Signal ; On le signale à la Library
bsr MainTask ; Et on saute à la bloucle principale
bsr EndTask
bra.s .Ret
.TaskFailed:
move.l #INIT_FAILED,d0
movea.l a4,a1
EXEC Signal
.Ret suba.l a1,a1 ; Suicide !!
EXEC RemTask
rts
; ************************************
PMenusName PUBLICMENUSNAME
PMenusID dc.b "PublicMenus ",VERSION+48,".",REVISION+48
dc.b " (24 April 1992)",13,10,0
even
TaskName DEFSTR <"PMenus.task">
; ************************************
Open addq.w #1,LIB_OPENCNT(a6)
bclr #LIBB_DELEXP,pmb_Flags(a6)
move.l a6,d0
rts
; ************************************
Close moveq #0,d0
subq.w #1,LIB_OPENCNT(a6)
bne.s .1
btst #LIBB_DELEXP,pmb_Flags(a6)
bne.s Expunge
.1 rts
; ************************************
; La fonction Expunge() retire la library de la liste des
; library, libère toute la mémoire allouée et ferme tout
; ce qui a pu être ouvert.
; Expunge() peut être appelée à deux occasions : lors d'une
; allocation mémoire (si Exec en manque) ou par Close() ci-dessus
; lorsque le dernier utilisateur a refermé la library.
; Elle doit retourner la liste des segments (transmise à InitRoutine)
; pour que le DOS l'UnloadSeg() ou NULL sinon.
Expunge movem.l d2/a5/a6,-(sp)
movea.l a6,a5
movea.l $4.w,a6
tst.w LIB_OPENCNT(a5) ; Library encore utilisée ?
beq.s .1
bset #LIBB_DELEXP,pmb_Flags(a6)
moveq #0,d0
bra.s .Ret
.1 move.l pmb_SegList(a5),d2 ; Prépare la seglist...
movea.l a5,a1 ; Retire la library de la
CALLSYS Remove ; liste ExecBase->LibList
movea.l pmb_PMenusTask(a5),a1 ; Prévient la tâche principale
move.l #QUIT_SIGNAL,d0 ; qu'il est temps de mourir...
CALLSYS Signal
moveq #0,d0 ; Libère la mémoire allouée
movea.l a5,a1 ; par Exec pour PublicMenusBase
move.w LIB_NEGSIZE(a5),d0
suba.l d0,a1
add.w LIB_POSSIZE(a5),d0
CALLSYS FreeMem
move.l d2,d0
.Ret movem.l (sp)+,d2/a5/a6
rts
; ************************************
Reserved:
moveq #0,d0
rts
; **************************************
; * Fonctions spécifiques à la library *
; **************************************
; Len = StringLen(String)
; D0 -30 A0
StringLen:
moveq #-1,d0 * String (A0)
.count tst.b (a0)+
dbeq d0,.count
adda.w d0,a0
not.l d0
rts
; ************************************
; NewPort = NewMsgPort(Name,Pri)
; D0 -36 A0 D0
NewMsgPort:
movem.l d2-d3/a2-a3/a6,-(sp)
movea.l a0,a2
move.l d0,d2
suba.l a3,a3
moveq #-1,d0
EXEC AllocSignal
move.b d0,d3
bmi.s .Ret
.SigOk moveq #MP_SIZE,d0
move.l #MEMF_CLEAR|MEMF_PUBLIC,d1
CALLSYS AllocMem
tst.l d0
bne.s .PortOk
move.b d3,d0
CALLSYS FreeSignal
bra.s .Ret
.PortOk movea.l d0,a3
move.b d2,MP+LN_PRI(a3)
move.b #NT_MSGPORT,MP+LN_TYPE(a3)
move.b #PA_SIGNAL,MP_FLAGS(a3)
move.b d3,MP_SIGBIT(a3)
move.l ThisTask(a6),MP_SIGTASK(a3)
move.l a2,MP+LN_NAME(a3)
beq.s .List
movea.l a3,a1
CALLSYS AddPort
bra.s .Ret
.List lea MP_MSGLIST(a3),a0
NEWLIST a0
.Ret move.l a3,d0
movem.l (sp)+,d2-d3/a2-a3/a6
rts
; ************************************
; VOID FreeMsgPort(Port)
; -42 A0
FreeMsgPort:
movem.l a2/a6,-(sp)
movea.l a0,a2
movea.l $4.w,a6
move.l MP+LN_NAME(a2),d0
beq.s .NoName
move.l a2,a1
CALLSYS RemPort
.NoName moveq #0,d0
move.b MP_SIGBIT(a2),d0
CALLSYS FreeSignal
movea.l a2,a1
moveq #MP_SIZE,d0
CALLSYS FreeMem
movem.l (sp)+,a2/a6
rts
; ************************************
; NewIO = NewIORequest(Port,Size)
; D0 -48 A0 D0
NewIORequest:
movem.l d2/a2-a3/a6,-(sp)
move.l d0,d2
movea.l a0,a2
move.l #MEMF_CLEAR|MEMF_PUBLIC,d1
EXEC AllocMem
tst.l d0
beq.s .Ret
movea.l d0,a3
move.b #NT_MESSAGE,IO+MP+LN_TYPE(a3)
move.w d2,IO+MP+MN_LENGTH(a3)
move.l a2,IO+MP+MN_REPLYPORT(a3)
.Ret movem.l (sp)+,d2/a2-a3/a6
rts
; ************************************
; VOID FreeIORequest(IORequest)
; -54 A1
FreeIORequest:
move.l a6,-(sp)
moveq #0,d0
move.w IO+MP+MN_LENGTH(a1),d0
EXEC FreeMem
movea.l (sp)+,a6
rts
; ************************************
; VOID LockPMenus(VOID)
; -60
LockPMenus:
movem.l d0-d1/a0-a1/a6,-(sp)
lea pmb_Semaphore(a6),a0
EXEC ObtainSemaphore
movem.l (sp)+,d0-d1/a0-a1/a6
rts
; ************************************
; VOID UnlockPMenus(VOID)
; -66
UnlockPMenus:
movem.l d0-d1/a0-a1/a6,-(sp)
lea pmb_Semaphore(a6),a0
EXEC ReleaseSemaphore
movem.l (sp)+,d0-d1/a0-a1/a6
rts
; ************************************
; BOOL AddPMenu(PMenu)
; D0 -72 A0
AddPMenu:
bsr.s LockPMenus
move.l pmb_PMenuStrip(a6),d0
beq.s .First
.Last movea.l d0,a1
move.l mu_NextMenu(a1),d0
bne.s .Last
move.l a0,mu_NextMenu(a1)
bra.s .Add
.First move.l a0,pmb_PMenuStrip(a6)
.Add addq.w #1,pmb_PMenuCount(a6)
clr.l mu_NextMenu(a0)
bsr.s UnlockPMenus
moveq #-1,d0
rts
; ************************************
; VOID RemPMenu(PMenu)
; -78 A0
RemPMenu:
bsr.s LockPMenus
move.l pmb_PMenuStrip(a6),d0
beq.s .ret
cmpa.l d0,a0
beq.s .First
.loop movea.l d0,a1
move.l mu_NextMenu(a1),d0
beq.s .rem
cmpa.l d0,a0
bne.s .loop
.rem move.l mu_NextMenu(a0),mu_NextMenu(a1)
bra.s .1
.First move.l mu_NextMenu(a0),pmb_PMenuStrip(a6)
.1 subq.w #1,pmb_PMenuCount(a6)
bne.s .ret
clr.l pmb_PMenuStrip(a6)
.ret bsr.s UnlockPMenus
rts
; ************************************
; VOID OffPMenu(PMenu,PMenuNumber)
; -84 A0 D0
OffPMenu:
bsr.s LockPMenus
bsr.s PItemAddress
tst.l d0
beq.s .Menu
.Item movea.l d0,a0
bclr #4,mi_Flags+1(a0)
bra.s UnlockPMenus
.Menu bclr #0,mu_Flags+1(a0)
bra.s UnlockPMenus
; ************************************
; VOID OnPMenu(PMenu,PMenuNumber)
; -90 A0 D0
OnPMenu:
bsr LockPMenus
bsr.s PItemAddress
tst.l d0
beq.s .Menu
.Item movea.l d0,a0
bset #4,mi_Flags+1(a0)
bra UnlockPMenus
.Menu bset #0,mu_Flags+1(a0)
bra UnlockPMenus
; ************************************
; Item = PItemAddress(PMenu,PMenuNumber)
; D0 -96 A0 D0
PItemAddress:
movem.l d2/a2,-(sp)
bsr LockPMenus
suba.l a2,a2
moveq #-1,d1 ; PMenuNumber == MENUNULL ?
cmp.w d1,d0
beq.s .ret
lsr.w #5,d0 ; ITEMNUM(PMenuNumber) == NOITEM ?
moveq #NOITEM,d2
and.w d0,d2
cmpi.w #NOITEM,d2
beq.s .ret
move.l mu_FirstItem(a0),d1
bra.s .1
.loop1 movea.l d1,a0
move.l mi_NextItem(a0),d1
.1 dbeq d2,.loop1
beq.s .ret
movea.l d1,a2
lsr.w #6,d0 ; SUBNUM(PMenuNumber) == NOSUB ?
moveq #NOSUB,d2
and.w d0,d2
cmpi.w #NOSUB,d2
beq.s .ret
move.l mi_SubItem(a2),d1
bra.s .2
.loop2 movea.l d1,a0
move.l mi_NextItem(a0),d1
.2 dbeq d2,.loop2
beq.s .ret
movea.l d1,a2
.ret bsr UnlockPMenus
move.l a2,d0
movem.l (sp)+,d2/a2
rts
; ************************************
END
|
|