Corso di AmigaOS

Torna all'elenco delle lezioniPer dubbi, consigli o richieste, potete mandare un'e-mail ad Andrea Carolfi.
Ringraziamo Amiga Transactor Mailing List per questo tangibile contributo!


Intuition (Nona lezione)

Dopo aver visto le strutture principali dell'AmigaDOS e di Exec e le relative procedure e funzioni messe a disposizione per gestirle, oggi cominceremo a trattare un'altra parte dell'AmigaOS molto importante: Intuition.
Intuition e tutte le sue sottoparti sia di sistema che esterne (MUI, ClassAct, ecc.) gestiscono l'interfaccia utente mettendo a disposizione delle strutture basi semplici che possono essere usate per creare strutture più complesse.
Gli elementi principali di Intuition sono:

  1. bordi
  2. bottoni
  3. immagini
  4. finestre
  5. schermi
  6. menù

bordi ed immagini li trascuriamo un momento.
I bottoni possono essere di vario tipo (ciclici, stringa, booleani, semplici, ecc..), le finestre possono essere configurate in vari aspetti e così pure gli schermi possono essere di vari tipi (risoluzione, numero di colori ecc ecc). Infine i menù possiedono tre livelli: menù, opzione e sotto opzione.
Possiamo vedere tutto questo in un contesto gerachico ad albero:

             Intuition
            /         \
          schermo     schermo
          /    \          \
        finestra   finestra   finestra
        /     \        \
    menù   bottoni   bottoni

Come si può vedere, alla base di tutto vi è Intuition, sopra di essa vi possono stare tutte quelle librerie che servono per facilitare al programmatore la creazione di una interfaccia grafica, quali gadtools.library, mui.library, e compagnia.
Subito dopo ci sono gli schermi, le finestre possono essere aperte solo sugli schermi.
Il primo schermo che viene automaticamente creato al boot è ovviamente lo schermo del Workbench. Ogni schermo può avere un numero variabile di finestre, ovviamente più la lista delle finestre presenti cresce più diventa laborioso gestirla. Però il sistema non pone dei limiti. Ogni finestra a sua volta può avere più strisce di menù (ma solo una alla volta attiva) e più liste di bottoni (anche quì solo una lista per volta).
Il numero massimo di questi oggetti che si possono creare ovviamente varia a seconda della quantità di memoria disponibile. Esistono però dei vincoli dettati dal sistema ossia: in una striscia di menù vi possono essere al massimo 32 menù, per ogni menù 64 opzioni e per ogni opzione 32 sotto opzioni. Questo perchè ogni voce viene identificata con una UWORD (una parola senza segno) "costruita" in questo modo:

|------------- 16 --------------|
 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|

| submenù |  opzione  |   menù  |
|--- 5 ---|---- 6 ----|--- 5 ---|

Per poter convertire un "codice di menù" nella relativa rappresentazione menù -> opzione -> sotto opzione e viceversa sono definite delle macro apposite nel file intuition/intuition.h. Queste sono: FULLMENUNUM(menu,item,sub), MENUNUM(code), ITEMNUM(code), SUBNUM(code).

Un'altra "limitazione" sono il numero di bottoni che si possono aggiungere ad una finestra: "solo" 65536. Questo perchè viene utilizzata una UWORD in alcune chiamate di sistema e nel campo GadgetID della struttura Gadget che vedremo in seguito.
In realtà, visto che quando viene premuto un bottone Intuition restituisce il suo indirizzo e non il suo ID, è possibile infrangere a proprio rischio quel limite.
Onestamente credo che una finestra con più di 65536 gadget sia difficile da creare ma non si sa mai... (a meno di non utilizzare un PowerPC G3 e una scheda grafica ogni volta che verrebbe spostata ci vorrebbero una decina di minuti per ridisegnarla :-) ).

Cominciamo dunque ad analizzare l'albero a partire dalla radice, ovvero dalla struttura Intuition:

/* ======================================================================== */
/* === IntuitionBase ====================================================== */
/* ======================================================================== */
/*
 * Be sure to protect yourself against someone modifying these data as
 * you look at them.  This is done by calling:
 *
 * lock = LockIBase(0), which returns a ULONG.  When done call
 * UnlockIBase(lock) where lock is what LockIBase() returned.
 */

/* This structure is strictly READ ONLY */
struct IntuitionBase
{
         struct Library LibNode;

         struct View ViewLord;

         struct Window *ActiveWindow;
         struct Screen *ActiveScreen;

