Obligement - L'Amiga au maximum

Lundi 26 janvier 2026 - 15:16  

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 Mastodon




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 - workbench.library et AppIcon
(Article écrit par Frédéric Delacroix et extrait d'Amiga News - juillet 1994)


Le Workbench a fait beaucoup de progrès depuis l'avènement des systèmes 2.x et 3.x. Outre les (nombreux) bogues corrigés, il existe maintenant un moyen tout à fait légal d'utiliser les capacités du Workbench.

La workbench.library vous permettra d'ajouter des AppIcons, des AppMenuItems et des AppWindows à volonté, discipline dans laquelle l'excellent ToolManager s'est rendu maître. A réserver aux Kickstart 2.0 et plus.

Présentation des AppObjets

Le préfixe "App" signifie ici "application". Une AppIcon est ainsi une icône qui se comporte exactement comme une icône normale (elle peut être déplacée et cliquée) mais qui n'est pas associée à un fichier, mais à un programme actuellement résident. Petite différence toutefois : le menu "Information..." ne marche pas sur les AppIcons. De la même façon, les AppMenuItems sont les menus du menu "Outils" du Workbench. Il n'est pour l'instant pas possible d'y associer des sous-menus (c'est dommage, ce sera peut-être pour la version 41...).

Les AppWindows sont (à peine) plus difficiles à mettre en oeuvre : il faut d'abord ouvrir une fenêtre Intuition grâce à OpenWindow [TagList]() et la déclarer auprès de la workbench.library.

Mais quel intérêt ?

Eh bien grâce à ces AppIcons, AppMenus et AppWindows, vous avez un moyen de communication avec le Workbench ! Le Workbench enverra un message à l'application qui a déclaré un objet lorsqu'un évènement concernant l'objet en question surviendra.

Pour une AppIcon, cela signifie qu'on lui a déposé une autre icône dessus, ou qu'elle a subi un double-clic : un AppMenu se manifeste lorsqu'il a été choisi dans le menu "Outils", et une AppWindow signalera qu'on a déplacé une icône dans la fenêtre (un peu à la manière des fenêtres "tiroirs" du Workbench).

Communication avec le Workbench

Le Workbench est une tâche (ou plutôt un processus). La communication avec lui passe donc, on peut s'en douter, par l'échange de messages. Il faut donc créer un port message, tout à fait standard, qui recevra les messages du Workbench (ce qui peut se faire pur CreateMsgPort() d'exec.library). Le Workbench emploie des messages étendus, connus sous le nom d'AppMessage, définie en C par :

	struct AppMessage {
	struct Message	am_Message;		/* Pour Exec */
	UWORD		am_Type;		/* type de message */
	ULONG		am_UserData;
	ULONG		am_ID;
	LONG		am_NumArgs;		/* nombre d'arguments */
	struct	WBArg *	am_ArgList;		/* liste d'arguments */
	UWORD		am_Version;
	UWORD		am_Class;		/* inutilisé apparemment */
	WORD		am_MouseX;		/* coordonnées souris */
	WORD		am_MouseY;
	ULONG		am_Seconds;		/* heure de l'évènement */
	ULONG		am_Micros;
	ULONG		am_Reserved[8];
};

Cette structure est bien sûr utilisable en assembleur, mais le C est un peu plus concis pour la description. Comme on peut le voir ci-dessus, le système utilisé par le Workbench pour passer ses arguments est le même que celui du message WBStartup : am_ArgList pointe sur un tableau de structures WBArg (gui contiennent Lock sur le répertoire et nom des objets sélectionnés) et am_NumArgs contient le nombre de ces arguments. Deux champs sont à notre entière disposition : atm_ID et am_UserData contiendront les valeurs données en paramètres aux fonctions AddAppXXXX(). Voyons maintenant le contenu des messages reçus.
  • Cas d'une AppIcon : si celle-ci été double-cliquée, alors am_NumArgs vaut 0. Si on y a déposé une ou plusieurs icônes (grâce à la multisélection), am_ArgList est la liste des structures WBArg correspondantes, et le type du message est MTYPE_APPICON. Pour l'instant, il est impossible de déposer l'AppIcon elle-même sur une autre icône, ou d'utiliser la multisélection avec des AppIcon (en "Shift-cliquant" une AppIcon). Sélectionner une AppIcon et choisir le menu "Ouvrir" est équivalent à un double-clic.

  • Cas d'un AppMenu : am_ArgList est la liste des icônes qui étaient sélectionnées au moment où l'utilisateur a choisi le menu. am_NumArgs est leur nombre, 0 si aucune icône n'était sélectionnée, le type du message est MTYPE_APPMENUITEM.

  • Cas d'une AppWindow : la liste des icônes qui ont été déposées dans la fenêtre est contenue dans am_ArgList. Ici, il y a toujours au moins un argument. Le champ am_Type vaudra alors MTYPE_APPWINDOW.
Gérer de nouveaux AppObjets

Tout se fait par l'intermédiaire de la workbench.library, une condition supplémentaire va de soi : le Workbench doit avoir été lancé (ce qui est normalement fait par la commande "LoadWB" dans la startup-sequence). Voyons d'abord les Applcons.

Il faut d'abord initialiser une structure DiskObject (reportez-vous à cet article pour plus d'informations sUr cette structure). Le meilleur moyen d'en avoir une à sa disposition est de charger l'icône du programme grâce à GetDiskObject() de l'icon.library, ou d'en créer une en passant 0 en paramètre à cette fonction. Seuls les champs suivants sont pris en compte :
  • do_Gadget : gg_Width, gg_Height, gg_Flags (contient 0 ou GFLG_GADGHIMAGE si l'icône a deux images), gg_GadgetRender (image non sélectionnée), gg_SelectRender (image sélectionnée si elle existe).

  • do_CurrentX et do_CurrentY : NO_ICON_POSITION est conseillé, mais d'autres valeurs sont possibles. On utilise ensuite la fonction AddAppIconA() de la workbench.library. Les valeurs passées en D0 et D1 sont ignorées par la workbench.library, on les retrouve telles quelles respectivement dans les champs am_ID et am_UserData des structures AppMessages futures. En A0, la fonction prend un pointeur sur la chaîne de caractères qui sera affichée sous l'icône ; A1 pointe sur le MsgPort qui sera utilisé pour communiquer avec le Workbench ; A2 doit être à 0, A3 pointe sur la structure DiskObject précédemment initialisée, et A4 pointe sur une liste de marqueurs. Aucun marqueur n'est défini pour l'instant, on peut mettre A4 à 0. En retour, D0 contient un pointeur sur une structure AppIcon, ou 0 si la fonction a échoué. Cette valeur n'a qu'une signification booléenne pour nous.

  • Pour retirer une AppIcon, c'est plus simple : on utilise la fonction RemoveAppIcon() à laquelle on passe en A0 la valeur renvoyée par AddAppIconA(), et on libère la structure DiskObject si nécessaire.

  • En ce qui concerne les AppMenus, moins d'initialisations sont nécessaires, on peut directement utiliser la fonction AddAppMenuItemA() avec les paramètres suivants : D0 et D1 contiennent les valeurs respectives de am_1D et am_UserData des AppMessages à venir, A0 pointe sur le texte qui apparaîtra dans le menu, A1 pointe sur le MsgPort pour la communication avec le Workbench, A2 sur une liste de marqueurs (aucun marqueur n'est défini pour l'instant). En retour, D0 pointe sur une structure AppMenuItem (privée, tout comme les structures AppIcon et AppWindow), ou vaut 0 si une erreur est survenue.

  • Pour retirer un AppMenu, on utilise naturellement RemoveAppMenuItem(), qui prend en A0 la valeur renvoyée par AddAppMenuItemA().

  • Pour les AppWindows, on passe les mêmes paramètres à AddAppWindowA() qu'à AddAppMenuItemA(), sauf pour le texte (en A0), qui est remplacé par un pointeur sur une fenêtre Intuition (structure Window) déjà ouverte. La fenêtre du CLI (si elle n'est pas en mode AUTO) est un exemple tout à fait acceptable (encore faut-il savoir récupérer un pointeur sur cette fenêtre de façon "propre", en dialoguant avec le processus de console). En retour, on obtient un pointeur sur une structure AppWindow, on en a l'habitude. Naturellement, la fenêtre ne doit pas se fermer avant d'avoir été retirée de la liste des AppWindows du Workbench, grâce à la fonction RemoveAppWindow(), qui prend en paramètre le pointeur sur la structure AppWindow obtenu précédemment.
Un exemple

Le programme d'exemple que je vous propose est un lecteur de fichiers (très) rudimentaire (312 octets, qui dit mieux ?). Il ne peut être utilisé qu'à partir du CLI, pour pouvoir bénéficier de la console du CLI. Il affiche une AppIcon sur l'écran du Workbench et affiche tous les fichiers dont les icônes y sont déposées dans la fenêtre du CLI. Pour quitter le programme, un double-clic sur l'icône fait l'affaire. L'AppIcon est l'icône par défaut, libre à vous d'améliorer le programme en choisissant une icône plus belle, en gérant le démarrage à partir du Workbench (il faudra dans ce cas ouvrir une console). Vous pourriez aussi par exemple envoyer toutes les données vers l'imprimante (device PRT:) et ajouter un SegList-split (voir cet article) pour avoir un petit spooler d'imprimante...

	include	exec/exec.i
	include	exec/execbase.i
	include	exec/exec_lib.i
	include	dos/dos.i
	include	dos/dos_lib.i
	include	workbench/workbench.i
	include	workbench/icon_lib.i
	include	workbench/workbench_lib.i
	include	workbench/startup.i

	move.l	4.w,a6			; CLI uniquement !
	lea	DOS.Name(pc),a1
	moveq	#37,d0			; Kickstart 2.04+
	jsr	_LVOOpenLibrary(a6)
	move.l	d0,_DOSBase
	beq	exit
	lea	Workbench.Name(pc),a1
	moveq	#37,d0
	jsr	_LVOOpenLibrary(a6)
	move.l	d0,_WorkbenchBase
	beq	NoWBLib
	lea	Icon.Name(pc),a1
	moveq	#37,d0
	jsr	_LVOOpenLibrary(a6)
	move.l	d0,_IconBase
	beq	NoIconLib

	jsr	_LVOCreateMsgPort(a6)	; création d'un port
	move.l	d0,Icon.Port
	beq	NoPort
	move.l	_IconBase(pc),a6
	moveq	#WBTOOL,d0		; on réclame l'icône par défaut
	jsr	_LVOGetDefDiskObject(a6)
	move.l	d0,Icon.DiskObject
	beq	NoDiskOb
	move.l	_WorkbenchBase(pc),a6
	moveq	#0,d0			; on n'utilise pas ID et UserData
	move.l	d0,d1
	lea	Icon.Titre(pc),a0
	move.l	Icon.Port(pc),a1
	move.l	d0,a2
	move.l	Icon.DiskObject(pc),a3
	move.l	d0,a4
	jsr	_LVOAddAppIconA(a6)
	move.l	d0,Icon.AppIcon
	beq.s	NoAppIcon
	move.l	Icon.Port(pc),a4
	move.l	4.w,a6

Attente	move.l	a4,a0			; on attend le prochain message du WB
	jsr	_LVOWaitPort(a6)
Boucle	move.l	a4,a0
	jsr	_LVOGetMsg(a6)
	move.l	d0,a5
	tst.l	d0
	beq.s	Attente
	move.l	am_ArgList(a5),a3	; liste des icônes
	move.l	am_NumArgs(a5),d5	; leur nombre
	subq.l	#1,d5			; 0 icônes => double-clic => fin
	blt.s	Quitte
FichierSuivant
	bsr.s	LitFichier		; sinon on lit tous les fichiers
	addq.l	#wa_SIZEOF,a3		; un par un
	dbra	d5,FichierSuivant
	move.l	a5,a1			; ne pas oublier de répondre au Workbench
	jsr	_LVOReplyMsg(a6)
	bra.s	Boucle

Quitte	move.l	a5,a1
	jsr	_LVOReplyMsg(a6)
VidePort
	move.l	a4,a0			; on vide le port au cas où le WB aurait eu
	jsr	_LVOGetMsg(a6)		; le temps d'envoyer des messages
	move.l	d0,a1			; supplémentaires
	tst.l	d0
	beq.s	Fin
	jsr	_LVOReplyMsg(a6)
	bra.s	VidePort

Fin	move.l	Icon.AppIcon(pc),a0	; on ferme tout en sens inverse
	move.l	_WorkbenchBase(pc),a6	; de l'ouverture (c'est plus
	jsr	_LVORemoveAppIcon(a6)	; sûr)
NoAppIcon
	move.l	Icon.DiskObject(pc),a0
	move.l	_IconBase(pc),a6
	jsr	_LVOFreeDiskObject(a6)
NoDiskOb
	move.l	Icon.Port(pc),a0
	move.l	4.w,a6
	jsr	_LVODeleteMsgPort(a6)
NoPort	move.l	_IconBase(pc),a1
	jsr	_LVOCloseLibrary(a6)
NoIconLib
	move.l	_WorkbenchBase(pc),a1
	jsr	_LVOCloseLibrary(a6)
NoWBLib	move.l	_DOSBase(pc),a1
	jsr	_LVOCloseLibrary(a6)
exit	moveq	#0,d0
	rts

LitFichier	; LitFichier(WBArg)(A3)
	movem.l	d5-d7/a6,-(sp)
	move.l	_DOSBase(pc),a6
	jsr	_LVOOutput(a6)		; canal de sortie (fenêtre du CLI)
	move.l	d0,d7
	move.l	wa_Lock(a3),d1		; On se met dans le bon répertoire
	jsr	_LVOCurrentDir(a6)
	move.l	d0,d6
	move.l	wa_Name(a3),d1
	move.l	#MODE_OLDFILE,d2
	jsr	_LVOOpen(a6)		; on ouvre le fichier
	move.l	d0,d5
	beq.s	.NoFile
.LitChar
	move.l	d5,d1			; on copie caractère par caractère
	jsr	_LVOFGetC(a6)
	cmp.l	#-1,d0
	beq.s	.Fin
	move.l	d7,d1
	move.l	d0,d2
	jsr	_LVOFPutC(a6)
	bra.s	.LitChar
.Fin	move.l	d5,d1
	jsr	_LVOClose(a6)
.NoFile	move.l	d6,d1
	jsr	_LVOCurrentDir(a6)
	movem.l	(sp)+,d5-d7/a6
	rts

_DOSBase	dc.l	0
_WorkbenchBase	dc.l	0
_IconBase	dc.l	0
Icon.Port	dc.l	0
Icon.DiskObject	dc.l	0
Icon.AppIcon	dc.l	0

DOS.Name	dc.b	"dos.library",0
Workbench.Name	dc.b	"workbench.library",0
Icon.Name	dc.b	"icon.library",0
Icon.Titre	dc.b	"Lecteur",0



[Retour en haut] / [Retour aux articles]