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 - 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.
|