         /* the FirstScreen variable points to the frontmost Screen.  Screens are
          * then maintained in a front to back order using Screen.NextScreen
          */
         struct Screen *FirstScreen; /* for linked list of all screens */

         ULONG Flags;  /* values are all system private */
         WORD MouseY, MouseX;
                        /* note "backwards" order of these     */

         ULONG Seconds;   /* timestamp of most current input event */
         ULONG Micros; /* timestamp of most current input event */

         /* I told you this was private.
          * The data beyond this point has changed, is changing, and
          * will continue to change.
          */
};

può essere utile dover accedere a queste informazioni magari per realizzare qualche
patch o altro.
 
La successiva struttura in ordine di importanza è quella che descrive uno schermo:

/* ======================================================================== */
/* === Screen ============================================================= */
/* ======================================================================== */

/* VERY IMPORTANT NOTE ABOUT Screen->BitMap.  In the future, bitmaps
 * will need to grow.  The embedded instance of a bitmap in the screen
 * will no longer be large enough to hold the whole description of
 * the bitmap.
 *
 * YOU ARE STRONGLY URGED to use Screen->RastPort.BitMap in place of
 * &Screen->BitMap whenever and whereever possible.
 */

struct Screen
{
         struct Screen *NextScreen;      /* linked list of screens */
         struct Window *FirstWindow;     /* linked list Screen's Windows */

         WORD LeftEdge, TopEdge;      /* parameters of the screen */
         WORD Width, Height;       /* parameters of the screen */

         WORD MouseY, MouseX;      /* position relative to upper-left */

         UWORD Flags;        /* see definitions below */

         UBYTE *Title;       /* null-terminated Title text */
         UBYTE *DefaultTitle;      /* for Windows without ScreenTitle */

         /* Bar sizes for this Screen and all Window's in this Screen */
         /* Note that BarHeight is one less than the actual menu bar
          * height. We're going to keep this in V36 for compatibility,
          * although V36 artwork might use that extra pixel
          *
          * Also, the title bar height of a window is calculated from the
          * screen's WBorTop field, plus the font height, plus one.
          */
         BYTE BarHeight, BarVBorder, BarHBorder, MenuVBorder, MenuHBorder;
         BYTE WBorTop, WBorLeft, WBorRight, WBorBottom;

         struct TextAttr *Font;    /* this screen's default font    */

         /* the display data structures for this Screen */
         struct ViewPort ViewPort;    /* describing the Screen's display */
         struct RastPort RastPort;    /* describing Screen rendering      */
         struct BitMap BitMap;     /* SEE WARNING ABOVE!         */
         struct Layer_Info LayerInfo; /* each screen gets a LayerInfo    */

         /* Only system gadgets may be attached to a screen.
          *   You get the standard system Screen Gadgets automatically
          */
         struct Gadget *FirstGadget;

         UBYTE DetailPen, BlockPen;      /* for bar/border/gadget rendering */

         /* the following variable(s) are maintained by Intuition to support the
          * DisplayBeep() color flashing technique
          */
         UWORD SaveColor0;

         /* This layer is for the Screen and Menu bars */
         struct Layer *BarLayer;

         UBYTE *ExtData;

         UBYTE *UserData; /* general-purpose pointer to User data extension */

         /**** Data below this point are SYSTEM PRIVATE ****/
};

Prima di andare avanti occorre dare una premessa: dato che il sistema operativo di Amiga è molto complesso e molte parti di esso sono correlate ed intrecciate tra loro, non si può capire a fondo il contenuto di questa struttura senza parlare delle librerie graphics.library e layer.library.
Per il momento però, visto che questa ed altre strutture vengono inizializzate per noi in base a nostri parametri da procedure di Intuition, le posticiperemo. Questo perchè vorrei darvi la possibilità di realizzare già da queste puntate dei piccoli programmini con la propria interfaccia. Se avessi introdotto la graphics.library prima di Intuition (come in realtà andrebbe fatto visto che si trova ad un livello più basso) si sarebbero "perse" molte puntate per descrivere questa libreria che è tutta importante e molto grossa.

Vediamo quindi la procedura che ci mette a disposizione Intuition per aprire degli schermi: OpenScreenTagList. In realtà questa procedura poggia sulla sua sorella OpenScreen, ma visto che aprire schermi con la OpenScreenTagList è di gran lunga molto più semplice e flessibile, trascurerò volutamente questa procedura.
Vediamo la struttura TagItem utilizzata (dal file utility/tagitem.h):

