Obligement - L'Amiga au maximum

Vendredi 23 mai 2025 - 04:33  

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 : C - Fenêtres Intuition et timer.device
(Article écrit par Denis Genot et extrait d'Amiga News Tech - août 1992)


L'inconvénient des fenêtres d'Intuition est qu'elles ne permettent pas de faire autre chose, par exemple une animation, pendant que l'on attend une réaction de l'utilisateur. En tout cas, pas directement...

Typiquement, un programme ouvre sa ou ses fenêtre(s), dessine un titre et quelques gadgets, puis attend patiemment que l'utilisateur veuille bien se décider à lui faire part de ses désirata. Cette attente s'effectue généralement par l'une des deux méthodes suivantes (qui sont d'ailleurs parfaitement équivalentes) :

WaitPort(Window->UserPort);

Ou

Wait(1L << Win->UserPort->mp_SigBit);

L'ennui, c'est que l'on n'a plus la main car le programme est gelé tant qu'un évènement n'a pas lieu... Impossible donc de faire, par exemple, une animation pendant ce temps.

Première solution

La première solution consiste à mettre le drapeau IDCMP INTUITICKS dans la structure NewWindow de la fenêtre à ouvrir : il demande à Intuition d'envoyer un message au propriétaire de la fenêtre tous les (en gros) 1/50e de seconde.

Avantage de la méthode : elle est très simple à mettre en oeuvre (l'intuition.library suffit amplement).

Inconvénient : le message INTUITICKS n'est envoyé qu'à une seule fenêtre, celle active au moment de l'évènement. Si l'utilisateur délaisse votre programme quelques instants, plus de messages, donc plus d'animation.

Seconde solution

La seconde solution utilise le timer.device pour demander au système d'être prévenu quand un certain délai s'est écoulé.

Avantage : cela fonctionne tout le temps, que notre fenêtre soit active ou pas.

Inconvénient : c'est un peu plus difficile à mettre en oeuvre. On n'a rien sans rien !

Pour utiliser le timer.device, on aura pris soin :
  • D'initialiser une structure "timerequest" pour envoyer la demande au système.
  • D'initialiser une structure "timeval" avec le délai voulu.
  • D'initialiser une structure "msgPort" pour obtenir la réponse.
  • D'ouvrir le timer.device, bien sûr !
L'envoi de la demande, qui peut se traduire par "préviens-moi quand le délai sera écoulé", se fait avec la fonction SendIO(), qui présente, contrairement à DoIO(), l'avantage d'être asynchrone (keskidi ?).

Avec DoIO(), le programme est interrompu tant que la demande n'est pas satisfaite, ce qui dans notre exemple empêcherait de gérer les gadgets en attendant le délai (requête synchrone). Avec SendIO(), le programme continue tranquillement d'être exécuté, ce qui permet de tester les gadgets, le clavier, l'arrivée de sa belle-mère... (requête asynchrone, vous l'aviez compris).

Quand le délai s'est écoulé (toutes les demi-secondes dans l'exemple), on reçoit un signal et la demande est interrompue, puisque le travail du timer.device est fini. Ce qui signifie que pour récidiver, il faudra envoyer une nouvelle demande par la même méthode. Ceci sera fait après avoir changé l'image si l'on veut faire une animation, ou après avoir affiché le nombre de secondes dans le cas de l'exemple.

Note : le délai peut être précisé à la microseconde près, mais il ne doit en aucun cas être inférieur à 3 microsecondes sous peine de l'Amiga... rou !

Quand on arrête ce cycle infernal (parce que la belle-mère est arrivée ?), il faut prendre soin de vérifier que le timer.device a fini son travail avec AbortIO() ("abandonne la demande"), puis waitIO() ("attends que tout soit OK").

Remarque : notre fenêtre comporte ici le drapeau "RMBTRAP", qui évite la gestion des menus déroulants, car sinon, tant que le bouton droit de la souris est maintenu enfoncé, le compteur de secondes est gelé.

Pour en savoir plus

Le timer.device mesure le temps de deux façons, soit avec l'interruption de balayage écran (UNIT_VBLANK), soit à l'aide d'un CIA 8520 (UNIT_MICROHZ).

Le chronomètre VBLANK est assez fiable pour de longues périodes (20 secondes par exemple) et sa précision est de l'ordre de 17 millisecondes (17 000 microsecondes), ce qui le rend peu efficace sur de courtes périodes.

