13. Librerie di classi ====================== La funzione NewObject() di Intuition non e' in grado di caricare direttamente una classe boopsi esterna dalla directory "SYS:Classes/". Le classi boopsi esterne sono in realta' delle librerie di Exec, che devono essere aperte con OpenLibrary() prima di poter usare le classi in esse contenute. In genere queste librerie contengono solamente i primi quattro vettori di salto comuni a tutte le librerie di Exec, cioe' LibOpen(), LibClose(), LibExpunge() e LibExtFunc(). Niente vieta di includerne delle altre, come nel caso del colorwheel.gadget, che offre due utili funzioni per la conversione tra i sistemi di colore RGB e HSV. Le applicazioni che usano una classe esterna devono operare in questo modo: struct Library *MyClassBase; MyClassBase = OpenLibrary ("gadgets/myclass.gadget", 39); if (MyClassBase) { myobj = NewObject (NULL,"myclass.gadget", TAG_DONE); if (myobj) { [...usa l'oggetto...] DisposeObject (myobj); } CloseLibrary (MyClassBase); } La coppia di funzioni OpenLibrary()/CloseLibrary() garantisce che il codice della classe rimanga in memoria finche' esistono oggetti oggetti che ne fanno parte. Se piu' task tentano di utilizzare la classe applicando questo protocollo, la libreria verra' comunque caricata soltanto la prima volta che viene aperta e scaricata soltanto quando l'ultimo task la chiude. Al momento dell'inizializzazione, la libreria crea una nuova classe usando la funzione MakeClass() e la aggiunge alla lista delle classi pubbliche di Intuition chiamando AddClass(). E' anche possibile creare una libreria che contenga al proprio interno piu' classi correlate tra loro, per esempio un toolkit completo per l'interfaccia utente. Normalmente le classi boopsi esterne memorizzano il puntatore ritornato da MakeClass() all'interno della base della propria libreria, in modo da poterlo recuperare quando la libreria sara' espulsa dal sistema. In una pre-release del file include che avrebbe dovuto accompagnare la V42 di AmigaOS, e' presente una definizione standard della base per le classi boopsi: struct ClassLibrary { struct Library cl_Lib; UWORD cl_Pad; Class *cl_Class; }; Usando questa struttura, il puntatore alla classe puo' essere recuperato direttamente dalla base della libreria (cl_Class). Questo permette all'utilizzatore di invocare i metodi della classe che non richiedono la creazione di un oggetto specifico. Esistono anche alune classi boopsi, per esempio i datatypes, che forniscono una funzione che ritorna il puntatore alla classe, chiamata ObtainEngine() oppure GetEngine(). Questa funzione deve occupare il primo vettore libero della tavola di salto della libreria (offset -30). Dal momento che esistono due modi diversi di ottenere il puntatore alla classe, gli implementatori di classi dovrebbero supportarli entrambi. Su Aminet e nell'Amiga Developer CD 1.1 si possono trovare numerosi esempi di classi boopsi esterne. I sorgenti della classe esterna VectorGlyphIClass sono inclusi nel dischetto allegato alla rivista unitamente alla startup in assembler necessaria per creare una libreria condivisa senza alcun supporto diretto da parte del compilatore. 14. Sottoclassi della imageclass ================================ Creare una sottoclasse della imageclass e' piuttosto semplice. Per ottenere una classe che disegna qualcosa usando le funzioni della graphics.library, e' sufficiente implementare i metodi IM_DRAW e IM_DRAWFRAME, lasciando alla propria superclasse la gestione di tutti gli altri metodi. Un'immagine di questo tipo puo' essere usata ovunque Intuition richieda una struttura Image, per esempio all'interno di in un bottone boopsi (frbuttongclass). L'immagine puo' essere inserita nel gadget usando l'attributo GA_LabelImage (e non GA_Image, che serve invece per specificare il frame del bottone). Come abbiamo gia' detto in precedenza, le immagini boopsi hanno all'inizio della propria istanza una struttura Image. Intuition distingue le immagini boopsi da quelle normali controllando il valore del campo Depth dell'immagine: il costrutture della imageclass inizializza questo campo con il valore CUSTOMIMAGEDEPTH (-1). Quando le funzioni di Intuition che operano sulle strutture Image riconoscono questo valore, chiamano il dispatcher della classe anziche' disegnare l'immagine direttamente. 15. IM_DRAW =========== I metodi IM_DRAW e IM_DRAWFRAME sono associati ad un messaggio di tipo impDraw, contenente le informazioni necessarie per il disegno: struct impDraw { ULONG MethodID; struct RastPort *imp_RPort; struct { WORD X; WORD Y; } imp_Offset; ULONG imp_State; struct DrawInfo *imp_DrInfo; struct { WORD Width; WORD Height; } imp_Dimensions; }; Il campo imp_RPort contiene l'indirizzo della RastPort da usare per il disegno. imp_Offset.X e imp_Offset.Y contengono le coordinate da utilizzare come origine per l'immagine. Alcune immagini boopsi hanno dimensioni fisse, come ad esempio le bitmap o alcune immagini della sysiclass. Altre possono essere scalate solo in orizzontale o solo in verticale. Un esempio sotto gli occhi di tutti sono le immagini associate ai gadget di chiusura e di profondita' delle finestre di Intuition, che hanno una larghezza fissa ed un'altezza variabile per adattarsi al font utilizzato dallo schermo. Ci sono inoltre immagini boopsi che sono completamente scalabili sia in verticale che in orizzontale. Le immagini boopsi possono calcolare automaticamente le loro dimensioni ideali al momento della creazione, e memorizzare questi valori nei campi Width e Height della struttura Image ad esse associata (usando DoMethod(), non scrivendo direttamente nella struttura!). La superclasse provvedera' a riportare questi valori quando verranno letti con GetAttr(). In particolare, i bottoni boopsi possono assumere automatiamente le dimensioni corrette per contenere l'immagine associata, se queste non vengono esplicitamente impostate con i tag GA_Width e GA_Height. imp_State indica lo stato in cui l'immagine deve essere disegnata: le immagini boopsi sono capaci di disegnarsi in modo diverso in funzione del contesto in cui vengono utilizzate. Alcuni degli stati possibili sono: IDS_NORMAL - normale IDS_SELECTED - selezionata IDS_DISABLED - disabilitata IDS_INACTIVENORMAL - normale, nel bordo di una finestra inattiva IDS_INACTIVESELECTED - selezionata, nel bordo di una finestra inattiva IDS_INACTIVEDISABLED - disabilitata, nel bordo di una finestra inattiva IDS_SELECTEDDISABLED - selezionata e disabilitata Non sempre e' necessario gestire tutti i possibili stati: per esempio, l'immagine del "checkmark" di un gadget di tipo checkbox puo' anche non prevedere gli stati che riguardano l'inserimento nel bordo di una finestra. Una buona classe boopsi deve comunque essere in grado di adattarsi all'ambiente in cui viene utilizzata. Intuition e' in grado di generare automaticamente la versione disabilitata (IDS_DISABLED o IDS_SELECTEDDISABLED) di un'immagine boopsi, disegnandovi sopra il classico pattern "ghost" che viene utilizzato comunemente per i gadget non boopsi disabilitati e per i menu. Se l'immagine boopsi desidera gestire autonomamente questa condizione, deve ritornare TRUE quando viene richiesto il valore del tag IA_SupportsDisable. 16. IM_DRAWFRAME ================ I campi imp_Dimensions.Width e imp_Dimensions.Height del messaggio impDraw sono validi soltanto nel caso del metodo IM_DRAWFRAME. Questo metodo differisce da IM_DRAW perche' sono specificate anche le dimensioni desiderate per l'immagine. L'implementazione di IM_DRAWFRAME e' specifica della classe, ma tipicamente viene impiegato dai gadget per disegnare i propri bordi boopsi in modo che circondino correttamente l'area del gadget. Se una sottoclasse della imageclass non implementa questo metodo, il dispatcher della imageclass lo riceve e lo traduce in un messaggio IM_DRAW, rispedendolo nuovamente all'oggetto. Le immagini completamente scalabili dovrebbero supportare questo metodo e adattare nel migliore dei modi il proprio disegno alle dimensioni richieste. L'adattamento puo' avvenire ricalcolando, scalando o tagliando l'immagine, in base alla sua natura. 17. IM_ERASE e IM_ERASEFRAME ============================ Questi due metodi vengono chiamati dalla funzione di Intuition EraseImage() e dai gadget boopsi quando vengono spostati o ridimensionati. Se l'immagine non implementa questo metodo, il dispatcher della imageclass provvedera' a chiamare EraseRect() fornendo come dimensioni quelle memorizzate nella struttura Image dell'oggetto. La maggior parte delle immagini boopsi non necessitano di ridefinire questo metodo, che esiste soltanto per gestire correttamente immagini di forma complessa oppure semi-trasparenti. 17. DrawInfo ============ Un'immagine boopsi dovrebbe essere progettata per apparire correttamente in tutti i tipi di schermo, sia esso a due colori o a 24bit, con qualsiasi tipo di aspect ratio e di palette. Il campo imp_DrInfo del pacchetto impDraw contiene la struttura DrawInfo associata allo schermo in cui dovra' comparire l'immagine. Questa struttura contiene delle informazioni utili per il disegno, come ad esempio l'array delle penne di sistema. La struttura DrawInfo e' cosi' composta: struct DrawInfo { UWORD dri_Version; UWORD dri_NumPens; UWORD *dri_Pens; struct TextFont *dri_Font; UWORD dri_Depth; struct { UWORD X; UWORD Y; } dri_Resolution; ULONG dri_Flags; struct Image *dri_CheckMark; struct Image *dri_AmigaKey; ULONG dri_Reserved[5]; }; L'array delle penne per lo schermo specifica i colori da utilizzare per disegnare i vari elementi della GUI. Intuition V39 specifica le seguenti penne, che per lo schermo Workbench corrispondono alle selezioni operate dall'utente tramite l'editor di preferenze Palette: BACKGROUNDPEN sfondo TEXTPEN testo FILLPEN riempimento per le finestre attive ed i gadget selezionati FILLTEXTPEN testo su sfondo riempito con FILLPEN SHINEPEN parte luminosa degli oggetti in rilievo SHADOWPEN parte in ombra degli oggetti in rilievo HIGHLIGHTTEXTPEN testo evidenziato BARDETAILPEN testo/disegni nella barra dei menu BARBLOCKPEN sfondo della barra dei menu BARTRIMPEN contorno della barra dei menu DETAILPEN obsoleto BLOCKPEN obsoleto Gli altri campi della struttura DrawInfo indicano quale font utilizzare per il testo, la profondita' dello schermo, la sua risoluzione nominale e le immagini (boopsi) di default per i simboli che compaiono nei menu. Le immagini boopsi devono riferirsi alle informazioni contenute nella struttura DrawInfo per quanto possibile e prevedere dei valori di default nel caso che la struttura non sia disponibile (cioe' quando imp_DrawInfo contiene NULL). Questa situazione puo' verificarsi quando l'immagine viene disegnata usando la funzione DrawImage() di Intuition, oppure quando chi usa l'oggetto ne invoca direttamente il metodo IM_DRAW senza passare una struttura DrawInfo. Per le immagini boopsi, la funzione di Intuition DrawImageState() permette di specificare sia lo stato dell'immagine, sia la struttura DrawInfo da passare. I bottoni boopsi passano sempre alle proprie immagini la struttura DrawInfo che ottengono a loro volta dalla struttura GadgetInfo associata al pacchetto del metodo GM_RENDER. Il pacchetto impDraw contiene alcuni campi di tipo WORD, che sono stati opportunamente raggruppati in strutture la cui dimensione totale e' quella di un LONG. Un tipico errore in cui e' possibile incorrere durante la costruzione di un messaggio boopsi come questo e' passare i campi imp_Offset.X e imp_Offset.Y oppure imp_Dimensions.Width e imp_Dimensions.Height come due LONG separate, in questo modo: DoMethod (obj, IM_DRAW, rastport, x, y, IDS_NORMAL, drawinfo); Per ottenere un messaggio boopsi corretto si devono raggruppare le due WORD in questo modo: DoMethod (obj, IM_DRAW, rastport, (((WORD)x) << 16 | ((WORD)y)), IDS_NORMAL, drawinfo); 17. Immagini boopsi multiple ============================ Seguendo l'esempio della sysiclass, la classe delle immagini di sistema, e' possibile scrivere una classe boopsi che contenga piu' simboli diversi (glyph), selezionabili al momento della creazione con un attributo come SYSIA_Which. L'immagine deve ricordare quale simbolo e' stato selezionato e opzionalmente puo' renderizzarlo in un buffer privato per evitare di doverlo ricalcolare ogni volta che viene chiamato il metodo IM_DRAW. Tra gli esempi inclusi nel disco troverete una classe di questo tipo, la VectorGlyphIClass. 18. VectorGlyph =============== Nel diso allegato alla rivista troverete la classe esterna vectorglyph.image ed il relativo programma VectorGlyphDemo, che ne mostra le caratteristiche. Si tratta di una sottoclasse della imageclass che disegna alcuni simboli vettoriali in una bitmap privata che viene successivamente utilizzata per disegnare piu' rapidamente l'immagine. Per la verita' questa classe non costituisce un buon esempio di come scrivere immagini boopsi generiche, perche' per disegnarsi non utilizza le penne specificate nella struttura DrawInfo. Inoltre non implementa il metodo IM_DRAWFRAME e non e' in grado di adattarsi dinamicamente alle dimensioni richieste. Invece e' piuttosto interessante il metodo usato per ottenere aree riempite di forma irregolare, una caratteristica poco conosciuta della graphics.library. 19. I gadget custom =================== L'intero sistema boopsi gravita attorno agli elementi che compongono l'interfaccia utente di Intuition, in particolar modo i gadget. Leggendo tra le righe degli AutoDoc e degli include si intuisce che boopsi era stato sviluppato inizialmente come un sistema che permettesse al programmatore di creare dei gadget custom che reagissero all'input dell'utente chiamando una funzione call back fornita dal programmatore. Venne definito un nuovo tipo di gadget, GTYP_CUSTOMGADGET, al quale era associato una funzione hook simile a quella di editing dei gadget stringa. Questo hook doveva essere chiamato da Intuition per effettuare tutte le operazioni di diseno e di gestione dell'input che per gli altri tipi di gadget vengono svolte autonomamente da Intuition stesso. Dal momento che non era stato ancora progettato il concetto piu' generico di classe e oggetto, il gadget custom conteneva semplicemente un puntatore ad una struttura Hook, goffamente inserito nel campo MutualExclude della struttura Gadget originale. Al riguardo gli include spiegano che il campo MutualExclude non era comunque di alcuna utilita' pratica perche' la mutua esclusione tra gadget puo' essere realizzata in altri modi. Senza il sistema boopsi, la struttura Gadget non era estendibile in alcun modo e continuava ad essere allocata e inizializzata manualmente dal programmatore dell'applicazione anziche' dalla rootclass. Evidentemente, dopo essere riusciti ad incastrare alla meglio questa contorta estensione nel sottosistema dei gadget preesistente, gia' di per se' troppo complesso, i progettisti di West Chester vennero ispirati dall'influenza della moda OOP che stava esplodendo qua e la' proprio nel periodo in cui veniva sviluppata la V36. Dunque fu deciso di progettare qualcosa che fosse molto piu' versatile dei gadget custom e che soppiantasse del tutto l'intero sistema dei gadget tradizionali. Se ne avessero avuto il tempo, avrebbero senz'altro implementato delle classi boopsi anche per tutti gli altri elementi che compongono l'interfaccia utente di Intuition: finestre, requester, menu e schermi. 20. Sottoclassi della gadgetclass ================================= La gadgetclass e' la piu' complessa tra le classi che abbiamo esaminato fino ad ora. Non ha senso istanziare un oggetto dalla gadgetclass, perche' questa classe in se' stessa non fa niente di utile. Le sue sottoclassi rappresentano invece dei tipi di gadget specifici, come bottoni e gadget stringa. Scrivere una di queste classi puo' essere piuttosto impegnativo, perche' i metodi della gadgetclass sono molti e la maggior parte di questi viene chiamata direttamente da Intuition. Non sempre pero' e' necessario derivare una classe direttamente della gadgetclass. Un gadget checkbox, ad esempio, puo' essere realizzato piu' semplicemente come sottoclasse della buttongclass. Nel sorgente di PIPWin, incluso nel disco allegato al numero 91 di Amiga Magazine, venogno create due semplici classi. La prima, ScrollButtonClass, e' una sottoclasse della buttongclass che viene utilizzata per creare i quattro bottoni di scorrimento posti nell'angolo in basso a destra della finestra. Questa classe ridefinisce i metodi GM_GOACTIVE e GM_HANDLEINPUT per ottenere il comportamento corretto di un bottone di scroll. Quando viene premuto, il bottone notifica immediatamente il proprio target. Successivamente, se l'utente continua a mantenere premuto il bottone per un tempo superiore a tre tick di intuition (circa 300ms), il bottone inizia ad inviare una nuova notifica ad ogni intuitick (circa 100ms), finche' l'utente non rilascia il bottone. Questa classe e' molto semplice, perche' la gestione della maggior parte dei metodi viene demandata alla superclasse, inclusa la creazione dell'oggetto (OM_NEW) ed il ridisegno (GM_RENDER). La classe PictureInPicture e' invece un esempio piu' completo. Si tratta di una classe derivata direttamente dalla gadgetclass, che ridefinisce completamente i metodi GM_RENDER, GM_GOACTIVE, GM_HANDLEINPUT, GM_GOINACTIVE e GM_LAYOUT. Il processing dell'input gestisce i messaggi che riguardano mouse e tastiera. Gli oggetti di questa classe sono in grado di notificare il cambiamento di alcuni attributi, permettendo cosi' di collegare l'oggetto a due slider proporzionali. 21. La struttura GadgetInfo =========================== Come le immagini boopsi, anche i gadget possiedono una struttura di riferimento contenente tutti i dati sull'ambiente in cui l'oggetto e' inserito. La struttura GadgetInfo e' definita nell'header : struct GadgetInfo { struct Screen *gi_Screen; struct Window *gi_Window; struct Requester *gi_Requester; struct RastPort *gi_RastPort; struct Layer *gi_Layer; struct IBox gi_Domain; struct { UBYTE DetailPen; UBYTE BlockPen; } gi_Pens; struct DrawInfo *gi_DrInfo; ULONG gi_Reserved[6]; }; Questa struttura e' allocata e inizializzata da Intuition prima di chiamare uno dei metodi dei gadget che la prevedono. E' questo il motivo per cui nel caso di un gadget e' preferibile usare SetGadgetAttrs() al posto di SetAttrs(): senza i parametri addizionali di SetGadgetAttrs(), Intuition non e' in grado di passare al gadget una struttura GadgetInfo e il gadget non e' dunque in grado di disegnare all'interno della finestra per aggiornare visivamente il proprio stato. I primi tre campi della struttura GadgetInfo indicano lo schermo, la finestra ed il requester in cui il gadget e' inserito. gi_Requester assume il valore NULL nel caso il gadget che faccia parte di un requester, gi_Window assume il valore NULL quando il gadget fa parte della title bar di uno schermo. gi_Layer corrisponde al layer associato all'oggetto che contiene il gadget, ovvero il layer della title bar, della finestra o del requester, mentre gi_RastPort e' la RastPort che il gadget deve usare per disegnare nel layer. Questi due campi non devono essere usati direttamente, perche' Intuition fornisce un meccanismo che rende mutualmente esclusive le operazioni di rendering dei gadget boopsi con quelle effettuate dall'applicazione. gi_Domain fornisce le dimensioni dell'oggetto che contiene il gadget. Un commento nell'header specifica il modo in cui vengono inizializzate le coordinate per i possibili "contenitori" del gadget, ma non viene menzionato il caso in cui un gadget faccia parte di un gruppo di gadget realizzato con la groupgclass. DatailPen e BlockPen sono i colori da usare per disegnare testo e aree piene nel caso che il gadget sia inserito nel bordo di una finestra. La struttura DrawInfo contiene tutte le altre penne da usare per gli altri casi. 22. ObtainGIRPort() =================== La struttura RastPort da usare per le operazioni di disegno del gadget deve essere ricavata dal relativo parametro passato nel pacchetto del metodo GM_RENDER, oppure usando la funzione ObtainGIRPort(), che restituisce un puntatore alla RastPort corretta. Qualora il gadget dovesse effettuare operazioni con il layer che lo contiene, ne puo' ricavare l'indirizzo prelevandolo dal campo Layer contenuto nella struttura RastPort. La funzione ObtainGIRPort() e' diventata piuttosto famosa a causa di un sottile bug che poteva causare dei deadlock di Intuition in presenza di finestre contenenti dei gadget boopsi e di alcune applicazioni quali CycleToMenu e le versioni piu' antiche di MagicMenu. Su Aminet si trovano molti programmi che correggono il problema installando un patch in ObtainGIRPort(). Tuttavia, un documento pubblicato da Amiga Technologies sull'Amiga Developer CD sconsiglia l'uso di questi patch e suggerisce invece agli sviluppatori di adeguare i propri programmi al sistema di lock utilizzato da Intuition. ObtainGIRPort() non deve essere chiamata direttamente dall'applicazione, ma puo' essere chiamata all'interno di qualsiasi metodo di un gadget boopsi, in genere per ricavare la struttura RastPort da passare al metodo GM_RENDER: if (opUpdate->opu_GInfo != NULL) { struct RastPort *rp; if (rp = ObtainGIRPort (opUpdate->opu_GInfo)) { DoMethod (obj, GM_RENDER, opUpdate->opu_GInfo, rp, GREDRAW_REDRAW); ReleaseGIRPort (rp); } } Quando si chiama ObtainGIRPort(), Intuition tenta di ottenere un lock sul layer contenuto nella struttura GadgetInfo usando LockLayer(). In realta', se la struttura GadgetInfo e' inizializzata correttamente, ObtainGIRPort() non puo' mai fallire, almeno nella sua attuale implementazione. Il frammento di codice riportato sopra preleva la struttura GadgetInfo dal messaggio che e' stato ricevuto dal gadget (in questo caso si tratta di OM_UPDATE). E' necessario verificare preventivamente che la struttura GadgetInfo sia effettivamente disponibile, dal momento l'Autodoc di ObtainGIRPort() non specifica se il passaggio di un puntatore nullo e' accettabile, e in certi casi il metodo OM_UPDATE potrebbe essere chiamato da un altro oggetto che a sua volta non e' in grado di fornire questa struttura. Purtroppo esiste un grave problema che limita l'interoperabilita' nel sistema di notifica dei gadget boopsi. Il metodo OM_NOTIFY, invocato dagli oggetti che intendono trasmettere ad altri oggetti il cambiamento di alcuni dei propri attributi, richiede un puntatore ad una struttura GadgetInfo. I gadget in questo caso passano la struttura GadgetInfo che ricevono da Intuition tra i parametri del metodo. Questo puntatore viene propagato fino al destinatario della notifica, il quale utilizza dunque la stessa struttura dell'oggetto che ha originato il messaggio. Questo disguido non ha conseguenze negative fintanto che i due gadget coinvolti risiedono nello stesso contenitore. E' sufficiente che un gadget posto nel bordo di una finestra di tipo WFLG_GIMMEZEROZERO tenti di notificarne uno che si trova invece nel layer interno per dare luogo ad un errore nel refresh. In pratica, le dimensioni del contenitore ed il layer non saranno quelli corretti, con conseguenze drammatiche: il gadget disegna nella finestra sbagliata, usando dimensioni sbagliate. Intuition non ha modo di sapere in quale finestra e' inserito il gadget, perche' la struttura Gadget da sola non contiene questa informazione. Vorremmo poter suggerire un metodo per aggirare questo problema, ma purtroppo non ne esiste uno generale che possa funzionare correttamente in tutti i casi possibili. Difficilmente i progettisti delle prossime versioni di Intuition potranno correggere questo bug, se non stravolgendo l'attuale sistema di notifica. 23. GM_RENDER ============= Il metodo GM_RENDER chiede al gadget di disegnasi o di modificare il proprio aspetto in base allo stato corrente del gadget. Intuition invoca questo metodo nel contesto dell'input.device quando ritiene che il gadget debba essere ridisegnato. Il metodo puo' anche essere invocato da un'applicazione, usando RefreshGadgets() oppure RefreshGList(). In certi casi puo' perfino accadere che GM_RENDER venga invocato nel contesto di un'applicazione estranea, per esempio quando una finestra sovrapposta a quella contenente il gadget boopsi viene chiusa, spostata o ridimensionata usando le apposite funzioni di Intuition. Per questo motivo e' necessario limitare l'uso dello stack all'interno dei metodi dei gadget boopsi, evitando di definire un gran numero di variabili locali. In caso di necessita', si puo' scrivere uno stub in assembler che estenda lo stack usando StackSwap(). Il pacchetto di parametri di GM_RENDER e' definito come segue: struct gpRender { ULONG MethodID; struct GadgetInfo *gpr_GInfo; struct RastPort *gpr_RPort; LONG gpr_Redraw; }; Quando il metodo GM_RENDER viene invocato, ObtainGIRPort() e' gia' stata chiamata per ottenere la RastPort contenuta nel campo gpr_RPort. gpr_Redraw indica il modo in cui il gadget deve disegnarsi. Attualmente, Intuition definisce tre diversi tipi di rendering: GREDRAW_REDRAW - Ridisegno completo del gadget GREDRAW_UPDATE - Aggiornamento incrementale (scroll, etc) GREDRAW_TOGGLE - Commutazione tra stato selezionato e non selezionato GREDRAW_REDRAW e' l'unico tipo di rendering che viene invocato direttamente da Intuition. GREDRAW_UPDATE e GREDRAW_TOGGLE sono in genere chiamati dagli altri metodi del gadget, per esempio quando e' necessario spostare la barra di un gadget proporzionale o selezionare un bottone. Anche se e' possibile chiamare ObtainGIRPort() ed eseguire le operazioni di disegno direttamente all'interno del codice che gestisce metodi quali GM_HANDLEINPUT e GM_SET, per ragioni di pulizia e riutilizzabilita' del codice e' preferibile che il gadget invochi sempre il metodo GM_RENDER su se' stesso, impostando uno dei tipi di ridisegno descritti sopra, oppure definendone altri. In questo modo, chi volesse creare una sottoclasse ha comunque la possibilita' di intercettare il metodo GM_RENDER e di ridefinirlo. La RastPort utilizzata per il rendering potrebbe essere condivisa tra tutti i gadget boopsi presenti nella finestra, percio' il codice non deve fare assunzioni sullo stato iniziale dei vari parametri di disengo, ne' tantomeno sulla possibilita' che un cambiamento venga conservato tra una chiamata al metodo GM_RENDER e la successiva. In generale, e' tollerato che l'oggetto imposti nella RastPort una penna ed un modo di disegno diversi usando le funzioni SetAPen(), SetBPen() e SetDrawMode(), oppure che alteri la posizione corrente della penna di disegno usando Move(), Draw() e Text(). Non e' lecito invece alterare in modo permanente i parametri piu' esotici quali la maschera di scrittura dei bitplane (SetWriteMask()), il font (SetFont()), il pattern per il riempimento delle aree (AreaPtrn), quello per il disegno delle linee (LinePtrn) e cosi' via. Se l'oggetto ha la necessita' di cambiare uno di questi parametri, deve prima salvare il valore precedente per poterlo reimpostare al termine delle operazioni di rendering. Se non si presta attenzione a questo aspetto, puo' accadere che in certi casi gli effetti si manifestino sugli altri gadget conenuti nella finestra. Un gadget potrebbe per esempio tentare di disegnare una linea continua ed ottenerne invece una tratteggiata. In certi casi puo' essere conveniente creare una o piu' strutture RastPort private ed impostarvi un'unica volta i parametri di disegno utilizzati piu' frequentemente dalla classe. Un commento nell'header suggerisce la possibilita' di clonare la RastPort contenuta nella struttura GadgetInfo, ma non spiega in che modo si deve procedere. E' sufficiente allocare e inizializzare una struttura RastPort con InitRastPort() e quindi copiare dalla RastPort originale i puntatori al Layer e alla BitMap in cui devono avvenire le operazioni di disegno. Dal momento che i gadget boopsi, in linea di principio, possono essere spostati da una finestra ad un'altra in qualsiasi momento, il Layer e la BitMap potrebbero non rimanere gli stessi per tutta la vita dell'oggetto. Il momento piu' adatto per aggiornare una RastPort clonata e' all'interno del metodo GM_LAYOUT. E' superfluo ricordare che le operazioni di rendering di un gadget boopsi possono avvenire in qualsiasi tipo di bitmap e di layer, inclusi i piu' bizzarri. In particolare, l'autore di una sottoclasse della gadgetclass dovrebbe astenersi dall'usare tecniche di disegno che dipendono dal formato della bitmap (assumendo dunque che essa sia di tipo planare, chunky o true-color). Da quando i sistemi RTG e le schede grafiche per Amiga si sono moltiplicati in una grande varieta' di configurazioni diverse, queste regole valgono per tutte le applicazioni, in special modo per un gadget boopsi.