typedef ULONG Tag;

struct TagItem
{
         Tag    ti_Tag;   /* identifies the type of data */
         ULONG ti_Data;   /* type-specific data          */
};

Ed ora la sintassi della procedura:

Screen = OpenScreenTagList(NewScreen,TagItems);
  D0                           A0       A1

struct Screen *OpenScreenTagList(struct NewScreen *,struct TagItem *);

Screen = OpenScreenTags(NewScreen, Tag1, ... );

struct Screen *OpenScreenTags(struct NewScreen *,ULONG, ... );

Perchè due versioni della stessa procedura? Perchè come molte altre procedure del sistema operativo, a partire dalla versione 2.0 accettano parametri sottoforma di TagItem in due modi diversi, il primo consente di passare i parametri sui registri (come mostrato dalle lettere poste sotto i parametri) il secondo sullo stack. Per fare un esempio concreto:

primo metodo)

        struct TagItem tags[] = {SA_Width,320,SA_Height,200,TAG_DONE};
        struct Screen *scr;

        [...]

        if((scr = OpenScreenTagList(NULL,tags)))

        [...]

secondo metodo)

        struct Screen * scr;

        [...]

        if((scr = OpenScreenTags(NULL,
                SA_Width,   320,
                SA_Height,  200,
                TAG_DONE)))

        [...]

Entrambi i metodi hanno i loro pregi e difetti. Il primo genererà un codice più compatto quando troverà la chiamata alla OpenScreenTagList ma obbliga il programmatore a dichiarare una variabile in più. Il secondo genererà del codice più lungo (perchè deve mettere diversi parametri sullo stack, invece di due puntatori nei registri) ma ha il vantaggio di essere più semplice da gestire. Scrivendo la chiamata come mostrato, per esempio è possibile abilitare/disabilitare dei tag semplicemente anteponendo un // (commento C++) o racchiuderlo tra /* */, non solo: è possibile utilizzare l'operatore ternario per modificare un flag al volo a seconda di determinate condizioni tipo:
SA_Title,piripì_piripò?"Titolo1":"Titolo2"e così via.
Infine, siccome alcuni tag vogliono come valore un puntatore, utilizzando il primo metodo, siccome il C non permette di inizializzare un array con un puntatore, bisognerebbe fare:


        struct TagItem tags[] = {SA_ErrorCode,NULL,TAG_DONE};
        LONG errcode;

        [...]

        tags[0].ti_Data = (ULONG)&errcode;
che secondo me è un pò scomodo ma nessuno vieta. :-)