Le chronomètre MICROHZ, quant à lui, est d'une grande précision sur de courtes périodes, mais moins fiable sur de grandes périodes, surtout si plusieurs tâches tournent en même temps.

Dans les deux cas, le délai est compté à partir de l'instant où la demande est reçue par le périphérique logique, le nombre de microsecondes devant être inférieur à 1 million (1 million de microsecondes = 1 seconde !).

/***************************************************
*   fenêtre Intuition et timer.device              *
*        par D. GENOT                              *
*   opt : -L                                       *
***************************************************/

#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <graphics/text.h>
#include <graphics/gfxbase.h>
#include <graphics/rastport.h>
#include <devices/timer.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/**********************
*     define          *
**********************/
#define WLARG 640
#define WHAUT 240

#define RP Window->RPort

/*********************
*   structures       *
*********************/
struct IntuitionBase *IntuitionBase=NULL;
struct GfxBase *GfxBase=NULL;
struct Screen *Screen=NULL;
struct Window *Window=NULL;
struct IntuiMessage *msg;

struct timerequest *tr=NULL;  /* timer Request   */
struct timeval *time;   /* délai d'attente */
struct MsgPort *tport;  /* pour signaux    */

LONG T_Dev;             /* device ouvert ? */

extern struct Window *OpenWindow();  
extern struct Screen *OpenScreen();

/********************
*  declarations     *
********************/
void openall();
void cleanexit();
void PrintIT(struct IntuiText *,int,int);

void attente();

/*********************************
* variables : nombres et chaines *
*********************************/

ULONG classe;       /* IDCMP */
USHORT code;        /* keys  */

char s[201];       /* pour 'storage' des messages */

/*********************************
*  structures                    *
*********************************/

struct TextAttr Font=
	{
	"topaz.font",8,	/* nom + hauteur */
	0,0				/* style + flags */
	};

struct NewScreen NewScreen=    /* def. et init. immediate */
  	{
	0,0,           /*  sommet gche , haut */
	640,256,       /* largeur et hauteur */
	3,             /* nbre de plans de bits  */
	0,1,           /*    couleurs        */ 
	HIRES,         /*      mode          */
	CUSTOMSCREEN,  /*      type          */
	&Font,          /*  fontes perso      */
	"   @ D. G. SoftWare 1991 , Programmation d'une ANIM...  ",/* titre */
	NULL,          /*   gadgets          */
	NULL          /*     bitmap         */
	}; 

struct NewWindow NewWindow=
{
0,				/* LeftEdge */
12,				/* TopEdge  */
WLARG,			/* Width    */
WHAUT,			/* Height   */
4,6,				/* DetailPen,BlockPen */
CLOSEWINDOW | VANILLAKEY ,/* IDCMPFflags */
SMART_REFRESH | ACTIVATE |
 NOCAREREFRESH | WINDOWCLOSE | BORDERLESS |
 SIZEBRIGHT |
 RMBTRAP ,		/* flags    */
 
 /******** RMBTRAP est nécessaire pour timer.device qui bloque 
           sinon à l'appui de R Mouse ...       *************/
           
NULL,			/* first gadget       */
NULL,			/* check mark         */
NULL,			 /* titre */
NULL,			  /* pteur ecran perso ouvert */
NULL,			/* bitmap   */
80,25,			/* MinWidth , MinHeight */
640,256,			/* MaxWidth , MaxHeight */
CUSTOMSCREEN		/* type */
};

struct IntuiText bleu=
{6,0,JAM2,0,0,0,&s[0],NULL};		/* en bleu pale */

struct IntuiText rouge=
{3,0,JAM2,0,0,0,&s[0],NULL};		/* en rouge */

USHORT couleurs[8]=
{0x334,0xfff,0x000,0xf80,0x00f,0x0f0,0x0ff,0xf5f};
/* gris,blanc,noir,orange,bleu f,vert,bleu c,rose */
/*  0  ,  1  ,  2  ,  3  ,  4   ,  5 ,  6   ,  7  */

/******* routines ***********************/

void PrintIT(texte,ab,or)
struct IntuiText *texte;
int ab,or;
{
	PrintIText(RP,texte,(SHORT)ab,(SHORT)or);
}

