Alcune note sulla struttura GadgetInfo -------------------------------------- Apparentemente l'input handler di Intuition riutilizza sempre, quando ciò è possibile, la stessa struttura GadgetInfo quando invoca un metodo di un gadget custom. Del resto il singolo task dell'input.device può solo invocare un metodo dopo l'altro in sequenza e nella maggioranza dei casi non necessita di avere contemporaneamente più di una struttura GadgetInfo. Nella struttura GadgetInfo un gadget custom riceve nel campo gi_Layer il puntatore al layer associato al "contenitore logico" in cui si trova il gadget stesso. · Un gadget custom situato in una finestra normale, oppure nella zona interna di una finestra GIMMEZEROZERO riceve in gi_Layer il puntatore al layer di Window.RPort. Il "contenitore logico" è l'area dell'intera finestra, oppure l'area della sua zona interna. · Un gadget custom situato nella zona esterna di una finestra GIMMEZEROZERO (GZZGADGET) riceve in gi_Layer il puntatore al layer di Window.BorderRPort. Il "contenitore logico" è l'area dell'intera finestra. · Un gadget custom situato in un requester (REQGADGET) riceve in gi_Layer il puntatore al layer del requester (Requester.ReqLayer). Il "contenitore logico" è l'area del requester. · Un gadget custom situato nella titlebar di uno schermo (SCRGADGET) riceve in gi_Layer il puntatore al layer della titlebar (Screen.BarLayer). Il "contenitore logico" è l'area della titlebar. · Un gadget custom situato in un gruppo (cioè appartenente alla lista interna di un gadget "groupgclass") riceve in gi_Layer un valore che dipende dal "contenitore logico" del gruppo stesso, ricadendo così in uno dei quattro casi precedenti. Il campo gi_RastPort è uguale a gi_Screen->BarLayer->rp quando il gadget appartiene ad una finestra o ad un requester, e punta a gi_Screen.RastPort quando invece il gadget appartiene alla titlebar dello schermo. Ignoro le ragioni di questo fatto; in ogni caso questa RastPort per qualche motivo non deve venire utilizzata per il rendering (nel caso di un gadget SCRGADGET essa non ha nemmeno un layer). Chiamando ObtainGIRPort() si ottiene un clone della RastPort di gi_Layer, che punta allo stesso layer, il quale punta alla RastPort originale (quella della finestra interna, o quella del bordo per le finestre GIMMEZEROZERO, ecc.). Inoltre ObtainGIRPort() esegue un LockLayer() su gi_Layer. Apparentemente gi_Layer ha già tre lock quando Intuition invoca il metodo GM_RENDER (solo due nel caso di un gadget SCRGADGET) mentre non è bloccato nel caso di tutti gli altri metodi. Per il metodo GM_RENDER il valore di gpr_RPort è esattamente lo stesso che si otterrebbe chiamando ObtainGIRPort(), il che suggerisce che tale RastPort clonata sia unica e conservata da qualche parte. In effetti a quanto ho visto finora ObtainGIRPort() restituisce sempre lo stesso indirizzo, qualunque sia il contesto. I valori di gi_Screen, gi_Window e gi_Requester sono inizializzati in modo opportuno (oppure nulli se non applicabili, a parte gi_Screen). Tabella di esempio per un gadget in una finestra non GZZ: +-------------------------------------------------------------------------+ | gi_Window: W | | gi_Layer: RL, LWindow: W, LRastPort: R | | gi_RastPort: S, BitMap: bm, Layer: SL, LWindow: 0, LRastPort: S | | gi_Window->RPort: R, BitMap: bm, Layer: RL, LWindow: W, LRastPort: R | | gi_Window->BorderRP: 0, BitMap: --, Layer: --, LWindow: -, LRastPort: - | | gpr_RPort: C, BitMap: bm, Layer: RL, LWindow: W, LRastPort: R | | ObtainGIRPort(): C, BitMap: bm, Layer: RL, LWindow: W, LRastPort: R | +-------------------------------------------------------------------------+ Tabella di esempio per un gadget non GZZ in una finestra GZZ: +-------------------------------------------------------------------------+ | gi_Window: W | | gi_Layer: RL, LWindow: W, LRastPort: R | | gi_RastPort: S, BitMap: bm, Layer: SL, LWindow: 0, LRastPort: S | | gi_Window->RPort: R, BitMap: bm, Layer: RL, LWindow: W, LRastPort: R | | gi_Window->BorderRP: B, BitMap: bm, Layer: BL, LWindow: W, LRastPort: B | | gpr_RPort: C, BitMap: bm, Layer: RL, LWindow: W, LRastPort: R | | ObtainGIRPort(): C, BitMap: bm, Layer: RL, LWindow: W, LRastPort: R | +-------------------------------------------------------------------------+ Tabella di esempio per un gadget GZZ in una finestra GZZ: +-------------------------------------------------------------------------+ | gi_Window: W | | gi_Layer: BL, LWindow: W, LRastPort: B | | gi_RastPort: S, BitMap: bm, Layer: SL, LWindow: 0, LRastPort: S | | gi_Window->RPort: R, BitMap: bm, Layer: RL, LWindow: W, LRastPort: R | | gi_Window->BorderRP: B, BitMap: bm, Layer: BL, LWindow: W, LRastPort: B | | gpr_RPort: C, BitMap: bm, Layer: BL, LWindow: W, LRastPort: B | | ObtainGIRPort(): C, BitMap: bm, Layer: BL, LWindow: W, LRastPort: B | +-------------------------------------------------------------------------+ Il campo gi_Domain contiene larghezza e altezza del "contenitore logico" del gadget. Nel caso di un gadget SCRGADGET, l'altezza è stranamente quella dello schermo, mentre sarebbe più corretto se fosse quella della titlebar. Inoltre un gadget che appartenga ad un gruppo ha come "contenitore logico" quello che contiene il gruppo, e non il gruppo stesso (probabilmente in quanto il gruppo non ha un layer proprio). Gli offset contenuti in gi_Domain sono la distanza della posizione (espressa in coordinate di schermo) del layer associato al "contenitore logico" del gadget dalla posizione (sempre in coordinate di schermo) del suo "contenitore fisico primario" (cioè lo schermo per i gadget SCRGADGET e la finestra per tutti gli altri, anche se REQGADGET oppure appartenenti ad un gruppo). La funzione DoGadgetMethodA() crea una struttura GadgetInfo appropriata in base al tipo di gadget di cui viene invocato il metodo. Se è di tipo GZZGADGET, REQGADGET o SCRGADGET viene scelto il layer corretto, e anche gi_Domain viene inizializzato adeguatamente. Un problema è che "gadgetclass" e "icclass" nell'implementare il metodo OM_NOTIFY non chiamano DoGadgetMethodA() per invocare il metodo OM_UPDATE dell'oggetto ICA_TARGET, bensì gli passano direttamente il puntatore a GadgetInfo ricevuto, che fa riferimento al contesto dell'oggetto notificante e non, come sarebbe corretto, a quello dell'oggetto notificato! Non si devono annidare chiamate a ObtainGIRPort(), altrimenti la RastPort clonata (sempre la stessa) può venire modificata ad ogni chiamata. In realtà probabilmente se si rimane nello stesso contesto la RastPort clonata viene reinizializzata ogni volta con gli stessi valori, per cui non cambia niente. Il vero pericolo sta nell'invocare un metodo di un altro gadget che chiami ObtainGIRPort() mentre si è ancora all'interno del proprio blocco ObtainGIRPort(). In entrambi i casi comunque può verificarsi un errore 01000008 (Semaphore in illegal state). Del resto chiamare tanto ObtainGIRPort() quanto DoGadgetMethodA() all'interno di un blocco ObtainGIRPort() dovrebbe essere scorretto comunque (sono due funzioni di Intuition). Note varie ---------- GACT_IMMEDIATE viene sempre rispettato anche per i gadget custom o BOOPSI. Il valore di Code del messaggio IDCMP_GADGETDOWN è sempre zero e non può essere impostato dal dispatcher in alcun metodo (GM_HITTEST/GM_GOACTIVE). GACT_RELVERIFY è necessario affinché l'uso di GMR_VERIFY + gpi_Termination generi effettivamente un messaggio IDCMP_GADGETUP; in sua assenza esso non viene generato. Viceversa la sua presenza non garantisce l'invio di tali messaggi; ciò è deciso dal dispatcher nei metodi GM_GOACTIVE e GM_HANDLEINPUT. La documentazione del metodo IM_FRAMEBOX sul RKM è sbagliata! Viene invertito il ruolo di imp_ContentsBox e imp_FrameBox.