Vediamo dunque i tags principali (sono definiti nel file intuition/screens.h e descritti uno per uno nell'autodoc di intuition ovviamente sotto la descrizione della procedura OpenScreen (per i motivi citati prima)):

SA_Left, SA_Top,SA_Width,SA_Height
A partire dalla versione 2.0 del sistema operativo è possibile specificare non solo le dimensioni di uno schermo ma anche la sua posizione (prima della V36, il campo LeftEdge doveva essere zero).

SA_Depth
Profondità dello schermo espressa in numero di piani (purtroppo la gestione della grafica di Amiga è planare. Una volta poteva essere utile avere schermi con 16 o meno colori ma adesso si fa sentire la mancanza della gestione chunky = velocità di accesso).

SA_Title
Titolo dello schermo.

SA_ErrorCode
Come nell'esempio mostrato prima, è molto utile per determinare la causa del fallimento dell'apertura dello schermo.

SA_Font
Carattere (vedremo più in là come si aprono) da utilizzare nello schermo.

SA_SysFont
Se volete usare il font scelto dall'utente (e quindi aperto) specificate come valore 1, se amate il topaz otto 0. :-)

SA_Type
Se volete che il vostro schermo sia pubblico (ossia che finestre di altri programmi possono venire aperte sul vostro schermo) specificate PUBLICSCREEN, CUSTOMSCREEN altrimenti.

SA_BitMap
Se volete allocarvi da soli la bitmap da utilizzare con questo schermo, specificate il puntatore alla vostra bitmap come valore di questo tag (vedremo nelle puntate dedicate alla graphics.library come si alloca una bitmap).

SA_PubName
Nome pubblico dello schermo (quello che uno deve specificare nella LockPubScreen per poter ottenere il puntatore al vostro schermo). Da specificare PRIMA dei due tag seguenti.

SA_PubSig
Valore che vogliamo sia specificato quando viene chiusa l'ultima finestra visitatrice presente sul nostro schermo.

SA_PubTask
Il task che deve essere notificato quando l'ultima finestra presente sullo schermo pubblico viene chiusa. Se non specificato viene assunto come task quello che ha chiamato la OpenScreenTagList.

SA_DisplayID
ID dello schermo da aprire. Quelli di default sono specificati nei file graphics/displayinfo.h> per la V37 o per la V39 e superiori.
Altri sono ritornati dal display database e possono essere scelti usando uno screen mode requester della libreria asl.library che vedremo più in là. è con questo ID che è possibile scegliere uno schermo prodotto da una scheda grafica.

Tag booleani:

SA_ShowTitle
Lo schermo deve mostrare o no la barra del titolo?

SA_Behind
Lo schermo deve essere aperto dietro tutti gli altri?

SA_Quiet
Se specificato a TRUE, in congiunzione con il flag WFLG_RMBTRAP posto a tutte le finestre presenti sul nostro schermo, impedirà la visualizzazione della barra dei menù quando l'utente preme il tasto destro del mouse. Utile per esempio per un gioco dove vogliamo che con il tasto destro succeda qualcosa di diverso che la comparsa della barra dei menù.

SA_AutoScroll
Se specifichiamo delle dimensioni di schermo maggiori di quelle disponibili per il modo video richiesto, impostando a TRUE questo tag, quando sposteremo agli estremi dello schermo il puntatore del mouse l'area video traslerà verso quella direzione.

SA_Draggable
Se vogliamo che lo schermo non sia trascinabile, basta impostare questo tag a TRUE.

SA_Exclusive
Se vogliamo che quando si abbassa uno schermo davanti al nostro questo non venga mostrato, bisogna valorizzare questo tag a TRUE. Ovviamente è ancora possibile ciclare tra gli schermi con il tasti Amiga - M.

SA_LikeWorkbench
Infine, se vogliamo che il nostro schermo sia uguale uguale :-) a quello del WB, basta specificare questo tag. Avremo quindi uno schermo con la stessa modalità video, profondità, dimensione, colori ecc. E' possibile non tener conto di questi valori specificando i tag relativi, ad esempio SA_Width non tiene conto della larghezza dello schermo del Workbench. Bisogna però fare attenzione alle supposizioni che si fanno perchè lo schermo del WB potrebbe avere o no degli attributi che vogliamo o no nel nostro schermo. Per esempio, se vogliamo utilizzare la risoluzione del WB ma con meno colori, potremmo ottenere dei colori di sistema sballati.

Non curante della lunghezza di questa lezione :-) proseguiamo con la OpenWindowTagList, anche perchè se mi fermassi quì avreste uno schermo aperto senza niente. :-)

La sintassi della OpenWindowTagList è la stessa della OpenScreenTagList salvo il tipo della struttura ritornata e della struttura NewWindow opzionale (al posto della NewScreen).
Vediamo quindi la struttura Window:


/* ======================================================================== */
/* === Window ============================================================= */
/* ======================================================================== */
struct Window
{
         struct Window *NextWindow;      /* for the linked list in a screen */

         WORD LeftEdge, TopEdge;      /* screen dimensions of window */
         WORD Width, Height;       /* screen dimensions of window */

         WORD MouseY, MouseX;      /* relative to upper-left of window */

         WORD MinWidth, MinHeight;    /* minimum sizes */
         UWORD MaxWidth, MaxHeight;      /* maximum sizes */

         ULONG Flags;        /* see below for defines */

         struct Menu *MenuStrip;      /* the strip of Menu headers */

         UBYTE *Title;       /* the title text for this window */

         struct Requester *FirstRequest; /* all active Requesters */

         struct Requester *DMRequest; /* double-click Requester */

         WORD ReqCount;         /* count of reqs blocking Window */

         struct Screen *WScreen;      /* this Window's Screen */
         struct RastPort *RPort;      /* this Window's very own RastPort */

         /* the border variables describe the window border.  If you specify
          * WFLG_GIMMEZEROZERO when you open the window, then the upper-left of
          * the ClipRect for this window will be upper-left of the BitMap (with
          * correct offsets when in SuperBitMap mode; you MUST select
          * WFLG_GIMMEZEROZERO when using SuperBitMap).  If you don't specify
          * ZeroZero, then you save memory (no allocation of RastPort, Layer,
          * ClipRect and associated Bitmaps), but you also must offset all your
          * writes by BorderTop, BorderLeft and do your own mini-clipping to
          * prevent writing over the system gadgets
          */
         BYTE BorderLeft, BorderTop, BorderRight, BorderBottom;
         struct RastPort *BorderRPort;