void cleanexit()
{
if( !T_Dev )
   CloseDevice((struct IORequest *)tr);
if( tr )
   DeleteExtIO(tr);
if( tport )
   DeletePort(tport);
if( time )
   FreeMem(time,sizeof(struct timeval));
if(Window)
	CloseWindow(Window);
if(Screen)
	CloseScreen(Screen);
if(IntuitionBase)
	CloseLibrary((struct Library *)IntuitionBase);
if(GfxBase)
	CloseLibrary((struct Library *)GfxBase);
exit(0);
}

void openall()
{
   
 IntuitionBase=(struct IntuitionBase *)
	OpenLibrary("intuition.library",0);
 if (IntuitionBase==NULL)
 	exit(0);

 if((GfxBase=(struct GfxBase *)
	OpenLibrary("graphics.library",0))==NULL)
	cleanexit();

 if ((Screen=OpenScreen(&NewScreen))==NULL)
 	cleanexit();

 NewWindow.Screen=Screen;
 if ((Window=OpenWindow(&NewWindow))==NULL)          
	cleanexit();               /*  si raté !! */

 LoadRGB4(&Screen->ViewPort,couleurs,8);

 time=(struct timeval *)AllocMem(sizeof(struct timeval),MEMF_PUBLIC | MEMF_CLEAR);
 if( !time )
   cleanexit();
 time->tv_secs =0;
 time->tv_micro=500000; /* 0,5 seconde */

 tport=(struct MsgPort *)CreatePort(0,0);
 if( !tport )
 {
   T_Dev=NULL;
   cleanexit();
 }
   
 tr=(struct timerequest *)CreateExtIO(tport,sizeof(struct timerequest));
 if( !tr )
 {
   T_Dev=NULL;
   cleanexit();
 } 
 tr->tr_time=*time;

 T_Dev=OpenDevice(TIMERNAME,UNIT_MICROHZ,(struct IORequest *)tr,0L);
 if( T_Dev )    /*   0   si OK  */
  cleanexit();
   
}

void attente()
{

   BOOL fini=FALSE;
   ULONG Wmask=1L << Window->UserPort->mp_SigBit;
   ULONG Tmask=1L << tport->mp_SigBit;
   ULONG Signal_recu;
   ULONG sec=0;
   ULONG dix=0; /* secondes et dixièmes */

   time->tv_secs =0;
   time->tv_micro=500000; /* 0,5 seconde */
   tr->tr_time=*time;
   tr->tr_node.io_Command=TR_ADDREQUEST;
   SendIO( (struct IORequest *)tr );   /* 1er envoi */
         
   do
	{
	   Signal_recu=Wait( Wmask | Tmask );
      
      if( Signal_recu & Wmask ) /* dans FENETRE */
      {
	     while(msg=(struct IntuiMessage *)GetMsg(Window->UserPort))
        { 
	       classe=msg->Class;                      
          code=msg->Code;
	      
          ReplyMsg((struct Message *)msg);
         
          switch(classe)
          {
            case VANILLAKEY:
               switch(code)
               {
                  case 'Q':
                  case 'q':
                    fini=TRUE;
                    break;
                  default:
                    sprintf(s,"dernière touche : '%c'",code);
                    PrintIT(&bleu,50,150);
                    break;
               }
               break;
            case CLOSEWINDOW:
               fini=TRUE;
               break;
            default:
               break;
          }
        } /* end while( msg ) */
      } /* end if( Wmask ) */

      if( Signal_recu & Tmask ) /* DELAI ecoulé */
      {
         dix+=5;
         if( dix==10 )
         {
            dix=0;
            sec++;
         }
         sprintf(s,"secondes : %3d,%d",sec,dix);
         PrintIT(&rouge,50,50);

         time->tv_secs =0;
         time->tv_micro=500000; /* 0,5 seconde */
         tr->tr_time=*time;
         tr->tr_node.io_Command=TR_ADDREQUEST;
         SendIO( (struct IORequest *)tr );   /* remettez-nous ça ! ! */
      } /* end if( Tmask ) */

	}while( !fini );	   
   
   if( !CheckIO(tr) )
      AbortIO(tr);   /* arrete la demande en cours */
   WaitIO(tr);       /* attend t_request OK     */
}

/***********  MAIN  ********************/

void main()
{
   openall();
   
   attente();
   
   cleanexit();
}

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/antintuitionandtimer.lha.


[Retour en haut] / [Retour aux articles]