         /* You supply a linked-list of Gadgets for your Window.
          * This list DOES NOT include system gadgets.  You get the standard
          * window system gadgets by setting flag-bits in the variable Flags (see
          * the bit definitions below)
          */
         struct Gadget *FirstGadget;

         /* these are for opening/closing the windows */
         struct Window *Parent, *Descendant;

         /* sprite data information for your own Pointer
          * set these AFTER you Open the Window by calling SetPointer()
          */
         UWORD *Pointer;  /* sprite data */
         BYTE PtrHeight;  /* sprite height (not including sprite padding) */
         BYTE PtrWidth;   /* sprite width (must be less than or equal to 16) */
         BYTE XOffset, YOffset; /* sprite offsets */

         /* the IDCMP Flags and User's and Intuition's Message Ports */
         ULONG IDCMPFlags;   /* User-selected flags */
         struct MsgPort *UserPort, *WindowPort;
         struct IntuiMessage *MessageKey;

         UBYTE DetailPen, BlockPen;   /* for bar/border/gadget rendering */

         /* the CheckMark is a pointer to the imagery that will be used when
          * rendering MenuItems of this Window that want to be checkmarked
          * if this is equal to NULL, you'll get the default imagery
          */
         struct Image *CheckMark;

         UBYTE *ScreenTitle; /* if non-null, Screen title when Window is active */

         /* These variables have the mouse coordinates relative to the
          * inner-Window of WFLG_GIMMEZEROZERO Windows.  This is compared with the
          * MouseX and MouseY variables, which contain the mouse coordinates
          * relative to the upper-left corner of the Window, WFLG_GIMMEZEROZERO
          * notwithstanding
          */
         WORD GZZMouseX;
         WORD GZZMouseY;
         /* these variables contain the width and height of the inner-Window of
          * WFLG_GIMMEZEROZERO Windows
          */
         WORD GZZWidth;
         WORD GZZHeight;

         UBYTE *ExtData;

         BYTE *UserData;  /* general-purpose pointer to User data extension */

         /** 11/18/85: this pointer keeps a duplicate of what
          * Window.RPort->Layer is _supposed_ to be pointing at
          */
         struct Layer *WLayer;

         /* NEW 1.2: need to keep track of the font that
          * OpenWindow opened, in case user SetFont's into RastPort
          */
         struct TextFont *IFont;

         /* (V36) another flag word (the Flags field is used up).
          * At present, all flag values are system private.
          * Until further notice, you may not change nor use this field.
          */
         ULONG   MoreFlags;

         /**** Data beyond this point are Intuition Private.  DO NOT USE ****/
};

ed i tag più importanti per aprire una finestra:

WA_Left, WA_Top, WA_Width, WA_Height

Posizione e dimensione della finestra.

WA_IDCMP

Vi ricordate la lezione sui messaggi? Ecco dunque dove vanno a finire. Gli IDCMP (l'acronimo sta per Intuition Direct Communication Message Port), sono i vari messaggi che Intuition può comunicare al nostro task a seconda dei determinati eventi che l'utente crea.
La definizione di questi si trovano sempre nel file intuition/intuition.h e spiegati nella sezione dedicata alla funzione ModifyIDCMP dell'autodoc di Intuition ma vediamone comunque alcuni:

  • IDCMP_MENUPICK - selezione di un menù
  • IDCMP_GADGETDOWN - pressione di bottone
  • IDCMP_GADGETUP - rilascio di un bottone
  • IDCMP_CLOSEWINDOW - pressione del bottone di chiusura della finestra

Possono essere specificati in congiunzione utilizzando l'or bit a bit | del C.

WA_Flags
Flag che determinano l'aspetto ed il comportamento della finestra (definiti in intuition/intuition.h e spiegati nella sezione della funzione OpenWindow). Anche questi possono essere 'sommati' con l'or bit a bit del C. Vediamone alcuni:

WFLG_SIZEGADGET gadget di ridimensionamento presente
WFLG_DRAGBAR barra del titolo
WFLG_DEPTHGADGET bottone di primo piano/sfondo
WFLG_CLOSEGADGET bottone di chiusura
WFLG_SIZEBRIGHT l'eventuale gadget di ridimensionamento usa il bordo destro
WFLG_SIZEBBOTTOM l'eventuale gadget di ridimensionamento usa il bordo inferiore possono essere specificati entrambi. Se nessuno di essi viene specificato, il valore predefinito è WFLG_SIZEBRIGHT.
WFLG_SMART_REFRESH veloce ma più dispendioso in termine di memoria
WFLG_SIMPLE_REFRESH semplice ma incompleto (alcuni gadget devono essere ridisegnati dal programmatore).
WFLG_BACKDROP finestra particolare sullo sfondo di tutte le altre (quella del Workbench è una finestra Backdrop = Pannello se si seleziona dal menù Workbench l'opzione relativa.
WFLG_REPORTMOUSE insieme all'IDCMP_MOUSEMOVE, quando la nostra finestra è attiva riceveremo un messaggio ad ogni spostamento del mouse.
WFLG_GIMMEZEROZERO un modo dispendioso per effettuare dell'output (grafico) sulla finestra. Se la nostra finestra ha i bordi, ogni output grafico deve essere "shiftato" considerando queste dimensioni, altrimenti si sovrascrivono i bordi (ecco perchè nella struttura Window sono definiti i campi BorderTop e BorderLeft ;-) ). Specificando questo flag, possiamo tranquillamente partire da 0,0, (angolo in alto a sinistra) senza curarci di quanto grossi siano i bordi.
WFLG_BORDERLESS se vogliamo una finestra senza bordi. Utile insieme a WFLG_BACKDROP. Entrambi sono molto utili per aprire una finestra che occupi l'intero schermo ad esempio per realizzare un gioco.
WFLG_ACTIVATE all'apertura questa finesta diventa attiva
WFLG_RMBTRAP per piazzare la "trappola" al tasto destro del mouse. In questo modo saranno gestiti come eventi e non selezione di un menù.
WFLG_NEWLOOKMENUS se la nostra finestra ha dei menù, specificando questo flag verranno colorati nel nuovo modo (di default barra bianca e testo nero), altrimenti nel modo vecchio: barra nera e testo grigio.



WA_Gadgets
Lista dei bottoni da collegare a questa finestra. Ovviamente devono essere creati PRIMA dell'apertura.

WA_Title
Titolo della finestra.

WA_ScreenTitle
Titolo dello schermo. "Come?" direte voi, è possibile specificare due titoli per lo schermo uno di default quando nessuna finesta è attiva ed uno da visualizzare per ogni finestra attiva in quel momento. Può essere molto comodo ad esempio, mostrare il nome dell'applicazione quando nessuna finestra è selezionata e mostrare una piccola descrizione sulla funzione svolta da quella particolare finestra quando questa è attiva.

WA_MinWidth,WA_MinHeight,WA_MaxWidth,WA_MaxHeight
Dimensioni minime e massime se la nostra finestra è ridimensionabile.

WA_PubScreenName
Nome dello schermo pubblico sul quale vogliamo aprire la finestra.

WA_PubScreen
Puntatore allo schermo pubblico sul quale vogliamo aprire la finestra. Se non è il nostro schermo aperto con la OpenScreenTagList, dobbiamo assicurarci che non venga chiuso o avendo già una finestra aperta su di esso o usando la LockPubScreen.
Infatti a partire dal 2.0, la CloseScreen si rifiuta di chiudere lo schermo se sono ancora presenti delle finestre su di esso, ritornando come valore FALSE.

Per concludere questa lunghissima lezione, un piccolissimo stralcio di codice, che illustri il tutto:

struct Screen *scr;
struct Window *win;
struct IntuiMessage *msg;
BOOL finito = FALSE;

if((scr = OpenScreenTags(NULL,SA_LikeWorkbench,TRUE,TAG_DONE)))
{
        if((win = OpenWindowTags(NULL,
                WA_IDCMP,      IDCMP_CLOSEWINDOW,
                WA_Flags,      WFLG_CLOSEGADGET,
                WA_PubScreen,  scr,
                TAG_DONE)))
        {
                while(!finito)
                {
                        WaitPort(win -> UserPort);
                        while((msg = (struct IntuiMessage *)GetMsg(win -> UserPort)))
                        {
                                switch(msg -> Class)
                                {
                                        case IDCMP_CLOSEWINDOW:
                                                finito = TRUE;
                                        break;
                                }
                                ReplyMsg((struct Message *)msg);
                        }
                }
                CloseWindow(win);
        }
        CloseScreen(scr);
}

Listato di questa lezione.

Lezione precedente Indice delle lezioni Lezione successiva
Copyright AMiWoRLD Ph0ton